summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore100
-rw-r--r--bin/designer/templates.xml13
-rw-r--r--bin/designer/templates/Dialog_with_Buttons_Bottom.ui71
-rw-r--r--bin/designer/templates/Dialog_with_Buttons_Right.ui71
-rw-r--r--bin/designer/templates/Dialog_without_Buttons.ui18
-rw-r--r--bin/designer/templates/Main_Window.ui27
-rw-r--r--bin/designer/templates/Widget.ui24
-rw-r--r--bin/gdbmacros/GPL_EXCEPTION.TXT87
-rw-r--r--bin/gdbmacros/gdbmacros.cpp2446
-rw-r--r--bin/gdbmacros/gdbmacros.pro3
-rw-r--r--bin/license.txt615
-rwxr-xr-xbin/runInTerminal.command7
-rw-r--r--bin/schemes/MS_Visual_C++.kms495
-rw-r--r--bin/schemes/Xcode.kms585
-rw-r--r--bin/snippets/class_generic.snp26
-rw-r--r--bin/snippets/class_qobject.snp29
-rw-r--r--bin/snippets/class_qwidget.snp29
-rw-r--r--bin/snippets/comment.snp23
-rw-r--r--bin/snippets/for.snp48
-rw-r--r--bin/snippets/foreach.snp25
-rw-r--r--bin/snippets/if.snp25
-rw-r--r--bin/snippets/ifelse.snp27
-rw-r--r--bin/templates/qt4project/main.cpp10
-rw-r--r--bin/templates/qt4project/mywidget.cpp11
-rw-r--r--bin/templates/qt4project/mywidget.h15
-rw-r--r--bin/templates/qt4project/mywidget_form.cpp13
-rw-r--r--bin/templates/qt4project/mywidget_form.h23
-rw-r--r--bin/templates/qt4project/widget.ui23
-rw-r--r--doc/classic.css102
-rw-r--r--doc/doc.pri25
-rw-r--r--doc/doc.pro1
-rw-r--r--doc/doxygen/Doxyfile1306
-rw-r--r--doc/example/textfinder/input.txt2
-rw-r--r--doc/example/textfinder/main.cpp43
-rw-r--r--doc/example/textfinder/textfinder.cpp75
-rw-r--r--doc/example/textfinder/textfinder.h64
-rw-r--r--doc/example/textfinder/textfinder.pro12
-rw-r--r--doc/example/textfinder/textfinder.qrc5
-rw-r--r--doc/example/textfinder/textfinder.ui78
-rw-r--r--doc/qt-logo.pngbin0 -> 1471 bytes
-rw-r--r--doc/qtcreator-add-resource-wizard.pngbin0 -> 42694 bytes
-rw-r--r--doc/qtcreator-add-resource.pngbin0 -> 29745 bytes
-rw-r--r--doc/qtcreator-application-output.pngbin0 -> 34584 bytes
-rw-r--r--doc/qtcreator-breakdown.pngbin0 -> 124959 bytes
-rw-r--r--doc/qtcreator-buildenvironment.pngbin0 -> 98411 bytes
-rw-r--r--doc/qtcreator-buildsettings.pngbin0 -> 72994 bytes
-rw-r--r--doc/qtcreator-buildsettingstab.pngbin0 -> 73430 bytes
-rw-r--r--doc/qtcreator-buildsteps.pngbin0 -> 81336 bytes
-rw-r--r--doc/qtcreator-class-info.pngbin0 -> 35255 bytes
-rw-r--r--doc/qtcreator-compile-pane.pngbin0 -> 87656 bytes
-rw-r--r--doc/qtcreator-context-sensitive-help.pngbin0 -> 214415 bytes
-rw-r--r--doc/qtcreator-debug-mode.pngbin0 -> 1285 bytes
-rw-r--r--doc/qtcreator-debugging-buttons.pngbin0 -> 8007 bytes
-rw-r--r--doc/qtcreator-formedit.pngbin0 -> 216164 bytes
-rw-r--r--doc/qtcreator-intro-and-location.pngbin0 -> 32434 bytes
-rw-r--r--doc/qtcreator-navigate-customfilter.pngbin0 -> 53542 bytes
-rw-r--r--doc/qtcreator-navigate-popup.pngbin0 -> 88751 bytes
-rw-r--r--doc/qtcreator-new-project.pngbin0 -> 14065 bytes
-rw-r--r--doc/qtcreator-run.pngbin0 -> 1293 bytes
-rw-r--r--doc/qtcreator-search-pane.pngbin0 -> 52779 bytes
-rw-r--r--doc/qtcreator-select-modules.pngbin0 -> 45128 bytes
-rw-r--r--doc/qtcreator-setting-breakpoint1.pngbin0 -> 15311 bytes
-rw-r--r--doc/qtcreator-setting-breakpoint2.pngbin0 -> 15315 bytes
-rw-r--r--doc/qtcreator-task-list.pngbin0 -> 22442 bytes
-rw-r--r--doc/qtcreator-textfinder-screenshot.pngbin0 -> 44173 bytes
-rw-r--r--doc/qtcreator-textfinder-ui.pngbin0 -> 7595 bytes
-rw-r--r--doc/qtcreator-watcher.pngbin0 -> 29080 bytes
-rw-r--r--doc/qtcreator.pngbin0 -> 73608 bytes
-rw-r--r--doc/qtcreator.qchbin0 -> 1649664 bytes
-rw-r--r--doc/qtcreator.qdoc1153
-rw-r--r--doc/qtcreator.qdocconf205
-rw-r--r--doc/runframework.diabin0 -> 5362 bytes
-rw-r--r--doc/trolltech-logo.pngbin0 -> 1512 bytes
-rw-r--r--doc/workbench.qdoc98
-rw-r--r--doc/workbench.qtdocconf147
-rw-r--r--examples/scripting/demo.js346
-rwxr-xr-xfix_makefile_header_dependencies.sh52
-rw-r--r--installer/TODO.txt12
-rw-r--r--installer/installer.cpp433
-rw-r--r--installer/installer.pro29
-rw-r--r--installer/installer.qrc7
-rw-r--r--installer/qinstaller.cpp1872
-rw-r--r--installer/qinstaller.h357
-rw-r--r--installer/qinstallergui.cpp742
-rw-r--r--installer/qinstallergui.h256
-rw-r--r--installer/resources/license.txt84
-rw-r--r--installer/resources/logo.pngbin0 -> 1592 bytes
-rw-r--r--installer/resources/watermark.pngbin0 -> 14462 bytes
-rw-r--r--qtcreator.pro4
-rwxr-xr-xreplaceVersion.sh101
-rw-r--r--shared/cpaster/cgi.cpp428
-rw-r--r--shared/cpaster/cgi.h58
-rw-r--r--shared/cpaster/cpaster.pri14
-rw-r--r--shared/cpaster/fetcher.cpp78
-rw-r--r--shared/cpaster/fetcher.h66
-rw-r--r--shared/cpaster/poster.cpp75
-rw-r--r--shared/cpaster/poster.h64
-rw-r--r--shared/cpaster/splitter.cpp95
-rw-r--r--shared/cpaster/splitter.h53
-rw-r--r--shared/cpaster/view.cpp185
-rw-r--r--shared/cpaster/view.h66
-rw-r--r--shared/cpaster/view.ui208
-rw-r--r--shared/cplusplus/AST.cpp2458
-rw-r--r--shared/cplusplus/AST.h1722
-rw-r--r--shared/cplusplus/ASTVisitor.cpp105
-rw-r--r--shared/cplusplus/ASTVisitor.h195
-rw-r--r--shared/cplusplus/ASTfwd.h173
-rw-r--r--shared/cplusplus/Array.cpp53
-rw-r--r--shared/cplusplus/Array.h135
-rw-r--r--shared/cplusplus/CPlusPlusForwardDeclarations.h140
-rw-r--r--shared/cplusplus/CheckDeclaration.cpp366
-rw-r--r--shared/cplusplus/CheckDeclaration.h106
-rw-r--r--shared/cplusplus/CheckDeclarator.cpp258
-rw-r--r--shared/cplusplus/CheckDeclarator.h110
-rw-r--r--shared/cplusplus/CheckExpression.cpp362
-rw-r--r--shared/cplusplus/CheckExpression.h126
-rw-r--r--shared/cplusplus/CheckName.cpp348
-rw-r--r--shared/cplusplus/CheckName.h92
-rw-r--r--shared/cplusplus/CheckSpecifier.cpp392
-rw-r--r--shared/cplusplus/CheckSpecifier.h95
-rw-r--r--shared/cplusplus/CheckStatement.cpp239
-rw-r--r--shared/cplusplus/CheckStatement.h102
-rw-r--r--shared/cplusplus/Control.cpp630
-rw-r--r--shared/cplusplus/Control.h175
-rw-r--r--shared/cplusplus/CoreTypes.cpp237
-rw-r--r--shared/cplusplus/CoreTypes.h217
-rw-r--r--shared/cplusplus/DiagnosticClient.cpp63
-rw-r--r--shared/cplusplus/DiagnosticClient.h86
-rw-r--r--shared/cplusplus/FullySpecifiedType.cpp204
-rw-r--r--shared/cplusplus/FullySpecifiedType.h158
-rw-r--r--shared/cplusplus/Keywords.cpp1211
-rw-r--r--shared/cplusplus/Keywords.kwgen86
-rw-r--r--shared/cplusplus/Lexer.cpp624
-rw-r--r--shared/cplusplus/Lexer.h153
-rw-r--r--shared/cplusplus/LiteralTable.cpp53
-rw-r--r--shared/cplusplus/LiteralTable.h181
-rw-r--r--shared/cplusplus/Literals.cpp138
-rw-r--r--shared/cplusplus/Literals.h122
-rw-r--r--shared/cplusplus/MemoryPool.cpp115
-rw-r--r--shared/cplusplus/MemoryPool.h105
-rw-r--r--shared/cplusplus/Name.cpp133
-rw-r--r--shared/cplusplus/Name.h103
-rw-r--r--shared/cplusplus/NameVisitor.cpp67
-rw-r--r--shared/cplusplus/NameVisitor.h86
-rw-r--r--shared/cplusplus/Names.cpp262
-rw-r--r--shared/cplusplus/Names.h241
-rw-r--r--shared/cplusplus/Parser.cpp3238
-rw-r--r--shared/cplusplus/Parser.h261
-rw-r--r--shared/cplusplus/Scope.cpp308
-rw-r--r--shared/cplusplus/Scope.h198
-rw-r--r--shared/cplusplus/Semantic.cpp198
-rw-r--r--shared/cplusplus/Semantic.h109
-rw-r--r--shared/cplusplus/SemanticCheck.cpp72
-rw-r--r--shared/cplusplus/SemanticCheck.h78
-rw-r--r--shared/cplusplus/Symbol.cpp421
-rw-r--r--shared/cplusplus/Symbol.h266
-rw-r--r--shared/cplusplus/SymbolVisitor.cpp66
-rw-r--r--shared/cplusplus/SymbolVisitor.h90
-rw-r--r--shared/cplusplus/Symbols.cpp484
-rw-r--r--shared/cplusplus/Symbols.h338
-rw-r--r--shared/cplusplus/Token.cpp131
-rw-r--r--shared/cplusplus/Token.h290
-rw-r--r--shared/cplusplus/TranslationUnit.cpp434
-rw-r--r--shared/cplusplus/TranslationUnit.h189
-rw-r--r--shared/cplusplus/Type.cpp198
-rw-r--r--shared/cplusplus/Type.h124
-rw-r--r--shared/cplusplus/TypeVisitor.cpp67
-rw-r--r--shared/cplusplus/TypeVisitor.h92
-rw-r--r--shared/cplusplus/cplusplus.pri73
-rw-r--r--shared/designerintegrationv2/README.txt10
-rw-r--r--shared/designerintegrationv2/designerintegration.pri11
-rw-r--r--shared/designerintegrationv2/formresizer.cpp194
-rw-r--r--shared/designerintegrationv2/formresizer.h103
-rw-r--r--shared/designerintegrationv2/sizehandlerect.cpp192
-rw-r--r--shared/designerintegrationv2/sizehandlerect.h86
-rw-r--r--shared/designerintegrationv2/widgethost.cpp108
-rw-r--r--shared/designerintegrationv2/widgethost.h83
-rw-r--r--shared/designerintegrationv2/widgethostconstants.h44
-rw-r--r--shared/help/bookmarkdialog.ui146
-rw-r--r--shared/help/bookmarkmanager.cpp866
-rw-r--r--shared/help/bookmarkmanager.h197
-rw-r--r--shared/help/contentwindow.cpp165
-rw-r--r--shared/help/contentwindow.h78
-rw-r--r--shared/help/filternamedialog.cpp65
-rw-r--r--shared/help/filternamedialog.h59
-rw-r--r--shared/help/filternamedialog.ui67
-rw-r--r--shared/help/help.pri25
-rw-r--r--shared/help/helpviewer.cpp483
-rw-r--r--shared/help/helpviewer.h154
-rw-r--r--shared/help/indexwindow.cpp209
-rw-r--r--shared/help/indexwindow.h78
-rw-r--r--shared/help/topicchooser.cpp78
-rw-r--r--shared/help/topicchooser.h63
-rw-r--r--shared/help/topicchooser.ui116
-rw-r--r--shared/indenter/README9
-rw-r--r--shared/indenter/constants.cpp65
-rw-r--r--shared/indenter/indenter.h144
-rw-r--r--shared/indenter/indenter.pri5
-rw-r--r--shared/indenter/indenter_impl.h1123
-rw-r--r--shared/indenter/test/main.cpp181
-rw-r--r--shared/indenter/test/test.pro10
-rw-r--r--shared/namespace_global.h52
-rw-r--r--shared/proparser/abstractproitemvisitor.h61
-rw-r--r--shared/proparser/images/append.pngbin0 -> 514 bytes
-rw-r--r--shared/proparser/images/other.pngbin0 -> 1499 bytes
-rw-r--r--shared/proparser/images/profile.pngbin0 -> 452 bytes
-rw-r--r--shared/proparser/images/remove.pngbin0 -> 497 bytes
-rw-r--r--shared/proparser/images/scope.pngbin0 -> 350 bytes
-rw-r--r--shared/proparser/images/set.pngbin0 -> 473 bytes
-rw-r--r--shared/proparser/images/value.pngbin0 -> 599 bytes
-rw-r--r--shared/proparser/procommandmanager.cpp166
-rw-r--r--shared/proparser/procommandmanager.h107
-rw-r--r--shared/proparser/proeditor.cpp387
-rw-r--r--shared/proparser/proeditor.h128
-rw-r--r--shared/proparser/proeditor.ui143
-rw-r--r--shared/proparser/proeditormodel.cpp983
-rw-r--r--shared/proparser/proeditormodel.h153
-rw-r--r--shared/proparser/profileevaluator.cpp1833
-rw-r--r--shared/proparser/profileevaluator.h94
-rw-r--r--shared/proparser/proiteminfo.cpp239
-rw-r--r--shared/proparser/proiteminfo.h132
-rw-r--r--shared/proparser/proiteminfo.xml110
-rw-r--r--shared/proparser/proitems.cpp314
-rw-r--r--shared/proparser/proitems.h226
-rw-r--r--shared/proparser/proparser.pri35
-rw-r--r--shared/proparser/proparser.qrc12
-rw-r--r--shared/proparser/proparserutils.h275
-rw-r--r--shared/proparser/prowriter.cpp207
-rw-r--r--shared/proparser/prowriter.h75
-rw-r--r--shared/proparser/proxml.cpp207
-rw-r--r--shared/proparser/proxml.h56
-rw-r--r--shared/proparser/valueeditor.cpp494
-rw-r--r--shared/proparser/valueeditor.h119
-rw-r--r--shared/proparser/valueeditor.ui384
-rw-r--r--shared/qrceditor/qrceditor.cpp401
-rw-r--r--shared/qrceditor/qrceditor.h109
-rw-r--r--shared/qrceditor/qrceditor.pri28
-rw-r--r--shared/qrceditor/qrceditor.ui131
-rw-r--r--shared/qrceditor/resourcefile.cpp982
-rw-r--r--shared/qrceditor/resourcefile_p.h266
-rw-r--r--shared/qrceditor/resourceview.cpp661
-rw-r--r--shared/qrceditor/resourceview.h183
-rw-r--r--shared/qrceditor/test/main.cpp42
-rw-r--r--shared/qrceditor/test/mainwindow.cpp102
-rw-r--r--shared/qrceditor/test/mainwindow.h56
-rw-r--r--shared/qrceditor/test/test.pro11
-rw-r--r--shared/qrceditor/undocommands.cpp206
-rw-r--r--shared/qrceditor/undocommands_p.h162
-rw-r--r--shared/qscripthighlighter/README3
-rw-r--r--shared/qscripthighlighter/qscripthighlighter.cpp480
-rw-r--r--shared/qscripthighlighter/qscripthighlighter.h71
-rw-r--r--shared/qscripthighlighter/qscripthighlighter.pri4
-rw-r--r--shared/qscripthighlighter/test/main.cpp48
-rw-r--r--shared/qscripthighlighter/test/test.pro10
-rw-r--r--shared/qtextended_integration.h98
-rw-r--r--shared/qtlockedfile/README.txt10
-rw-r--r--shared/qtlockedfile/namespace.patch70
-rw-r--r--shared/qtlockedfile/qtlockedfile.cpp161
-rw-r--r--shared/qtlockedfile/qtlockedfile.h80
-rw-r--r--shared/qtlockedfile/qtlockedfile.pri13
-rw-r--r--shared/qtlockedfile/qtlockedfile_unix.cpp110
-rw-r--r--shared/qtlockedfile/qtlockedfile_win.cpp205
-rw-r--r--shared/qtsingleapplication/README.txt10
-rw-r--r--shared/qtsingleapplication/namespace.patch133
-rw-r--r--shared/qtsingleapplication/qtlocalpeer.cpp179
-rw-r--r--shared/qtsingleapplication/qtlocalpeer.h69
-rw-r--r--shared/qtsingleapplication/qtsingleapplication.cpp143
-rw-r--r--shared/qtsingleapplication/qtsingleapplication.h85
-rw-r--r--shared/qtsingleapplication/qtsingleapplication.pri14
-rw-r--r--shared/qtsingleapplication/qtsinglecoreapplication.cpp72
-rw-r--r--shared/qtsingleapplication/qtsinglecoreapplication.h63
-rw-r--r--shared/qtsingleapplication/qtsinglecoreapplication.pri14
-rw-r--r--shared/scriptwrapper/README58
-rw-r--r--shared/scriptwrapper/interface_wrap_helpers.h92
-rw-r--r--shared/scriptwrapper/scriptwrapper.pri3
-rw-r--r--shared/scriptwrapper/wrap_helpers.h334
-rw-r--r--src/app/Info.plist189
-rw-r--r--src/app/app.pro82
-rw-r--r--src/app/main.cpp285
-rw-r--r--src/app/qtcreator.icnsbin0 -> 35774 bytes
-rw-r--r--src/app/qtcreator.icobin0 -> 300318 bytes
-rw-r--r--src/app/qtcreator.rc1
-rw-r--r--src/libs/aggregation/aggregate.cpp265
-rw-r--r--src/libs/aggregation/aggregate.h134
-rw-r--r--src/libs/aggregation/aggregation.pri1
-rw-r--r--src/libs/aggregation/aggregation.pro12
-rw-r--r--src/libs/aggregation/aggregation_global.h44
-rw-r--r--src/libs/aggregation/examples/examples.pro3
-rw-r--r--src/libs/aggregation/examples/text/main.cpp110
-rw-r--r--src/libs/aggregation/examples/text/main.h62
-rw-r--r--src/libs/aggregation/examples/text/main.ui128
-rw-r--r--src/libs/aggregation/examples/text/myinterfaces.h87
-rw-r--r--src/libs/aggregation/examples/text/text.pro14
-rw-r--r--src/libs/aggregation/test/test.pro12
-rw-r--r--src/libs/aggregation/test/tst_aggregate.cpp198
-rw-r--r--src/libs/cplusplus/CppDocument.cpp242
-rw-r--r--src/libs/cplusplus/CppDocument.h187
-rw-r--r--src/libs/cplusplus/ExpressionUnderCursor.cpp242
-rw-r--r--src/libs/cplusplus/ExpressionUnderCursor.h68
-rw-r--r--src/libs/cplusplus/Icons.cpp122
-rw-r--r--src/libs/cplusplus/Icons.h75
-rw-r--r--src/libs/cplusplus/LookupContext.cpp402
-rw-r--r--src/libs/cplusplus/LookupContext.h151
-rw-r--r--src/libs/cplusplus/NameOfExpression.cpp438
-rw-r--r--src/libs/cplusplus/NameOfExpression.h99
-rw-r--r--src/libs/cplusplus/NamePrettyPrinter.cpp255
-rw-r--r--src/libs/cplusplus/NamePrettyPrinter.h69
-rw-r--r--src/libs/cplusplus/Overview.cpp91
-rw-r--r--src/libs/cplusplus/Overview.h80
-rw-r--r--src/libs/cplusplus/OverviewModel.cpp183
-rw-r--r--src/libs/cplusplus/OverviewModel.h84
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp793
-rw-r--r--src/libs/cplusplus/ResolveExpression.h131
-rw-r--r--src/libs/cplusplus/SimpleLexer.cpp117
-rw-r--r--src/libs/cplusplus/SimpleLexer.h106
-rw-r--r--src/libs/cplusplus/TokenUnderCursor.cpp75
-rw-r--r--src/libs/cplusplus/TokenUnderCursor.h63
-rw-r--r--src/libs/cplusplus/TypeOfExpression.cpp114
-rw-r--r--src/libs/cplusplus/TypeOfExpression.h98
-rw-r--r--src/libs/cplusplus/TypePrettyPrinter.cpp309
-rw-r--r--src/libs/cplusplus/TypePrettyPrinter.h101
-rw-r--r--src/libs/cplusplus/cplusplus.pri3
-rw-r--r--src/libs/cplusplus/cplusplus.pro40
-rw-r--r--src/libs/cplusplus/cplusplus.qrc20
-rw-r--r--src/libs/cplusplus/images/class.pngbin0 -> 573 bytes
-rw-r--r--src/libs/cplusplus/images/enum.pngbin0 -> 359 bytes
-rw-r--r--src/libs/cplusplus/images/enumerator.pngbin0 -> 478 bytes
-rw-r--r--src/libs/cplusplus/images/func.pngbin0 -> 583 bytes
-rw-r--r--src/libs/cplusplus/images/func_priv.pngbin0 -> 656 bytes
-rw-r--r--src/libs/cplusplus/images/func_prot.pngbin0 -> 647 bytes
-rw-r--r--src/libs/cplusplus/images/keyword.pngbin0 -> 341 bytes
-rw-r--r--src/libs/cplusplus/images/macro.pngbin0 -> 505 bytes
-rw-r--r--src/libs/cplusplus/images/namespace.pngbin0 -> 377 bytes
-rw-r--r--src/libs/cplusplus/images/signal.pngbin0 -> 558 bytes
-rw-r--r--src/libs/cplusplus/images/slot.pngbin0 -> 646 bytes
-rw-r--r--src/libs/cplusplus/images/slot_priv.pngbin0 -> 709 bytes
-rw-r--r--src/libs/cplusplus/images/slot_prot.pngbin0 -> 681 bytes
-rw-r--r--src/libs/cplusplus/images/var.pngbin0 -> 530 bytes
-rw-r--r--src/libs/cplusplus/images/var_priv.pngbin0 -> 632 bytes
-rw-r--r--src/libs/cplusplus/images/var_prot.pngbin0 -> 619 bytes
-rw-r--r--src/libs/extensionsystem/ExtensionSystemInterfaces6
-rw-r--r--src/libs/extensionsystem/extensionsystem.pri3
-rw-r--r--src/libs/extensionsystem/extensionsystem.pro32
-rw-r--r--src/libs/extensionsystem/extensionsystem_dependencies.pri1
-rw-r--r--src/libs/extensionsystem/extensionsystem_global.h44
-rw-r--r--src/libs/extensionsystem/images/error.pngbin0 -> 111 bytes
-rw-r--r--src/libs/extensionsystem/images/ok.pngbin0 -> 103 bytes
-rw-r--r--src/libs/extensionsystem/iplugin.cpp325
-rw-r--r--src/libs/extensionsystem/iplugin.h76
-rw-r--r--src/libs/extensionsystem/iplugin_p.h58
-rw-r--r--src/libs/extensionsystem/optionsparser.cpp192
-rw-r--r--src/libs/extensionsystem/optionsparser.h87
-rw-r--r--src/libs/extensionsystem/plugindetailsview.cpp89
-rw-r--r--src/libs/extensionsystem/plugindetailsview.h67
-rw-r--r--src/libs/extensionsystem/plugindetailsview.ui258
-rw-r--r--src/libs/extensionsystem/pluginerrorview.cpp114
-rw-r--r--src/libs/extensionsystem/pluginerrorview.h66
-rw-r--r--src/libs/extensionsystem/pluginerrorview.ui77
-rw-r--r--src/libs/extensionsystem/pluginmanager.cpp749
-rw-r--r--src/libs/extensionsystem/pluginmanager.h138
-rw-r--r--src/libs/extensionsystem/pluginmanager_p.h96
-rw-r--r--src/libs/extensionsystem/pluginspec.cpp871
-rw-r--r--src/libs/extensionsystem/pluginspec.h120
-rw-r--r--src/libs/extensionsystem/pluginspec_p.h106
-rw-r--r--src/libs/extensionsystem/pluginview.cpp159
-rw-r--r--src/libs/extensionsystem/pluginview.h82
-rw-r--r--src/libs/extensionsystem/pluginview.qrc6
-rw-r--r--src/libs/extensionsystem/pluginview.ui74
-rw-r--r--src/libs/extensionsystem/pluginview_p.h51
-rw-r--r--src/libs/extensionsystem/test/auto/auto.pro3
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp53
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h55
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro8
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp53
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h55
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro8
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp53
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h55
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro8
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro3
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp86
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h58
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro15
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp68
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h58
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro12
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp77
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h58
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro15
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/test.pro14
-rwxr-xr-xsrc/libs/extensionsystem/test/auto/pluginmanager/test.sh5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp267
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro4
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/test.pro14
-rwxr-xr-xsrc/libs/extensionsystem/test/auto/pluginspec/test.sh5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp56
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h62
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro13
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h44
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp278
-rw-r--r--src/libs/extensionsystem/test/extensionsystem_test.pri12
-rw-r--r--src/libs/extensionsystem/test/manual/manual.pro3
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp142
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugindialog.h61
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml18
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp86
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h59
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro15
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml4
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp69
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h59
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro12
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml6
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp77
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h59
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro15
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml5
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro3
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/pluginview.pro3
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/test.pro9
-rwxr-xr-xsrc/libs/extensionsystem/test/manual/pluginview/test.sh5
-rw-r--r--src/libs/extensionsystem/test/test.pro4
-rw-r--r--src/libs/libs.pro9
-rw-r--r--src/libs/qtconcurrent/QtConcurrentTools2
-rw-r--r--src/libs/qtconcurrent/multitask.h198
-rw-r--r--src/libs/qtconcurrent/qtconcurrent.pri1
-rw-r--r--src/libs/qtconcurrent/qtconcurrent.pro10
-rw-r--r--src/libs/qtconcurrent/qtconcurrent_global.h44
-rw-r--r--src/libs/qtconcurrent/runextensions.h397
-rw-r--r--src/libs/utils/basevalidatinglineedit.cpp157
-rw-r--r--src/libs/utils/basevalidatinglineedit.h100
-rw-r--r--src/libs/utils/classnamevalidatinglineedit.cpp137
-rw-r--r--src/libs/utils/classnamevalidatinglineedit.h79
-rw-r--r--src/libs/utils/codegeneration.cpp89
-rw-r--r--src/libs/utils/codegeneration.h70
-rw-r--r--src/libs/utils/fancylineedit.cpp317
-rw-r--r--src/libs/utils/fancylineedit.h115
-rw-r--r--src/libs/utils/filenamevalidatinglineedit.cpp97
-rw-r--r--src/libs/utils/filenamevalidatinglineedit.h56
-rw-r--r--src/libs/utils/filesearch.cpp216
-rw-r--r--src/libs/utils/filesearch.h69
-rw-r--r--src/libs/utils/filewizarddialog.cpp73
-rw-r--r--src/libs/utils/filewizarddialog.h69
-rw-r--r--src/libs/utils/filewizardpage.cpp129
-rw-r--r--src/libs/utils/filewizardpage.h86
-rw-r--r--src/libs/utils/filewizardpage.ui83
-rw-r--r--src/libs/utils/linecolumnlabel.cpp69
-rw-r--r--src/libs/utils/linecolumnlabel.h68
-rw-r--r--src/libs/utils/listutils.h54
-rw-r--r--src/libs/utils/newclasswidget.cpp462
-rw-r--r--src/libs/utils/newclasswidget.h150
-rw-r--r--src/libs/utils/newclasswidget.ui150
-rw-r--r--src/libs/utils/pathchooser.cpp185
-rw-r--r--src/libs/utils/pathchooser.h90
-rw-r--r--src/libs/utils/projectintropage.cpp215
-rw-r--r--src/libs/utils/projectintropage.h107
-rw-r--r--src/libs/utils/projectintropage.ui122
-rw-r--r--src/libs/utils/projectnamevalidatinglineedit.cpp66
-rw-r--r--src/libs/utils/projectnamevalidatinglineedit.h56
-rw-r--r--src/libs/utils/qtcolorbutton.cpp290
-rw-r--r--src/libs/utils/qtcolorbutton.h84
-rw-r--r--src/libs/utils/reloadpromptutils.cpp62
-rw-r--r--src/libs/utils/reloadpromptutils.h54
-rw-r--r--src/libs/utils/settingsutils.cpp53
-rw-r--r--src/libs/utils/settingsutils.h48
-rw-r--r--src/libs/utils/submiteditorwidget.cpp305
-rw-r--r--src/libs/utils/submiteditorwidget.h122
-rw-r--r--src/libs/utils/submiteditorwidget.ui59
-rw-r--r--src/libs/utils/synchronousprocess.cpp356
-rw-r--r--src/libs/utils/synchronousprocess.h139
-rw-r--r--src/libs/utils/utils.pri1
-rw-r--r--src/libs/utils/utils.pro53
-rw-r--r--src/libs/utils/utils_global.h57
-rw-r--r--src/plugins/bineditor/BinEditor.mimetypes.xml39
-rw-r--r--src/plugins/bineditor/BinEditor.pluginspec11
-rw-r--r--src/plugins/bineditor/bineditor.cpp871
-rw-r--r--src/plugins/bineditor/bineditor.h181
-rw-r--r--src/plugins/bineditor/bineditor.pro13
-rw-r--r--src/plugins/bineditor/bineditor.qrc5
-rw-r--r--src/plugins/bineditor/bineditor_dependencies.pri4
-rw-r--r--src/plugins/bineditor/bineditorconstants.h43
-rw-r--r--src/plugins/bineditor/bineditorplugin.cpp503
-rw-r--r--src/plugins/bineditor/bineditorplugin.h124
-rw-r--r--src/plugins/bookmarks/Bookmarks.pluginspec12
-rw-r--r--src/plugins/bookmarks/bookmark.cpp96
-rw-r--r--src/plugins/bookmarks/bookmark.h85
-rw-r--r--src/plugins/bookmarks/bookmarkmanager.cpp742
-rw-r--r--src/plugins/bookmarks/bookmarkmanager.h193
-rw-r--r--src/plugins/bookmarks/bookmarks.pro18
-rw-r--r--src/plugins/bookmarks/bookmarks.qrc5
-rw-r--r--src/plugins/bookmarks/bookmarks_global.h56
-rw-r--r--src/plugins/bookmarks/bookmarksplugin.cpp185
-rw-r--r--src/plugins/bookmarks/bookmarksplugin.h86
-rw-r--r--src/plugins/bookmarks/images/bookmark.pngbin0 -> 913 bytes
-rw-r--r--src/plugins/cmakeprojectmanager/CMakeProject.mimetypes.xml8
-rw-r--r--src/plugins/cmakeprojectmanager/CMakeProjectManager.pluginspec14
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.cpp441
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.h158
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.qrc5
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectconstants.h45
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp72
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.h60
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro14
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager_dependencies.pri4
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp89
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectnodes.h66
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp65
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectplugin.h63
-rw-r--r--src/plugins/coreplugin/Core.pluginspec7
-rw-r--r--src/plugins/coreplugin/actionmanager/actioncontainer.cpp696
-rw-r--r--src/plugins/coreplugin/actionmanager/actioncontainer.h157
-rw-r--r--src/plugins/coreplugin/actionmanager/actionmanager.cpp560
-rw-r--r--src/plugins/coreplugin/actionmanager/actionmanager.h129
-rw-r--r--src/plugins/coreplugin/actionmanager/actionmanagerinterface.h76
-rw-r--r--src/plugins/coreplugin/actionmanager/command.cpp579
-rw-r--r--src/plugins/coreplugin/actionmanager/command.h178
-rw-r--r--src/plugins/coreplugin/actionmanager/commandsfile.cpp126
-rw-r--r--src/plugins/coreplugin/actionmanager/commandsfile.h63
-rw-r--r--src/plugins/coreplugin/actionmanager/iactioncontainer.h81
-rw-r--r--src/plugins/coreplugin/actionmanager/icommand.h93
-rw-r--r--src/plugins/coreplugin/basefilewizard.cpp671
-rw-r--r--src/plugins/coreplugin/basefilewizard.h244
-rw-r--r--src/plugins/coreplugin/basemode.cpp122
-rw-r--r--src/plugins/coreplugin/basemode.h86
-rw-r--r--src/plugins/coreplugin/baseview.cpp189
-rw-r--r--src/plugins/coreplugin/baseview.h71
-rw-r--r--src/plugins/coreplugin/core.qrc71
-rw-r--r--src/plugins/coreplugin/core_global.h57
-rw-r--r--src/plugins/coreplugin/coreconstants.h224
-rw-r--r--src/plugins/coreplugin/coreimpl.cpp211
-rw-r--r--src/plugins/coreplugin/coreimpl.h105
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp111
-rw-r--r--src/plugins/coreplugin/coreplugin.h70
-rw-r--r--src/plugins/coreplugin/coreplugin.pri3
-rw-r--r--src/plugins/coreplugin/coreplugin.pro169
-rw-r--r--src/plugins/coreplugin/coreplugin_dependencies.pri2
-rw-r--r--src/plugins/coreplugin/dialogs/ioptionspage.h61
-rw-r--r--src/plugins/coreplugin/dialogs/iwizard.h70
-rw-r--r--src/plugins/coreplugin/dialogs/newdialog.cpp150
-rw-r--r--src/plugins/coreplugin/dialogs/newdialog.h82
-rw-r--r--src/plugins/coreplugin/dialogs/newdialog.ui86
-rw-r--r--src/plugins/coreplugin/dialogs/openwithdialog.cpp87
-rw-r--r--src/plugins/coreplugin/dialogs/openwithdialog.h69
-rw-r--r--src/plugins/coreplugin/dialogs/openwithdialog.ui46
-rw-r--r--src/plugins/coreplugin/dialogs/saveitemsdialog.cpp207
-rw-r--r--src/plugins/coreplugin/dialogs/saveitemsdialog.h102
-rw-r--r--src/plugins/coreplugin/dialogs/saveitemsdialog.ui66
-rw-r--r--src/plugins/coreplugin/dialogs/settingsdialog.cpp138
-rw-r--r--src/plugins/coreplugin/dialogs/settingsdialog.h67
-rw-r--r--src/plugins/coreplugin/dialogs/settingsdialog.ui121
-rw-r--r--src/plugins/coreplugin/dialogs/shortcutsettings.cpp379
-rw-r--r--src/plugins/coreplugin/dialogs/shortcutsettings.h110
-rw-r--r--src/plugins/coreplugin/dialogs/shortcutsettings.ui170
-rw-r--r--src/plugins/coreplugin/editmode.cpp138
-rw-r--r--src/plugins/coreplugin/editmode.h80
-rw-r--r--src/plugins/coreplugin/editormanager/editorgroup.cpp337
-rw-r--r--src/plugins/coreplugin/editormanager/editorgroup.h165
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager.cpp1576
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager.h229
-rw-r--r--src/plugins/coreplugin/editormanager/editorsplitter.cpp664
-rw-r--r--src/plugins/coreplugin/editormanager/editorsplitter.h136
-rw-r--r--src/plugins/coreplugin/editormanager/ieditor.h102
-rw-r--r--src/plugins/coreplugin/editormanager/ieditorfactory.h59
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorsview.cpp310
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorsview.h91
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorsview.ui39
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorswindow.cpp351
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorswindow.h99
-rw-r--r--src/plugins/coreplugin/editormanager/stackededitorgroup.cpp375
-rw-r--r--src/plugins/coreplugin/editormanager/stackededitorgroup.h111
-rw-r--r--src/plugins/coreplugin/fancyactionbar.cpp137
-rw-r--r--src/plugins/coreplugin/fancyactionbar.h76
-rw-r--r--src/plugins/coreplugin/fancyactionbar.qrc10
-rw-r--r--src/plugins/coreplugin/fancytabwidget.cpp373
-rw-r--r--src/plugins/coreplugin/fancytabwidget.h118
-rw-r--r--src/plugins/coreplugin/fileiconprovider.cpp138
-rw-r--r--src/plugins/coreplugin/fileiconprovider.h71
-rw-r--r--src/plugins/coreplugin/filemanager.cpp592
-rw-r--r--src/plugins/coreplugin/filemanager.h140
-rw-r--r--src/plugins/coreplugin/findplaceholder.cpp69
-rw-r--r--src/plugins/coreplugin/findplaceholder.h60
-rw-r--r--src/plugins/coreplugin/flowlayout.cpp155
-rw-r--r--src/plugins/coreplugin/flowlayout.h83
-rw-r--r--src/plugins/coreplugin/generalsettings.cpp114
-rw-r--r--src/plugins/coreplugin/generalsettings.h71
-rw-r--r--src/plugins/coreplugin/generalsettings.ui149
-rw-r--r--src/plugins/coreplugin/html/images/bg_site_header_dark_grey.pngbin0 -> 156 bytes
-rw-r--r--src/plugins/coreplugin/html/images/body_bg_circles_bottom_right.pngbin0 -> 23017 bytes
-rw-r--r--src/plugins/coreplugin/html/images/body_bg_gradient.pngbin0 -> 238 bytes
-rw-r--r--src/plugins/coreplugin/html/images/btn_getting_started.pngbin0 -> 1949 bytes
-rw-r--r--src/plugins/coreplugin/html/images/btn_getting_started_hover.pngbin0 -> 2036 bytes
-rw-r--r--src/plugins/coreplugin/html/images/btn_restore_session.pngbin0 -> 1717 bytes
-rw-r--r--src/plugins/coreplugin/html/images/btn_restore_session_hover.pngbin0 -> 1798 bytes
-rw-r--r--src/plugins/coreplugin/html/images/list_bullet_arrow.pngbin0 -> 280 bytes
-rw-r--r--src/plugins/coreplugin/html/images/mode_Project.pngbin0 -> 3838 bytes
-rw-r--r--src/plugins/coreplugin/html/images/nokia_logo.pngbin0 -> 2321 bytes
-rw-r--r--src/plugins/coreplugin/html/images/product_logo.pngbin0 -> 20877 bytes
-rw-r--r--src/plugins/coreplugin/html/images/qt_logo.pngbin0 -> 4439 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_bottom_left.pngbin0 -> 181 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_bottom_mid.pngbin0 -> 126 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_bottom_right.pngbin0 -> 175 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_mid_left.pngbin0 -> 178 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_mid_mid.pngbin0 -> 158 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_mid_right.pngbin0 -> 174 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_top_left.pngbin0 -> 194 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_top_mid.pngbin0 -> 133 bytes
-rw-r--r--src/plugins/coreplugin/html/images/rc_top_right.pngbin0 -> 199 bytes
-rw-r--r--src/plugins/coreplugin/html/qt.css351
-rw-r--r--src/plugins/coreplugin/html/recent_projects.html41
-rw-r--r--src/plugins/coreplugin/html/recent_sessions.html43
-rw-r--r--src/plugins/coreplugin/html/welcome.html76
-rw-r--r--src/plugins/coreplugin/icontext.h59
-rw-r--r--src/plugins/coreplugin/icore.h134
-rw-r--r--src/plugins/coreplugin/icorelistener.h77
-rw-r--r--src/plugins/coreplugin/ifile.h72
-rw-r--r--src/plugins/coreplugin/ifilefactory.h63
-rw-r--r--src/plugins/coreplugin/ifilewizardextension.h72
-rw-r--r--src/plugins/coreplugin/images/clean_pane_small.pngbin0 -> 713 bytes
-rw-r--r--src/plugins/coreplugin/images/clear.pngbin0 -> 298 bytes
-rw-r--r--src/plugins/coreplugin/images/closebutton.pngbin0 -> 288 bytes
-rw-r--r--src/plugins/coreplugin/images/dir.pngbin0 -> 862 bytes
-rw-r--r--src/plugins/coreplugin/images/editcopy.pngbin0 -> 1715 bytes
-rw-r--r--src/plugins/coreplugin/images/editcut.pngbin0 -> 1949 bytes
-rw-r--r--src/plugins/coreplugin/images/editpaste.pngbin0 -> 2087 bytes
-rw-r--r--src/plugins/coreplugin/images/empty14.pngbin0 -> 172 bytes
-rw-r--r--src/plugins/coreplugin/images/fancytoolbutton.svg539
-rw-r--r--src/plugins/coreplugin/images/filenew.pngbin0 -> 977 bytes
-rw-r--r--src/plugins/coreplugin/images/fileopen.pngbin0 -> 2402 bytes
-rw-r--r--src/plugins/coreplugin/images/filesave.pngbin0 -> 1980 bytes
-rw-r--r--src/plugins/coreplugin/images/find.pngbin0 -> 737 bytes
-rw-r--r--src/plugins/coreplugin/images/findnext.pngbin0 -> 828 bytes
-rw-r--r--src/plugins/coreplugin/images/inputfield.pngbin0 -> 422 bytes
-rw-r--r--src/plugins/coreplugin/images/inputfield_disabled.pngbin0 -> 453 bytes
-rw-r--r--src/plugins/coreplugin/images/linkicon.pngbin0 -> 230 bytes
-rw-r--r--src/plugins/coreplugin/images/locked.pngbin0 -> 351 bytes
-rw-r--r--src/plugins/coreplugin/images/magnifier.pngbin0 -> 439 bytes
-rw-r--r--src/plugins/coreplugin/images/minus.pngbin0 -> 258 bytes
-rw-r--r--src/plugins/coreplugin/images/mode_Debug.pngbin0 -> 1926 bytes
-rw-r--r--src/plugins/coreplugin/images/mode_Edit.pngbin0 -> 724 bytes
-rw-r--r--src/plugins/coreplugin/images/mode_Output.pngbin0 -> 871 bytes
-rw-r--r--src/plugins/coreplugin/images/mode_Project.pngbin0 -> 1193 bytes
-rw-r--r--src/plugins/coreplugin/images/mode_Reference.pngbin0 -> 2188 bytes
-rw-r--r--src/plugins/coreplugin/images/next.pngbin0 -> 908 bytes
-rw-r--r--src/plugins/coreplugin/images/panel_button.pngbin0 -> 442 bytes
-rw-r--r--src/plugins/coreplugin/images/panel_button_checked.pngbin0 -> 407 bytes
-rw-r--r--src/plugins/coreplugin/images/panel_button_checked_hover.pngbin0 -> 407 bytes
-rw-r--r--src/plugins/coreplugin/images/panel_button_hover.pngbin0 -> 439 bytes
-rw-r--r--src/plugins/coreplugin/images/panel_button_pressed.pngbin0 -> 440 bytes
-rw-r--r--src/plugins/coreplugin/images/plus.pngbin0 -> 541 bytes
-rw-r--r--src/plugins/coreplugin/images/prev.pngbin0 -> 911 bytes
-rw-r--r--src/plugins/coreplugin/images/pushbutton.pngbin0 -> 488 bytes
-rw-r--r--src/plugins/coreplugin/images/pushbutton_hover.pngbin0 -> 370 bytes
-rw-r--r--src/plugins/coreplugin/images/pushbutton_pressed.pngbin0 -> 389 bytes
-rw-r--r--src/plugins/coreplugin/images/qtcreator_logo_128.pngbin0 -> 8690 bytes
-rw-r--r--src/plugins/coreplugin/images/qtcreator_logo_16.pngbin0 -> 725 bytes
-rw-r--r--src/plugins/coreplugin/images/qtcreator_logo_24.pngbin0 -> 1139 bytes
-rw-r--r--src/plugins/coreplugin/images/qtcreator_logo_32.pngbin0 -> 1623 bytes
-rw-r--r--src/plugins/coreplugin/images/qtcreator_logo_48.pngbin0 -> 2773 bytes
-rw-r--r--src/plugins/coreplugin/images/qtcreator_logo_64.pngbin0 -> 3386 bytes
-rw-r--r--src/plugins/coreplugin/images/qtwatermark.pngbin0 -> 6423 bytes
-rw-r--r--src/plugins/coreplugin/images/redo.pngbin0 -> 1787 bytes
-rw-r--r--src/plugins/coreplugin/images/replace.pngbin0 -> 891 bytes
-rw-r--r--src/plugins/coreplugin/images/reset.pngbin0 -> 184 bytes
-rw-r--r--src/plugins/coreplugin/images/sidebaricon.pngbin0 -> 294 bytes
-rw-r--r--src/plugins/coreplugin/images/splitbutton_horizontal.pngbin0 -> 147 bytes
-rw-r--r--src/plugins/coreplugin/images/statusbar.pngbin0 -> 303 bytes
-rw-r--r--src/plugins/coreplugin/images/undo.pngbin0 -> 1768 bytes
-rw-r--r--src/plugins/coreplugin/images/unknownfile.pngbin0 -> 345 bytes
-rw-r--r--src/plugins/coreplugin/images/unlocked.pngbin0 -> 280 bytes
-rw-r--r--src/plugins/coreplugin/imode.h62
-rw-r--r--src/plugins/coreplugin/inavigationwidgetfactory.cpp51
-rw-r--r--src/plugins/coreplugin/inavigationwidgetfactory.h70
-rw-r--r--src/plugins/coreplugin/ioutputpane.h103
-rw-r--r--src/plugins/coreplugin/iversioncontrol.h96
-rw-r--r--src/plugins/coreplugin/iview.h60
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp1102
-rw-r--r--src/plugins/coreplugin/mainwindow.h227
-rw-r--r--src/plugins/coreplugin/manhattanstyle.cpp942
-rw-r--r--src/plugins/coreplugin/manhattanstyle.h106
-rw-r--r--src/plugins/coreplugin/messagemanager.cpp88
-rw-r--r--src/plugins/coreplugin/messagemanager.h74
-rw-r--r--src/plugins/coreplugin/messageoutputwindow.cpp94
-rw-r--r--src/plugins/coreplugin/messageoutputwindow.h73
-rw-r--r--src/plugins/coreplugin/mimedatabase.cpp1178
-rw-r--r--src/plugins/coreplugin/mimedatabase.h226
-rw-r--r--src/plugins/coreplugin/minisplitter.cpp98
-rw-r--r--src/plugins/coreplugin/minisplitter.h59
-rw-r--r--src/plugins/coreplugin/modemanager.cpp236
-rw-r--r--src/plugins/coreplugin/modemanager.h106
-rw-r--r--src/plugins/coreplugin/navigationwidget.cpp494
-rw-r--r--src/plugins/coreplugin/navigationwidget.h172
-rw-r--r--src/plugins/coreplugin/outputpane.cpp531
-rw-r--r--src/plugins/coreplugin/outputpane.h142
-rw-r--r--src/plugins/coreplugin/plugindialog.cpp141
-rw-r--r--src/plugins/coreplugin/plugindialog.h75
-rw-r--r--src/plugins/coreplugin/progressmanager/futureprogress.cpp167
-rw-r--r--src/plugins/coreplugin/progressmanager/futureprogress.h94
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanager.cpp110
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanager.h74
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanagerinterface.h62
-rw-r--r--src/plugins/coreplugin/progressmanager/progresspie.cpp166
-rw-r--r--src/plugins/coreplugin/progressmanager/progresspie.h69
-rw-r--r--src/plugins/coreplugin/progressmanager/progressview.cpp142
-rw-r--r--src/plugins/coreplugin/progressmanager/progressview.h81
-rw-r--r--src/plugins/coreplugin/rightpane.cpp242
-rw-r--r--src/plugins/coreplugin/rightpane.h108
-rw-r--r--src/plugins/coreplugin/scriptmanager/metatypedeclarations.h70
-rw-r--r--src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp381
-rw-r--r--src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h262
-rw-r--r--src/plugins/coreplugin/scriptmanager/scriptmanager.cpp313
-rw-r--r--src/plugins/coreplugin/scriptmanager/scriptmanager.h71
-rw-r--r--src/plugins/coreplugin/scriptmanager/scriptmanagerinterface.h75
-rw-r--r--src/plugins/coreplugin/sidebar.cpp371
-rw-r--r--src/plugins/coreplugin/sidebar.h184
-rw-r--r--src/plugins/coreplugin/styleanimator.cpp156
-rw-r--r--src/plugins/coreplugin/styleanimator.h104
-rw-r--r--src/plugins/coreplugin/stylehelper.cpp229
-rw-r--r--src/plugins/coreplugin/stylehelper.h78
-rw-r--r--src/plugins/coreplugin/tabpositionindicator.cpp57
-rw-r--r--src/plugins/coreplugin/tabpositionindicator.h57
-rw-r--r--src/plugins/coreplugin/uniqueidmanager.cpp69
-rw-r--r--src/plugins/coreplugin/uniqueidmanager.h62
-rw-r--r--src/plugins/coreplugin/variablemanager.cpp78
-rw-r--r--src/plugins/coreplugin/variablemanager.h67
-rw-r--r--src/plugins/coreplugin/vcsmanager.cpp113
-rw-r--r--src/plugins/coreplugin/vcsmanager.h75
-rw-r--r--src/plugins/coreplugin/versiondialog.cpp135
-rw-r--r--src/plugins/coreplugin/versiondialog.h53
-rw-r--r--src/plugins/coreplugin/viewmanager.cpp132
-rw-r--r--src/plugins/coreplugin/viewmanager.h86
-rw-r--r--src/plugins/coreplugin/viewmanagerinterface.h64
-rw-r--r--src/plugins/coreplugin/welcomemode.cpp271
-rw-r--r--src/plugins/coreplugin/welcomemode.h98
-rw-r--r--src/plugins/cpaster/CodePaster.pluginspec12
-rw-r--r--src/plugins/cpaster/cpaster.pro15
-rw-r--r--src/plugins/cpaster/cpaster_dependencies.pri3
-rw-r--r--src/plugins/cpaster/cpasterplugin.cpp304
-rw-r--r--src/plugins/cpaster/cpasterplugin.h119
-rw-r--r--src/plugins/cpaster/pasteselect.ui138
-rw-r--r--src/plugins/cpaster/settingspage.cpp117
-rw-r--r--src/plugins/cpaster/settingspage.h81
-rw-r--r--src/plugins/cpaster/settingspage.ui94
-rw-r--r--src/plugins/cppeditor/CppEditor.mimetypes.xml137
-rw-r--r--src/plugins/cppeditor/CppEditor.pluginspec12
-rw-r--r--src/plugins/cppeditor/CppEditor.qwp23
-rw-r--r--src/plugins/cppeditor/CppEditor.tpa16
-rw-r--r--src/plugins/cppeditor/cppclasswizard.cpp232
-rw-r--r--src/plugins/cppeditor/cppclasswizard.h128
-rw-r--r--src/plugins/cppeditor/cppeditor.cpp815
-rw-r--r--src/plugins/cppeditor/cppeditor.h145
-rw-r--r--src/plugins/cppeditor/cppeditor.pri3
-rw-r--r--src/plugins/cppeditor/cppeditor.pro22
-rw-r--r--src/plugins/cppeditor/cppeditor.qrc7
-rw-r--r--src/plugins/cppeditor/cppeditor_dependencies.pri6
-rw-r--r--src/plugins/cppeditor/cppeditor_global.h44
-rw-r--r--src/plugins/cppeditor/cppeditoractionhandler.cpp54
-rw-r--r--src/plugins/cppeditor/cppeditoractionhandler.h61
-rw-r--r--src/plugins/cppeditor/cppeditorconstants.h59
-rw-r--r--src/plugins/cppeditor/cppeditorenums.h59
-rw-r--r--src/plugins/cppeditor/cppfilewizard.cpp103
-rw-r--r--src/plugins/cppeditor/cppfilewizard.h69
-rw-r--r--src/plugins/cppeditor/cpphighlighter.cpp303
-rw-r--r--src/plugins/cppeditor/cpphighlighter.h73
-rw-r--r--src/plugins/cppeditor/cppplugin.cpp258
-rw-r--r--src/plugins/cppeditor/cppplugin.h113
-rw-r--r--src/plugins/cppeditor/images/qt_cpp.pngbin0 -> 561 bytes
-rw-r--r--src/plugins/cppeditor/images/qt_h.pngbin0 -> 448 bytes
-rw-r--r--src/plugins/cpptools/CppTools.pluginspec12
-rw-r--r--src/plugins/cpptools/cppcodecompletion.cpp1040
-rw-r--r--src/plugins/cpptools/cppcodecompletion.h145
-rw-r--r--src/plugins/cpptools/cpphoverhandler.cpp243
-rw-r--r--src/plugins/cpptools/cpphoverhandler.h75
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp740
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h135
-rw-r--r--src/plugins/cpptools/cppmodelmanagerinterface.h79
-rw-r--r--src/plugins/cpptools/cppquickopenfilter.cpp280
-rw-r--r--src/plugins/cpptools/cppquickopenfilter.h118
-rw-r--r--src/plugins/cpptools/cpptools.cpp256
-rw-r--r--src/plugins/cpptools/cpptools.h86
-rw-r--r--src/plugins/cpptools/cpptools.pri3
-rw-r--r--src/plugins/cpptools/cpptools.pro40
-rw-r--r--src/plugins/cpptools/cpptools.qrc5
-rw-r--r--src/plugins/cpptools/cpptools_dependencies.pri3
-rw-r--r--src/plugins/cpptools/cpptools_global.h42
-rw-r--r--src/plugins/cpptools/cpptoolsconstants.h49
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.cpp97
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.h87
-rw-r--r--src/plugins/cpptools/images/f1.svg175
-rw-r--r--src/plugins/cpptools/rpp/pp-cctype.h76
-rw-r--r--src/plugins/cpptools/rpp/pp-client.h69
-rw-r--r--src/plugins/cpptools/rpp/pp-engine.cpp1085
-rw-r--r--src/plugins/cpptools/rpp/pp-engine.h230
-rw-r--r--src/plugins/cpptools/rpp/pp-environment.cpp231
-rw-r--r--src/plugins/cpptools/rpp/pp-environment.h109
-rw-r--r--src/plugins/cpptools/rpp/pp-fwd.h62
-rw-r--r--src/plugins/cpptools/rpp/pp-internal.h102
-rw-r--r--src/plugins/cpptools/rpp/pp-macro-expander.cpp362
-rw-r--r--src/plugins/cpptools/rpp/pp-macro-expander.h103
-rw-r--r--src/plugins/cpptools/rpp/pp-macro.h95
-rw-r--r--src/plugins/cpptools/rpp/pp-scanner.h380
-rw-r--r--src/plugins/cpptools/rpp/pp-symbol.h52
-rw-r--r--src/plugins/cpptools/rpp/pp.h76
-rw-r--r--src/plugins/cpptools/rpp/rpp.pri20
-rw-r--r--src/plugins/debugger/Debugger.pluginspec13
-rw-r--r--src/plugins/debugger/assert.h45
-rw-r--r--src/plugins/debugger/attachexternaldialog.cpp344
-rw-r--r--src/plugins/debugger/attachexternaldialog.h65
-rw-r--r--src/plugins/debugger/attachexternaldialog.ui64
-rw-r--r--src/plugins/debugger/attachremotedialog.cpp344
-rw-r--r--src/plugins/debugger/attachremotedialog.h65
-rw-r--r--src/plugins/debugger/attachremotedialog.ui64
-rw-r--r--src/plugins/debugger/breakbyfunction.ui58
-rw-r--r--src/plugins/debugger/breakcondition.ui95
-rw-r--r--src/plugins/debugger/breakhandler.cpp559
-rw-r--r--src/plugins/debugger/breakhandler.h174
-rw-r--r--src/plugins/debugger/breakwindow.cpp164
-rw-r--r--src/plugins/debugger/breakwindow.h76
-rw-r--r--src/plugins/debugger/debugger.pro92
-rw-r--r--src/plugins/debugger/debugger.qrc24
-rw-r--r--src/plugins/debugger/debuggerconstants.h65
-rw-r--r--src/plugins/debugger/debuggermanager.cpp1298
-rw-r--r--src/plugins/debugger/debuggermanager.h451
-rw-r--r--src/plugins/debugger/debuggeroutputwindow.cpp318
-rw-r--r--src/plugins/debugger/debuggeroutputwindow.h87
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp610
-rw-r--r--src/plugins/debugger/debuggerplugin.h111
-rw-r--r--src/plugins/debugger/debuggerrunner.cpp161
-rw-r--r--src/plugins/debugger/debuggerrunner.h96
-rw-r--r--src/plugins/debugger/disassemblerhandler.cpp187
-rw-r--r--src/plugins/debugger/disassemblerhandler.h78
-rw-r--r--src/plugins/debugger/disassemblerwindow.cpp140
-rw-r--r--src/plugins/debugger/disassemblerwindow.h71
-rw-r--r--src/plugins/debugger/gdbengine.cpp4035
-rw-r--r--src/plugins/debugger/gdbengine.h351
-rw-r--r--src/plugins/debugger/gdbmi.cpp473
-rw-r--r--src/plugins/debugger/gdbmi.h183
-rw-r--r--src/plugins/debugger/gdboptionpage.cpp128
-rw-r--r--src/plugins/debugger/gdboptionpage.h106
-rw-r--r--src/plugins/debugger/gdboptionpage.ui111
-rw-r--r--src/plugins/debugger/gdbtypemacros.cpp214
-rw-r--r--src/plugins/debugger/gdbtypemacros.ui186
-rw-r--r--src/plugins/debugger/idebuggerengine.h88
-rw-r--r--src/plugins/debugger/images/breakpoint.svg154
-rw-r--r--src/plugins/debugger/images/breakpoint_pending.svg534
-rw-r--r--src/plugins/debugger/images/debugger_breakpoints.pngbin0 -> 650 bytes
-rw-r--r--src/plugins/debugger/images/debugger_continue_small.pngbin0 -> 739 bytes
-rw-r--r--src/plugins/debugger/images/debugger_interrupt_small.pngbin0 -> 417 bytes
-rw-r--r--src/plugins/debugger/images/debugger_start.pngbin0 -> 1235 bytes
-rw-r--r--src/plugins/debugger/images/debugger_start_small.pngbin0 -> 739 bytes
-rw-r--r--src/plugins/debugger/images/debugger_stepinto_small.pngbin0 -> 420 bytes
-rw-r--r--src/plugins/debugger/images/debugger_steponeproc_small.pngbin0 -> 297 bytes
-rw-r--r--src/plugins/debugger/images/debugger_stepout_small.pngbin0 -> 382 bytes
-rw-r--r--src/plugins/debugger/images/debugger_stepover_small.pngbin0 -> 617 bytes
-rw-r--r--src/plugins/debugger/images/debugger_stepoverproc_small.pngbin0 -> 517 bytes
-rw-r--r--src/plugins/debugger/images/debugger_stop_small.pngbin0 -> 314 bytes
-rw-r--r--src/plugins/debugger/images/delete.pngbin0 -> 578 bytes
-rw-r--r--src/plugins/debugger/images/done.pngbin0 -> 235 bytes
-rw-r--r--src/plugins/debugger/images/empty.svg67
-rw-r--r--src/plugins/debugger/images/error.pngbin0 -> 326 bytes
-rw-r--r--src/plugins/debugger/images/location.svg121
-rw-r--r--src/plugins/debugger/images/newitem.pngbin0 -> 239 bytes
-rw-r--r--src/plugins/debugger/images/running.pngbin0 -> 532 bytes
-rw-r--r--src/plugins/debugger/imports.h49
-rw-r--r--src/plugins/debugger/mode.cpp233
-rw-r--r--src/plugins/debugger/mode.h84
-rw-r--r--src/plugins/debugger/mode.ui76
-rw-r--r--src/plugins/debugger/moduleshandler.cpp172
-rw-r--r--src/plugins/debugger/moduleshandler.h104
-rw-r--r--src/plugins/debugger/moduleswindow.cpp136
-rw-r--r--src/plugins/debugger/moduleswindow.h71
-rw-r--r--src/plugins/debugger/procinterrupt.cpp182
-rw-r--r--src/plugins/debugger/procinterrupt.h47
-rw-r--r--src/plugins/debugger/registerhandler.cpp128
-rw-r--r--src/plugins/debugger/registerhandler.h81
-rw-r--r--src/plugins/debugger/registerwindow.cpp181
-rw-r--r--src/plugins/debugger/registerwindow.h71
-rw-r--r--src/plugins/debugger/scriptengine.cpp677
-rw-r--r--src/plugins/debugger/scriptengine.h134
-rw-r--r--src/plugins/debugger/stackhandler.cpp271
-rw-r--r--src/plugins/debugger/stackhandler.h136
-rw-r--r--src/plugins/debugger/stackwindow.cpp117
-rw-r--r--src/plugins/debugger/stackwindow.h75
-rw-r--r--src/plugins/debugger/startexternaldialog.cpp124
-rw-r--r--src/plugins/debugger/startexternaldialog.h63
-rw-r--r--src/plugins/debugger/startexternaldialog.ui93
-rw-r--r--src/plugins/debugger/threadswindow.cpp112
-rw-r--r--src/plugins/debugger/threadswindow.h68
-rw-r--r--src/plugins/debugger/watchhandler.cpp1137
-rw-r--r--src/plugins/debugger/watchhandler.h219
-rw-r--r--src/plugins/debugger/watchwindow.cpp253
-rw-r--r--src/plugins/debugger/watchwindow.h95
-rw-r--r--src/plugins/designer/Designer.mimetypes.xml37
-rw-r--r--src/plugins/designer/Designer.pluginspec12
-rw-r--r--src/plugins/designer/README.txt37
-rw-r--r--src/plugins/designer/cpp/cpp.pri15
-rw-r--r--src/plugins/designer/cpp/formclasswizard.cpp117
-rw-r--r--src/plugins/designer/cpp/formclasswizard.h77
-rw-r--r--src/plugins/designer/cpp/formclasswizarddialog.cpp114
-rw-r--r--src/plugins/designer/cpp/formclasswizarddialog.h83
-rw-r--r--src/plugins/designer/cpp/formclasswizardpage.cpp209
-rw-r--r--src/plugins/designer/cpp/formclasswizardpage.h87
-rw-r--r--src/plugins/designer/cpp/formclasswizardpage.ui167
-rw-r--r--src/plugins/designer/cpp/formclasswizardparameters.cpp174
-rw-r--r--src/plugins/designer/cpp/formclasswizardparameters.h67
-rw-r--r--src/plugins/designer/designer.pro57
-rw-r--r--src/plugins/designer/designer.qrc6
-rw-r--r--src/plugins/designer/designer_dependencies.pri3
-rw-r--r--src/plugins/designer/designerconstants.h65
-rw-r--r--src/plugins/designer/editorwidget.cpp270
-rw-r--r--src/plugins/designer/editorwidget.h118
-rw-r--r--src/plugins/designer/formeditorfactory.cpp78
-rw-r--r--src/plugins/designer/formeditorfactory.h73
-rw-r--r--src/plugins/designer/formeditorplugin.cpp146
-rw-r--r--src/plugins/designer/formeditorplugin.h74
-rw-r--r--src/plugins/designer/formeditorw.cpp720
-rw-r--r--src/plugins/designer/formeditorw.h175
-rw-r--r--src/plugins/designer/formtemplatewizardpage.cpp330
-rw-r--r--src/plugins/designer/formtemplatewizardpage.h79
-rw-r--r--src/plugins/designer/formwindoweditor.cpp355
-rw-r--r--src/plugins/designer/formwindoweditor.h128
-rw-r--r--src/plugins/designer/formwindowfile.cpp210
-rw-r--r--src/plugins/designer/formwindowfile.h105
-rw-r--r--src/plugins/designer/formwindowhost.cpp72
-rw-r--r--src/plugins/designer/formwindowhost.h61
-rw-r--r--src/plugins/designer/formwizard.cpp79
-rw-r--r--src/plugins/designer/formwizard.h69
-rw-r--r--src/plugins/designer/formwizarddialog.cpp127
-rw-r--r--src/plugins/designer/formwizarddialog.h104
-rw-r--r--src/plugins/designer/images/qt_ui.pngbin0 -> 666 bytes
-rw-r--r--src/plugins/designer/settingsmanager.cpp87
-rw-r--r--src/plugins/designer/settingsmanager.h64
-rw-r--r--src/plugins/designer/settingspage.cpp72
-rw-r--r--src/plugins/designer/settingspage.h70
-rw-r--r--src/plugins/designer/workbenchintegration.cpp352
-rw-r--r--src/plugins/designer/workbenchintegration.h71
-rw-r--r--src/plugins/find/Find.pluginspec10
-rw-r--r--src/plugins/find/basetextfind.cpp246
-rw-r--r--src/plugins/find/basetextfind.h90
-rw-r--r--src/plugins/find/currentdocumentfind.cpp201
-rw-r--r--src/plugins/find/currentdocumentfind.h93
-rw-r--r--src/plugins/find/find.pri3
-rw-r--r--src/plugins/find/find.pro33
-rw-r--r--src/plugins/find/find.qrc13
-rw-r--r--src/plugins/find/find_dependencies.pri1
-rw-r--r--src/plugins/find/find_global.h57
-rw-r--r--src/plugins/find/finddialog.ui146
-rw-r--r--src/plugins/find/findplugin.cpp272
-rw-r--r--src/plugins/find/findplugin.h111
-rw-r--r--src/plugins/find/findtoolbar.cpp482
-rw-r--r--src/plugins/find/findtoolbar.h112
-rw-r--r--src/plugins/find/findtoolwindow.cpp140
-rw-r--r--src/plugins/find/findtoolwindow.h78
-rw-r--r--src/plugins/find/findwidget.ui147
-rw-r--r--src/plugins/find/ifindfilter.h66
-rw-r--r--src/plugins/find/ifindsupport.h76
-rw-r--r--src/plugins/find/images/all.pngbin0 -> 108 bytes
-rw-r--r--src/plugins/find/images/casesensitively.pngbin0 -> 182 bytes
-rw-r--r--src/plugins/find/images/empty.pngbin0 -> 75 bytes
-rw-r--r--src/plugins/find/images/expand.pngbin0 -> 931 bytes
-rw-r--r--src/plugins/find/images/next.pngbin0 -> 109 bytes
-rw-r--r--src/plugins/find/images/previous.pngbin0 -> 103 bytes
-rw-r--r--src/plugins/find/images/replace_all.pngbin0 -> 934 bytes
-rw-r--r--src/plugins/find/images/wholewords.pngbin0 -> 210 bytes
-rw-r--r--src/plugins/find/images/wordandcase.pngbin0 -> 158 bytes
-rw-r--r--src/plugins/find/searchresulttreeitemdelegate.cpp121
-rw-r--r--src/plugins/find/searchresulttreeitemdelegate.h57
-rw-r--r--src/plugins/find/searchresulttreeitemroles.h57
-rw-r--r--src/plugins/find/searchresulttreeitems.cpp136
-rw-r--r--src/plugins/find/searchresulttreeitems.h106
-rw-r--r--src/plugins/find/searchresulttreemodel.cpp260
-rw-r--r--src/plugins/find/searchresulttreemodel.h87
-rw-r--r--src/plugins/find/searchresulttreeview.cpp99
-rw-r--r--src/plugins/find/searchresulttreeview.h74
-rw-r--r--src/plugins/find/searchresultwindow.cpp196
-rw-r--r--src/plugins/find/searchresultwindow.h108
-rw-r--r--src/plugins/find/textfindconstants.h57
-rw-r--r--src/plugins/git/ScmGit.pluginspec13
-rw-r--r--src/plugins/git/TODO.txt26
-rw-r--r--src/plugins/git/annotationhighlighter.cpp53
-rw-r--r--src/plugins/git/annotationhighlighter.h58
-rw-r--r--src/plugins/git/changeselectiondialog.cpp71
-rw-r--r--src/plugins/git/changeselectiondialog.h63
-rw-r--r--src/plugins/git/changeselectiondialog.ui91
-rw-r--r--src/plugins/git/commitdata.cpp96
-rw-r--r--src/plugins/git/commitdata.h81
-rw-r--r--src/plugins/git/git.pro35
-rw-r--r--src/plugins/git/gitclient.cpp635
-rw-r--r--src/plugins/git/gitclient.h168
-rw-r--r--src/plugins/git/gitconstants.h58
-rw-r--r--src/plugins/git/giteditor.cpp145
-rw-r--r--src/plugins/git/giteditor.h68
-rw-r--r--src/plugins/git/gitoutputwindow.cpp122
-rw-r--r--src/plugins/git/gitoutputwindow.h79
-rw-r--r--src/plugins/git/gitplugin.cpp717
-rw-r--r--src/plugins/git/gitplugin.h163
-rw-r--r--src/plugins/git/gitsubmiteditor.cpp92
-rw-r--r--src/plugins/git/gitsubmiteditor.h67
-rw-r--r--src/plugins/git/gitsubmiteditorwidget.cpp69
-rw-r--r--src/plugins/git/gitsubmiteditorwidget.h73
-rw-r--r--src/plugins/git/gitsubmitpanel.ui101
-rw-r--r--src/plugins/git/settingspage.cpp115
-rw-r--r--src/plugins/git/settingspage.h82
-rw-r--r--src/plugins/git/settingspage.ui135
-rw-r--r--src/plugins/helloworld/HelloWorld.pluginspec10
-rw-r--r--src/plugins/helloworld/helloworld.pro12
-rw-r--r--src/plugins/helloworld/helloworldplugin.cpp166
-rw-r--r--src/plugins/helloworld/helloworldplugin.h65
-rw-r--r--src/plugins/helloworld/helloworldwindow.cpp46
-rw-r--r--src/plugins/helloworld/helloworldwindow.h54
-rw-r--r--src/plugins/help/Help.pluginspec12
-rw-r--r--src/plugins/help/centralwidget.cpp687
-rw-r--r--src/plugins/help/centralwidget.h157
-rw-r--r--src/plugins/help/contentstoolwindow.cpp180
-rw-r--r--src/plugins/help/contentstoolwindow.h102
-rw-r--r--src/plugins/help/docsettingspage.cpp143
-rw-r--r--src/plugins/help/docsettingspage.h81
-rw-r--r--src/plugins/help/docsettingspage.ui77
-rw-r--r--src/plugins/help/filtersettingspage.cpp220
-rw-r--r--src/plugins/help/filtersettingspage.h82
-rw-r--r--src/plugins/help/filtersettingspage.ui72
-rw-r--r--src/plugins/help/help.pri3
-rw-r--r--src/plugins/help/help.pro36
-rw-r--r--src/plugins/help/help.qrc16
-rw-r--r--src/plugins/help/help_global.h57
-rw-r--r--src/plugins/help/helpengine.cpp606
-rw-r--r--src/plugins/help/helpengine.h182
-rw-r--r--src/plugins/help/helpfindsupport.cpp78
-rw-r--r--src/plugins/help/helpfindsupport.h74
-rw-r--r--src/plugins/help/helpindexfilter.cpp114
-rw-r--r--src/plugins/help/helpindexfilter.h82
-rw-r--r--src/plugins/help/helpmode.cpp53
-rw-r--r--src/plugins/help/helpmode.h61
-rw-r--r--src/plugins/help/helpplugin.cpp684
-rw-r--r--src/plugins/help/helpplugin.h169
-rw-r--r--src/plugins/help/images/book.pngbin0 -> 1669 bytes
-rw-r--r--src/plugins/help/images/bookmark.pngbin0 -> 913 bytes
-rw-r--r--src/plugins/help/images/find.pngbin0 -> 2011 bytes
-rw-r--r--src/plugins/help/images/home.pngbin0 -> 1493 bytes
-rw-r--r--src/plugins/help/images/mac/addtab.pngbin0 -> 469 bytes
-rw-r--r--src/plugins/help/images/mac/closetab.pngbin0 -> 516 bytes
-rw-r--r--src/plugins/help/images/next.pngbin0 -> 908 bytes
-rw-r--r--src/plugins/help/images/previous.pngbin0 -> 911 bytes
-rw-r--r--src/plugins/help/images/win/addtab.pngbin0 -> 314 bytes
-rw-r--r--src/plugins/help/images/win/closetab.pngbin0 -> 375 bytes
-rw-r--r--src/plugins/help/indextoolwindow.cpp215
-rw-r--r--src/plugins/help/indextoolwindow.h113
-rw-r--r--src/plugins/help/indexwindow.h82
-rw-r--r--src/plugins/help/searchwidget.cpp213
-rw-r--r--src/plugins/help/searchwidget.h88
-rw-r--r--src/plugins/perforce/Perforce.mimetypes.xml10
-rw-r--r--src/plugins/perforce/Perforce.pluginspec13
-rw-r--r--src/plugins/perforce/annotationhighlighter.cpp52
-rw-r--r--src/plugins/perforce/annotationhighlighter.h58
-rw-r--r--src/plugins/perforce/changenumberdialog.cpp52
-rw-r--r--src/plugins/perforce/changenumberdialog.h61
-rw-r--r--src/plugins/perforce/changenumberdialog.ui79
-rw-r--r--src/plugins/perforce/images/diff.pngbin0 -> 204 bytes
-rw-r--r--src/plugins/perforce/images/submit.pngbin0 -> 309 bytes
-rw-r--r--src/plugins/perforce/p4.h48
-rw-r--r--src/plugins/perforce/pendingchangesdialog.cpp72
-rw-r--r--src/plugins/perforce/pendingchangesdialog.h59
-rw-r--r--src/plugins/perforce/pendingchangesdialog.ui99
-rw-r--r--src/plugins/perforce/perforce.pro38
-rw-r--r--src/plugins/perforce/perforce.qrc7
-rw-r--r--src/plugins/perforce/perforce_dependencies.pri5
-rw-r--r--src/plugins/perforce/perforceconstants.h53
-rw-r--r--src/plugins/perforce/perforceeditor.cpp159
-rw-r--r--src/plugins/perforce/perforceeditor.h67
-rw-r--r--src/plugins/perforce/perforceoutputwindow.cpp166
-rw-r--r--src/plugins/perforce/perforceoutputwindow.h87
-rw-r--r--src/plugins/perforce/perforceplugin.cpp1270
-rw-r--r--src/plugins/perforce/perforceplugin.h250
-rw-r--r--src/plugins/perforce/perforcesettings.cpp95
-rw-r--r--src/plugins/perforce/perforcesettings.h65
-rw-r--r--src/plugins/perforce/perforcesubmiteditor.cpp194
-rw-r--r--src/plugins/perforce/perforcesubmiteditor.h84
-rw-r--r--src/plugins/perforce/perforcesubmiteditorwidget.cpp55
-rw-r--r--src/plugins/perforce/perforcesubmiteditorwidget.h60
-rw-r--r--src/plugins/perforce/perforceversioncontrol.cpp69
-rw-r--r--src/plugins/perforce/perforceversioncontrol.h60
-rw-r--r--src/plugins/perforce/promptdialog.ui128
-rw-r--r--src/plugins/perforce/settingspage.cpp110
-rw-r--r--src/plugins/perforce/settingspage.h84
-rw-r--r--src/plugins/perforce/settingspage.ui148
-rw-r--r--src/plugins/perforce/submitpanel.ui100
-rw-r--r--src/plugins/perforce/workbenchclientuser.cpp285
-rw-r--r--src/plugins/perforce/workbenchclientuser.h111
-rw-r--r--src/plugins/plugins.pro150
-rw-r--r--src/plugins/projectexplorer/ProjectExplorer.pluginspec13
-rw-r--r--src/plugins/projectexplorer/ProjectExplorerInterfaces11
-rw-r--r--src/plugins/projectexplorer/abstractprocess.h72
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.cpp237
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.h141
-rw-r--r--src/plugins/projectexplorer/allprojectsfilter.cpp75
-rw-r--r--src/plugins/projectexplorer/allprojectsfilter.h73
-rw-r--r--src/plugins/projectexplorer/allprojectsfind.cpp133
-rw-r--r--src/plugins/projectexplorer/allprojectsfind.h80
-rw-r--r--src/plugins/projectexplorer/applicationlauncher.h96
-rw-r--r--src/plugins/projectexplorer/applicationlauncher_win.cpp137
-rw-r--r--src/plugins/projectexplorer/applicationlauncher_x11.cpp159
-rw-r--r--src/plugins/projectexplorer/applicationrunconfiguration.cpp169
-rw-r--r--src/plugins/projectexplorer/applicationrunconfiguration.h100
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp101
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.h64
-rw-r--r--src/plugins/projectexplorer/buildmanager.cpp385
-rw-r--r--src/plugins/projectexplorer/buildmanager.h139
-rw-r--r--src/plugins/projectexplorer/buildparserinterface.cpp41
-rw-r--r--src/plugins/projectexplorer/buildparserinterface.h76
-rw-r--r--src/plugins/projectexplorer/buildprogress.cpp98
-rw-r--r--src/plugins/projectexplorer/buildprogress.h65
-rw-r--r--src/plugins/projectexplorer/buildsettingspropertiespage.cpp464
-rw-r--r--src/plugins/projectexplorer/buildsettingspropertiespage.h102
-rw-r--r--src/plugins/projectexplorer/buildsettingspropertiespage.ui190
-rw-r--r--src/plugins/projectexplorer/buildstep.cpp146
-rw-r--r--src/plugins/projectexplorer/buildstep.h181
-rw-r--r--src/plugins/projectexplorer/buildstepspage.cpp266
-rw-r--r--src/plugins/projectexplorer/buildstepspage.h87
-rw-r--r--src/plugins/projectexplorer/buildstepspage.ui127
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.cpp96
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.h70
-rw-r--r--src/plugins/projectexplorer/consoleprocess.h99
-rw-r--r--src/plugins/projectexplorer/consoleprocess_unix.cpp102
-rw-r--r--src/plugins/projectexplorer/consoleprocess_win.cpp239
-rw-r--r--src/plugins/projectexplorer/currentprojectfilter.cpp96
-rw-r--r--src/plugins/projectexplorer/currentprojectfilter.h78
-rw-r--r--src/plugins/projectexplorer/currentprojectfind.cpp129
-rw-r--r--src/plugins/projectexplorer/currentprojectfind.h75
-rw-r--r--src/plugins/projectexplorer/customexecutablerunconfiguration.cpp316
-rw-r--r--src/plugins/projectexplorer/customexecutablerunconfiguration.h126
-rw-r--r--src/plugins/projectexplorer/dependenciesdialog.cpp244
-rw-r--r--src/plugins/projectexplorer/dependenciesdialog.h73
-rw-r--r--src/plugins/projectexplorer/dependenciesdialog.ui98
-rw-r--r--src/plugins/projectexplorer/directoryproject.cpp34
-rw-r--r--src/plugins/projectexplorer/editorconfiguration.cpp53
-rw-r--r--src/plugins/projectexplorer/editorconfiguration.h59
-rw-r--r--src/plugins/projectexplorer/editorsettingspropertiespage.cpp111
-rw-r--r--src/plugins/projectexplorer/editorsettingspropertiespage.h84
-rw-r--r--src/plugins/projectexplorer/editorsettingspropertiespage.ui57
-rw-r--r--src/plugins/projectexplorer/environment.cpp346
-rw-r--r--src/plugins/projectexplorer/environment.h101
-rw-r--r--src/plugins/projectexplorer/environmenteditmodel.cpp421
-rw-r--r--src/plugins/projectexplorer/environmenteditmodel.h92
-rw-r--r--src/plugins/projectexplorer/foldernavigationwidget.cpp217
-rw-r--r--src/plugins/projectexplorer/foldernavigationwidget.h101
-rw-r--r--src/plugins/projectexplorer/images/build.pngbin0 -> 1047 bytes
-rw-r--r--src/plugins/projectexplorer/images/build_small.pngbin0 -> 728 bytes
-rw-r--r--src/plugins/projectexplorer/images/clean.pngbin0 -> 1180 bytes
-rw-r--r--src/plugins/projectexplorer/images/clean_small.pngbin0 -> 785 bytes
-rw-r--r--src/plugins/projectexplorer/images/closetab.pngbin0 -> 375 bytes
-rw-r--r--src/plugins/projectexplorer/images/compile_error.pngbin0 -> 580 bytes
-rw-r--r--src/plugins/projectexplorer/images/compile_unspecified.pngbin0 -> 959 bytes
-rw-r--r--src/plugins/projectexplorer/images/compile_warning.pngbin0 -> 668 bytes
-rw-r--r--src/plugins/projectexplorer/images/debugger_start.pngbin0 -> 1616 bytes
-rw-r--r--src/plugins/projectexplorer/images/debugger_start_small.pngbin0 -> 766 bytes
-rw-r--r--src/plugins/projectexplorer/images/filtericon.pngbin0 -> 194 bytes
-rw-r--r--src/plugins/projectexplorer/images/findallprojects.pngbin0 -> 822 bytes
-rw-r--r--src/plugins/projectexplorer/images/findproject.pngbin0 -> 745 bytes
-rw-r--r--src/plugins/projectexplorer/images/insert_line_small.pngbin0 -> 584 bytes
-rw-r--r--src/plugins/projectexplorer/images/projectexplorer.pngbin0 -> 782 bytes
-rw-r--r--src/plugins/projectexplorer/images/rebuild.pngbin0 -> 1734 bytes
-rw-r--r--src/plugins/projectexplorer/images/rebuild_small.pngbin0 -> 979 bytes
-rw-r--r--src/plugins/projectexplorer/images/run.pngbin0 -> 856 bytes
-rw-r--r--src/plugins/projectexplorer/images/run_small.pngbin0 -> 565 bytes
-rw-r--r--src/plugins/projectexplorer/images/session.pngbin0 -> 583 bytes
-rw-r--r--src/plugins/projectexplorer/images/stop.pngbin0 -> 578 bytes
-rw-r--r--src/plugins/projectexplorer/iprojectmanager.h60
-rw-r--r--src/plugins/projectexplorer/iprojectproperties.h68
-rw-r--r--src/plugins/projectexplorer/metatypedeclarations.h67
-rw-r--r--src/plugins/projectexplorer/nodesvisitor.cpp129
-rw-r--r--src/plugins/projectexplorer/nodesvisitor.h87
-rw-r--r--src/plugins/projectexplorer/outputwindow.cpp680
-rw-r--r--src/plugins/projectexplorer/outputwindow.h198
-rw-r--r--src/plugins/projectexplorer/persistentsettings.cpp225
-rw-r--r--src/plugins/projectexplorer/persistentsettings.h75
-rw-r--r--src/plugins/projectexplorer/pluginfilefactory.cpp101
-rw-r--r--src/plugins/projectexplorer/pluginfilefactory.h76
-rw-r--r--src/plugins/projectexplorer/processstep.cpp220
-rw-r--r--src/plugins/projectexplorer/processstep.h97
-rw-r--r--src/plugins/projectexplorer/processstep.ui100
-rw-r--r--src/plugins/projectexplorer/project.cpp522
-rw-r--r--src/plugins/projectexplorer/project.h182
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp1814
-rw-r--r--src/plugins/projectexplorer/projectexplorer.h280
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pri3
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro115
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qrc23
-rw-r--r--src/plugins/projectexplorer/projectexplorer_dependencies.pri5
-rw-r--r--src/plugins/projectexplorer/projectexplorer_export.h57
-rw-r--r--src/plugins/projectexplorer/projectexplorerconstants.h180
-rw-r--r--src/plugins/projectexplorer/projectfilewizardextension.cpp199
-rw-r--r--src/plugins/projectexplorer/projectfilewizardextension.h73
-rw-r--r--src/plugins/projectexplorer/projectmodels.cpp1180
-rw-r--r--src/plugins/projectexplorer/projectmodels.h186
-rw-r--r--src/plugins/projectexplorer/projectnodes.cpp685
-rw-r--r--src/plugins/projectexplorer/projectnodes.h289
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.cpp327
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.h109
-rw-r--r--src/plugins/projectexplorer/projectwindow.cpp273
-rw-r--r--src/plugins/projectexplorer/projectwindow.h92
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.cpp121
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.h83
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.ui124
-rw-r--r--src/plugins/projectexplorer/removefiledialog.cpp68
-rw-r--r--src/plugins/projectexplorer/removefiledialog.h64
-rw-r--r--src/plugins/projectexplorer/removefiledialog.ui133
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp138
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h168
-rw-r--r--src/plugins/projectexplorer/runsettingspropertiespage.cpp292
-rw-r--r--src/plugins/projectexplorer/runsettingspropertiespage.h100
-rw-r--r--src/plugins/projectexplorer/runsettingspropertiespage.ui102
-rw-r--r--src/plugins/projectexplorer/scriptwrappers.cpp34
-rw-r--r--src/plugins/projectexplorer/scriptwrappers.h36
-rw-r--r--src/plugins/projectexplorer/session.cpp1109
-rw-r--r--src/plugins/projectexplorer/session.h207
-rw-r--r--src/plugins/projectexplorer/sessiondialog.cpp194
-rw-r--r--src/plugins/projectexplorer/sessiondialog.h73
-rw-r--r--src/plugins/projectexplorer/sessiondialog.ui109
-rw-r--r--src/plugins/projectexplorer/taskwindow.cpp534
-rw-r--r--src/plugins/projectexplorer/taskwindow.h127
-rw-r--r--src/plugins/projectexplorer/winguiprocess.cpp187
-rw-r--r--src/plugins/projectexplorer/winguiprocess.h78
-rw-r--r--src/plugins/qhelpproject/qhelpproject.cpp201
-rw-r--r--src/plugins/qhelpproject/qhelpproject.h115
-rw-r--r--src/plugins/qhelpproject/qhelpproject.pro16
-rw-r--r--src/plugins/qhelpproject/qhelpprojectitems.cpp106
-rw-r--r--src/plugins/qhelpproject/qhelpprojectitems.h91
-rw-r--r--src/plugins/qhelpproject/qhelpprojectmanager.cpp121
-rw-r--r--src/plugins/qhelpproject/qhelpprojectmanager.h89
-rw-r--r--src/plugins/qt4projectmanager/Qt4ProjectManager.mimetypes.xml13
-rw-r--r--src/plugins/qt4projectmanager/Qt4ProjectManager.pluginspec14
-rw-r--r--src/plugins/qt4projectmanager/applicationlauncher.h88
-rw-r--r--src/plugins/qt4projectmanager/buildoptionspage.cpp105
-rw-r--r--src/plugins/qt4projectmanager/buildparserfactory.cpp71
-rw-r--r--src/plugins/qt4projectmanager/buildparserfactory.h68
-rw-r--r--src/plugins/qt4projectmanager/cesdkhandler.cpp153
-rw-r--r--src/plugins/qt4projectmanager/cesdkhandler.h107
-rw-r--r--src/plugins/qt4projectmanager/deployhelper.cpp196
-rw-r--r--src/plugins/qt4projectmanager/deployhelper.h95
-rw-r--r--src/plugins/qt4projectmanager/directorywatcher.cpp206
-rw-r--r--src/plugins/qt4projectmanager/directorywatcher.h93
-rw-r--r--src/plugins/qt4projectmanager/embeddedpropertiespage.cpp140
-rw-r--r--src/plugins/qt4projectmanager/embeddedpropertiespage.h85
-rw-r--r--src/plugins/qt4projectmanager/embeddedpropertiespage.ui49
-rw-r--r--src/plugins/qt4projectmanager/enveditdialog.ui236
-rw-r--r--src/plugins/qt4projectmanager/envvariablespage.ui121
-rw-r--r--src/plugins/qt4projectmanager/gccparser.cpp131
-rw-r--r--src/plugins/qt4projectmanager/gccparser.h60
-rw-r--r--src/plugins/qt4projectmanager/gccpreprocessor.cpp127
-rw-r--r--src/plugins/qt4projectmanager/gccpreprocessor.h62
-rw-r--r--src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp192
-rw-r--r--src/plugins/qt4projectmanager/gdbmacrosbuildstep.h82
-rw-r--r--src/plugins/qt4projectmanager/headerpath.h69
-rw-r--r--src/plugins/qt4projectmanager/images/qt_project.pngbin0 -> 516 bytes
-rw-r--r--src/plugins/qt4projectmanager/images/run_qmake.pngbin0 -> 1903 bytes
-rw-r--r--src/plugins/qt4projectmanager/images/run_qmake_small.pngbin0 -> 804 bytes
-rw-r--r--src/plugins/qt4projectmanager/images/window.pngbin0 -> 323 bytes
-rw-r--r--src/plugins/qt4projectmanager/makestep.cpp315
-rw-r--r--src/plugins/qt4projectmanager/makestep.h95
-rw-r--r--src/plugins/qt4projectmanager/makestep.ui79
-rw-r--r--src/plugins/qt4projectmanager/msvcenvironment.cpp156
-rw-r--r--src/plugins/qt4projectmanager/msvcenvironment.h64
-rw-r--r--src/plugins/qt4projectmanager/msvcparser.cpp92
-rw-r--r--src/plugins/qt4projectmanager/msvcparser.h59
-rw-r--r--src/plugins/qt4projectmanager/proeditorcontainer.ui72
-rw-r--r--src/plugins/qt4projectmanager/profilecache.cpp362
-rw-r--r--src/plugins/qt4projectmanager/profilecache.h97
-rw-r--r--src/plugins/qt4projectmanager/profileeditor.cpp169
-rw-r--r--src/plugins/qt4projectmanager/profileeditor.h121
-rw-r--r--src/plugins/qt4projectmanager/profileeditorfactory.cpp96
-rw-r--r--src/plugins/qt4projectmanager/profileeditorfactory.h80
-rw-r--r--src/plugins/qt4projectmanager/profilehighlighter.cpp198
-rw-r--r--src/plugins/qt4projectmanager/profilehighlighter.h65
-rw-r--r--src/plugins/qt4projectmanager/profilereader.cpp192
-rw-r--r--src/plugins/qt4projectmanager/profilereader.h86
-rw-r--r--src/plugins/qt4projectmanager/projectloadwizard.cpp221
-rw-r--r--src/plugins/qt4projectmanager/projectloadwizard.h102
-rw-r--r--src/plugins/qt4projectmanager/qmakebuildstepfactory.cpp102
-rw-r--r--src/plugins/qt4projectmanager/qmakebuildstepfactory.h75
-rw-r--r--src/plugins/qt4projectmanager/qmakestep.cpp272
-rw-r--r--src/plugins/qt4projectmanager/qmakestep.h94
-rw-r--r--src/plugins/qt4projectmanager/qmakestep.ui120
-rw-r--r--src/plugins/qt4projectmanager/qt4buildconfigwidget.cpp257
-rw-r--r--src/plugins/qt4projectmanager/qt4buildconfigwidget.h76
-rw-r--r--src/plugins/qt4projectmanager/qt4buildconfigwidget.ui191
-rw-r--r--src/plugins/qt4projectmanager/qt4buildenvironmentwidget.cpp182
-rw-r--r--src/plugins/qt4projectmanager/qt4buildenvironmentwidget.h83
-rw-r--r--src/plugins/qt4projectmanager/qt4buildenvironmentwidget.ui93
-rw-r--r--src/plugins/qt4projectmanager/qt4nodes.cpp975
-rw-r--r--src/plugins/qt4projectmanager/qt4nodes.h234
-rw-r--r--src/plugins/qt4projectmanager/qt4project.cpp897
-rw-r--r--src/plugins/qt4projectmanager/qt4project.h239
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanager.cpp229
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanager.h123
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanager.pro101
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanager.qrc9
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanager_dependencies.pri4
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanagerconstants.h90
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanagerenums.h49
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp235
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanagerplugin.h97
-rw-r--r--src/plugins/qt4projectmanager/qt4runconfiguration.cpp443
-rw-r--r--src/plugins/qt4projectmanager/qt4runconfiguration.h119
-rw-r--r--src/plugins/qt4projectmanager/qtversionmanager.cpp1278
-rw-r--r--src/plugins/qt4projectmanager/qtversionmanager.h214
-rw-r--r--src/plugins/qt4projectmanager/qtversionmanager.ui212
-rw-r--r--src/plugins/qt4projectmanager/speinfo.cpp805
-rw-r--r--src/plugins/qt4projectmanager/speinfo.h116
-rw-r--r--src/plugins/qt4projectmanager/wizards/consoleappwizard.cpp105
-rw-r--r--src/plugins/qt4projectmanager/wizards/consoleappwizard.h62
-rw-r--r--src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp90
-rw-r--r--src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.h74
-rw-r--r--src/plugins/qt4projectmanager/wizards/filespage.cpp185
-rw-r--r--src/plugins/qt4projectmanager/wizards/filespage.h95
-rw-r--r--src/plugins/qt4projectmanager/wizards/guiappwizard.cpp201
-rw-r--r--src/plugins/qt4projectmanager/wizards/guiappwizard.h70
-rw-r--r--src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp136
-rw-r--r--src/plugins/qt4projectmanager/wizards/guiappwizarddialog.h91
-rw-r--r--src/plugins/qt4projectmanager/wizards/images/console.pngbin0 -> 567 bytes
-rw-r--r--src/plugins/qt4projectmanager/wizards/images/gui.pngbin0 -> 831 bytes
-rw-r--r--src/plugins/qt4projectmanager/wizards/images/lib.pngbin0 -> 1245 bytes
-rw-r--r--src/plugins/qt4projectmanager/wizards/libraryparameters.cpp166
-rw-r--r--src/plugins/qt4projectmanager/wizards/libraryparameters.h72
-rw-r--r--src/plugins/qt4projectmanager/wizards/librarywizard.cpp128
-rw-r--r--src/plugins/qt4projectmanager/wizards/librarywizard.h65
-rw-r--r--src/plugins/qt4projectmanager/wizards/librarywizarddialog.cpp268
-rw-r--r--src/plugins/qt4projectmanager/wizards/librarywizarddialog.h80
-rw-r--r--src/plugins/qt4projectmanager/wizards/modulespage.cpp128
-rw-r--r--src/plugins/qt4projectmanager/wizards/modulespage.h68
-rw-r--r--src/plugins/qt4projectmanager/wizards/qtprojectparameters.cpp128
-rw-r--r--src/plugins/qt4projectmanager/wizards/qtprojectparameters.h77
-rw-r--r--src/plugins/qt4projectmanager/wizards/qtwizard.cpp106
-rw-r--r--src/plugins/qt4projectmanager/wizards/qtwizard.h87
-rw-r--r--src/plugins/qt4projectmanager/wizards/wizards.qrc7
-rw-r--r--src/plugins/qtestlib/QTestLibPlugin.qwp16
-rw-r--r--src/plugins/qtestlib/images/pass.pngbin0 -> 235 bytes
-rw-r--r--src/plugins/qtestlib/qtestlib.pro14
-rw-r--r--src/plugins/qtestlib/qtestlib.qrc5
-rw-r--r--src/plugins/qtestlib/qtestlibplugin.cpp501
-rw-r--r--src/plugins/qtestlib/qtestlibplugin.h209
-rw-r--r--src/plugins/qtscripteditor/QtScriptEditor.mimetypes.xml41
-rw-r--r--src/plugins/qtscripteditor/QtScriptEditor.pluginspec11
-rw-r--r--src/plugins/qtscripteditor/qtscripteditor.cpp172
-rw-r--r--src/plugins/qtscripteditor/qtscripteditor.h99
-rw-r--r--src/plugins/qtscripteditor/qtscripteditor.pro22
-rw-r--r--src/plugins/qtscripteditor/qtscripteditor.qrc5
-rw-r--r--src/plugins/qtscripteditor/qtscripteditoractionhandler.cpp110
-rw-r--r--src/plugins/qtscripteditor/qtscripteditoractionhandler.h62
-rw-r--r--src/plugins/qtscripteditor/qtscripteditorconstants.h46
-rw-r--r--src/plugins/qtscripteditor/qtscripteditorfactory.cpp89
-rw-r--r--src/plugins/qtscripteditor/qtscripteditorfactory.h84
-rw-r--r--src/plugins/qtscripteditor/qtscripteditorplugin.cpp145
-rw-r--r--src/plugins/qtscripteditor/qtscripteditorplugin.h84
-rw-r--r--src/plugins/qtscripteditor/qtscripthighlighter.cpp110
-rw-r--r--src/plugins/qtscripteditor/qtscripthighlighter.h67
-rw-r--r--src/plugins/quickopen/QuickOpen.pluginspec10
-rw-r--r--src/plugins/quickopen/basefilefilter.cpp105
-rw-r--r--src/plugins/quickopen/basefilefilter.h71
-rw-r--r--src/plugins/quickopen/directoryfilter.cpp258
-rw-r--r--src/plugins/quickopen/directoryfilter.h87
-rw-r--r--src/plugins/quickopen/directoryfilter.ui197
-rw-r--r--src/plugins/quickopen/directoryparser.cpp104
-rw-r--r--src/plugins/quickopen/directoryparser.h77
-rw-r--r--src/plugins/quickopen/filesystemfilter.cpp161
-rw-r--r--src/plugins/quickopen/filesystemfilter.h81
-rw-r--r--src/plugins/quickopen/filesystemfilter.ui111
-rw-r--r--src/plugins/quickopen/images/quickopen.pngbin0 -> 767 bytes
-rw-r--r--src/plugins/quickopen/images/reload.pngbin0 -> 735 bytes
-rw-r--r--src/plugins/quickopen/iquickopenfilter.cpp130
-rw-r--r--src/plugins/quickopen/iquickopenfilter.h152
-rw-r--r--src/plugins/quickopen/opendocumentsfilter.cpp104
-rw-r--r--src/plugins/quickopen/opendocumentsfilter.h76
-rw-r--r--src/plugins/quickopen/quickopen.pri3
-rw-r--r--src/plugins/quickopen/quickopen.pro31
-rw-r--r--src/plugins/quickopen/quickopen.qrc6
-rw-r--r--src/plugins/quickopen/quickopen_dependencies.pri2
-rw-r--r--src/plugins/quickopen/quickopen_global.h57
-rw-r--r--src/plugins/quickopen/quickopenconstants.h44
-rw-r--r--src/plugins/quickopen/quickopenfiltersfilter.cpp104
-rw-r--r--src/plugins/quickopen/quickopenfiltersfilter.h74
-rw-r--r--src/plugins/quickopen/quickopenmanager.cpp61
-rw-r--r--src/plugins/quickopen/quickopenmanager.h66
-rw-r--r--src/plugins/quickopen/quickopenplugin.cpp252
-rw-r--r--src/plugins/quickopen/quickopenplugin.h97
-rw-r--r--src/plugins/quickopen/quickopentoolwindow.cpp484
-rw-r--r--src/plugins/quickopen/quickopentoolwindow.h102
-rw-r--r--src/plugins/quickopen/settingspage.cpp187
-rw-r--r--src/plugins/quickopen/settingspage.h97
-rw-r--r--src/plugins/quickopen/settingspage.ui118
-rw-r--r--src/plugins/quickopen/settingswidget.ui133
-rw-r--r--src/plugins/regexp/RegExp.pluginspec10
-rw-r--r--src/plugins/regexp/regexp.pro10
-rw-r--r--src/plugins/regexp/regexpplugin.cpp77
-rw-r--r--src/plugins/regexp/regexpplugin.h69
-rw-r--r--src/plugins/regexp/regexpwindow.cpp294
-rw-r--r--src/plugins/regexp/regexpwindow.h92
-rw-r--r--src/plugins/regexp/settings.cpp94
-rw-r--r--src/plugins/regexp/settings.h69
-rw-r--r--src/plugins/resourceeditor/ResourceEditor.mimetypes.xml8
-rw-r--r--src/plugins/resourceeditor/ResourceEditor.pluginspec10
-rw-r--r--src/plugins/resourceeditor/images/qt_qrc.pngbin0 -> 622 bytes
-rw-r--r--src/plugins/resourceeditor/resourceeditor.pro24
-rw-r--r--src/plugins/resourceeditor/resourceeditor.qrc6
-rw-r--r--src/plugins/resourceeditor/resourceeditorconstants.h44
-rw-r--r--src/plugins/resourceeditor/resourceeditorfactory.cpp86
-rw-r--r--src/plugins/resourceeditor/resourceeditorfactory.h80
-rw-r--r--src/plugins/resourceeditor/resourceeditorplugin.cpp131
-rw-r--r--src/plugins/resourceeditor/resourceeditorplugin.h84
-rw-r--r--src/plugins/resourceeditor/resourceeditorw.cpp271
-rw-r--r--src/plugins/resourceeditor/resourceeditorw.h143
-rw-r--r--src/plugins/resourceeditor/resourcewizard.cpp59
-rw-r--r--src/plugins/resourceeditor/resourcewizard.h59
-rw-r--r--src/plugins/snippets/Snippets.pluginspec12
-rw-r--r--src/plugins/snippets/images/dir.pngbin0 -> 862 bytes
-rw-r--r--src/plugins/snippets/images/diropen.pngbin0 -> 931 bytes
-rw-r--r--src/plugins/snippets/images/file.pngbin0 -> 452 bytes
-rw-r--r--src/plugins/snippets/images/snippets.pngbin0 -> 908 bytes
-rw-r--r--src/plugins/snippets/inputwidget.cpp134
-rw-r--r--src/plugins/snippets/inputwidget.h70
-rw-r--r--src/plugins/snippets/snippets.pro24
-rw-r--r--src/plugins/snippets/snippets.qrc8
-rw-r--r--src/plugins/snippets/snippetscompletion.cpp159
-rw-r--r--src/plugins/snippets/snippetscompletion.h99
-rw-r--r--src/plugins/snippets/snippetspec.cpp100
-rw-r--r--src/plugins/snippets/snippetspec.h68
-rw-r--r--src/plugins/snippets/snippetsplugin.cpp118
-rw-r--r--src/plugins/snippets/snippetsplugin.h90
-rw-r--r--src/plugins/snippets/snippetswindow.cpp434
-rw-r--r--src/plugins/snippets/snippetswindow.h128
-rw-r--r--src/plugins/subversion/Subversion.mimetypes.xml7
-rw-r--r--src/plugins/subversion/Subversion.pluginspec13
-rw-r--r--src/plugins/subversion/annotationhighlighter.cpp52
-rw-r--r--src/plugins/subversion/annotationhighlighter.h58
-rw-r--r--src/plugins/subversion/changenumberdialog.cpp52
-rw-r--r--src/plugins/subversion/changenumberdialog.h60
-rw-r--r--src/plugins/subversion/changenumberdialog.ui79
-rw-r--r--src/plugins/subversion/images/diff.pngbin0 -> 204 bytes
-rw-r--r--src/plugins/subversion/images/submit.pngbin0 -> 309 bytes
-rw-r--r--src/plugins/subversion/settingspage.cpp110
-rw-r--r--src/plugins/subversion/settingspage.h90
-rw-r--r--src/plugins/subversion/settingspage.ui117
-rw-r--r--src/plugins/subversion/subversion.pro34
-rw-r--r--src/plugins/subversion/subversion.qrc7
-rw-r--r--src/plugins/subversion/subversionconstants.h51
-rw-r--r--src/plugins/subversion/subversioncontrol.cpp70
-rw-r--r--src/plugins/subversion/subversioncontrol.h60
-rw-r--r--src/plugins/subversion/subversioneditor.cpp140
-rw-r--r--src/plugins/subversion/subversioneditor.h65
-rw-r--r--src/plugins/subversion/subversionoutputwindow.cpp105
-rw-r--r--src/plugins/subversion/subversionoutputwindow.h81
-rw-r--r--src/plugins/subversion/subversionplugin.cpp1087
-rw-r--r--src/plugins/subversion/subversionplugin.h223
-rw-r--r--src/plugins/subversion/subversionsettings.cpp133
-rw-r--r--src/plugins/subversion/subversionsettings.h73
-rw-r--r--src/plugins/subversion/subversionsubmiteditor.cpp63
-rw-r--r--src/plugins/subversion/subversionsubmiteditor.h57
-rw-r--r--src/plugins/texteditor/TextEditor.mimetypes.xml47
-rw-r--r--src/plugins/texteditor/TextEditor.pluginspec12
-rw-r--r--src/plugins/texteditor/basefilefind.cpp233
-rw-r--r--src/plugins/texteditor/basefilefind.h95
-rw-r--r--src/plugins/texteditor/basetextdocument.cpp349
-rw-r--r--src/plugins/texteditor/basetextdocument.h161
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp3453
-rw-r--r--src/plugins/texteditor/basetexteditor.h513
-rw-r--r--src/plugins/texteditor/basetexteditor_p.h225
-rw-r--r--src/plugins/texteditor/basetextmark.cpp136
-rw-r--r--src/plugins/texteditor/basetextmark.h132
-rw-r--r--src/plugins/texteditor/codecselector.cpp179
-rw-r--r--src/plugins/texteditor/codecselector.h85
-rw-r--r--src/plugins/texteditor/completionsupport.cpp171
-rw-r--r--src/plugins/texteditor/completionsupport.h83
-rw-r--r--src/plugins/texteditor/completionwidget.cpp264
-rw-r--r--src/plugins/texteditor/completionwidget.h90
-rw-r--r--src/plugins/texteditor/displaysettings.cpp108
-rw-r--r--src/plugins/texteditor/displaysettings.h67
-rw-r--r--src/plugins/texteditor/findinfiles.cpp144
-rw-r--r--src/plugins/texteditor/findinfiles.h83
-rw-r--r--src/plugins/texteditor/fontsettings.cpp277
-rw-r--r--src/plugins/texteditor/fontsettings.h149
-rw-r--r--src/plugins/texteditor/fontsettingspage.cpp465
-rw-r--r--src/plugins/texteditor/fontsettingspage.h124
-rw-r--r--src/plugins/texteditor/fontsettingspage.ui268
-rw-r--r--src/plugins/texteditor/generalsettingspage.cpp217
-rw-r--r--src/plugins/texteditor/generalsettingspage.h98
-rw-r--r--src/plugins/texteditor/generalsettingspage.ui336
-rw-r--r--src/plugins/texteditor/icompletioncollector.h114
-rw-r--r--src/plugins/texteditor/images/finddirectory.pngbin0 -> 845 bytes
-rw-r--r--src/plugins/texteditor/images/finddocuments.pngbin0 -> 721 bytes
-rw-r--r--src/plugins/texteditor/itexteditable.h64
-rw-r--r--src/plugins/texteditor/itexteditor.h132
-rw-r--r--src/plugins/texteditor/linenumberfilter.cpp80
-rw-r--r--src/plugins/texteditor/linenumberfilter.h76
-rw-r--r--src/plugins/texteditor/plaintexteditor.cpp129
-rw-r--r--src/plugins/texteditor/plaintexteditor.h72
-rw-r--r--src/plugins/texteditor/plaintexteditorfactory.cpp83
-rw-r--r--src/plugins/texteditor/plaintexteditorfactory.h73
-rw-r--r--src/plugins/texteditor/storagesettings.cpp81
-rw-r--r--src/plugins/texteditor/storagesettings.h62
-rw-r--r--src/plugins/texteditor/tabsettings.cpp241
-rw-r--r--src/plugins/texteditor/tabsettings.h83
-rw-r--r--src/plugins/texteditor/textblockiterator.cpp96
-rw-r--r--src/plugins/texteditor/textblockiterator.h71
-rw-r--r--src/plugins/texteditor/texteditor.pri3
-rw-r--r--src/plugins/texteditor/texteditor.pro58
-rw-r--r--src/plugins/texteditor/texteditor.qrc7
-rw-r--r--src/plugins/texteditor/texteditor_dependencies.pri4
-rw-r--r--src/plugins/texteditor/texteditor_global.h57
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.cpp459
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.h143
-rw-r--r--src/plugins/texteditor/texteditorconstants.h88
-rw-r--r--src/plugins/texteditor/texteditorplugin.cpp180
-rw-r--r--src/plugins/texteditor/texteditorplugin.h94
-rw-r--r--src/plugins/texteditor/texteditorsettings.cpp152
-rw-r--r--src/plugins/texteditor/texteditorsettings.h88
-rw-r--r--src/plugins/texteditor/textfilewizard.cpp63
-rw-r--r--src/plugins/texteditor/textfilewizard.h67
-rw-r--r--src/plugins/vcsbase/README.txt6
-rw-r--r--src/plugins/vcsbase/VCSBase.mimetypes.xml39
-rw-r--r--src/plugins/vcsbase/VCSBase.pluginspec12
-rw-r--r--src/plugins/vcsbase/baseannotationhighlighter.cpp102
-rw-r--r--src/plugins/vcsbase/baseannotationhighlighter.h76
-rw-r--r--src/plugins/vcsbase/basevcseditorfactory.cpp106
-rw-r--r--src/plugins/vcsbase/basevcseditorfactory.h121
-rw-r--r--src/plugins/vcsbase/basevcssubmiteditorfactory.cpp89
-rw-r--r--src/plugins/vcsbase/basevcssubmiteditorfactory.h100
-rw-r--r--src/plugins/vcsbase/diffhighlighter.cpp119
-rw-r--r--src/plugins/vcsbase/diffhighlighter.h91
-rw-r--r--src/plugins/vcsbase/submiteditorfile.cpp71
-rw-r--r--src/plugins/vcsbase/submiteditorfile.h77
-rw-r--r--src/plugins/vcsbase/vcsbase.pri3
-rw-r--r--src/plugins/vcsbase/vcsbase.pro31
-rw-r--r--src/plugins/vcsbase/vcsbase.qrc5
-rw-r--r--src/plugins/vcsbase/vcsbase_dependencies.pri4
-rw-r--r--src/plugins/vcsbase/vcsbase_global.h57
-rw-r--r--src/plugins/vcsbase/vcsbaseconstants.h46
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.cpp486
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.h173
-rw-r--r--src/plugins/vcsbase/vcsbaseplugin.cpp81
-rw-r--r--src/plugins/vcsbase/vcsbaseplugin.h64
-rw-r--r--src/plugins/vcsbase/vcsbasesubmiteditor.cpp281
-rw-r--r--src/plugins/vcsbase/vcsbasesubmiteditor.h146
-rw-r--r--src/plugins/vcsbase/vcsbasetextdocument.cpp53
-rw-r--r--src/plugins/vcsbase/vcsbasetextdocument.h55
-rw-r--r--src/qworkbench.pri41
-rw-r--r--src/qworkbenchlibrary.pri22
-rw-r--r--src/qworkbenchplugin.pri57
-rw-r--r--src/src.pro9
-rw-r--r--src/tools/makespy/main.cpp211
-rw-r--r--src/tools/makespy/makespy.pro6
-rw-r--r--src/tools/qdebugger/lean.h153
-rw-r--r--src/tools/qdebugger/main.cpp46
-rw-r--r--src/tools/qdebugger/mainwindow.cpp543
-rw-r--r--src/tools/qdebugger/mainwindow.h104
-rw-r--r--src/tools/qdebugger/qdebugger.pro123
-rw-r--r--src/tools/qtcreatorwidgets/README.txt8
-rw-r--r--src/tools/qtcreatorwidgets/customwidget.h163
-rw-r--r--src/tools/qtcreatorwidgets/customwidgets.cpp171
-rw-r--r--src/tools/qtcreatorwidgets/customwidgets.h162
-rw-r--r--src/tools/qtcreatorwidgets/qtcreatorwidgets.pro25
-rw-r--r--src/tools/texteditor/main.cpp46
-rw-r--r--src/tools/texteditor/mainwindow.cpp215
-rw-r--r--src/tools/texteditor/mainwindow.h75
-rw-r--r--src/tools/texteditor/texteditor.pro46
-rw-r--r--tests/auto/extensionsystem/extensionsystem.pro11
-rw-r--r--tests/auto/extensionsystem/tst_composite.cpp103
-rw-r--r--tests/auto/profilereader/data/includefiles/pri.cpp32
-rw-r--r--tests/auto/profilereader/data/includefiles/pro.cpp32
-rw-r--r--tests/auto/profilereader/data/includefiles/test.pri1
-rw-r--r--tests/auto/profilereader/data/includefiles/test.pro3
-rw-r--r--tests/auto/profilereader/main.cpp71
-rw-r--r--tests/auto/profilereader/profilecache.h51
-rw-r--r--tests/auto/profilereader/profilereader.pro16
-rw-r--r--tests/auto/profilereader/qtversionmanager.h45
-rwxr-xr-xtests/auto/profilereader/sync114
-rw-r--r--tests/manual/cppmodelmanager/codemodel/binder.cpp866
-rw-r--r--tests/manual/cppmodelmanager/codemodel/binder.h141
-rw-r--r--tests/manual/cppmodelmanager/codemodel/class_compiler.cpp91
-rw-r--r--tests/manual/cppmodelmanager/codemodel/class_compiler.h90
-rw-r--r--tests/manual/cppmodelmanager/codemodel/codemodel_finder.cpp99
-rw-r--r--tests/manual/cppmodelmanager/codemodel/codemodel_finder.h86
-rw-r--r--tests/manual/cppmodelmanager/codemodel/codemodelitems.cpp893
-rw-r--r--tests/manual/cppmodelmanager/codemodel/codemodelitems.h527
-rw-r--r--tests/manual/cppmodelmanager/codemodel/compiler_utils.cpp77
-rw-r--r--tests/manual/cppmodelmanager/codemodel/compiler_utils.h68
-rw-r--r--tests/manual/cppmodelmanager/codemodel/declarator_compiler.cpp168
-rw-r--r--tests/manual/cppmodelmanager/codemodel/declarator_compiler.h109
-rw-r--r--tests/manual/cppmodelmanager/codemodel/name_compiler.cpp150
-rw-r--r--tests/manual/cppmodelmanager/codemodel/name_compiler.h85
-rw-r--r--tests/manual/cppmodelmanager/codemodel/type_compiler.cpp169
-rw-r--r--tests/manual/cppmodelmanager/codemodel/type_compiler.h95
-rw-r--r--tests/manual/cppmodelmanager/cppcodemodel.cpp204
-rw-r--r--tests/manual/cppmodelmanager/cppcodemodel.h94
-rw-r--r--tests/manual/cppmodelmanager/cppcodemodelitems.cpp122
-rw-r--r--tests/manual/cppmodelmanager/cppcodemodelitems.h138
-rw-r--r--tests/manual/cppmodelmanager/cppcodemodelpart.cpp89
-rw-r--r--tests/manual/cppmodelmanager/cppcodemodelpart.h75
-rw-r--r--tests/manual/cppmodelmanager/cppmodelmanager.pro62
-rw-r--r--tests/manual/cppmodelmanager/cpppartparser.cpp204
-rw-r--r--tests/manual/cppmodelmanager/cpppartparser.h72
-rw-r--r--tests/manual/cppmodelmanager/dbcodemodel.cpp147
-rw-r--r--tests/manual/cppmodelmanager/dbcodemodel.h55
-rw-r--r--tests/manual/cppmodelmanager/main.cpp81
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-engine.cpp1117
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-engine.h232
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-internal.cpp68
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-internal.h69
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-macro-expander.cpp287
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-macro-expander.h105
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-macro.cpp62
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-macro.h78
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-scanner.cpp289
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-scanner.h119
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-stream.cpp266
-rw-r--r--tests/manual/cppmodelmanager/rpp/pp-stream.h118
-rw-r--r--tests/manual/cppmodelmanager/rpp/preprocessor.cpp161
-rw-r--r--tests/manual/cppmodelmanager/rpp/preprocessor.h119
-rw-r--r--tests/manual/cppmodelmanager/rpp/rpp.pri20
-rw-r--r--tests/manual/dockwidgets/dockwidgets.pro11
-rw-r--r--tests/manual/dockwidgets/main.cpp56
-rw-r--r--tests/manual/dockwidgets/mainwindow.cpp124
-rw-r--r--tests/manual/dockwidgets/mainwindow.h66
-rw-r--r--tests/manual/gdbdebugger/script/math.js6
-rw-r--r--tests/manual/gdbdebugger/script/script.pro4
-rw-r--r--tests/manual/gdbdebugger/simple/app.cpp827
-rw-r--r--tests/manual/gdbdebugger/simple/app/app.pro9
-rw-r--r--tests/manual/gdbdebugger/simple/plugin.cpp45
-rw-r--r--tests/manual/gdbdebugger/simple/plugin/plugin.pro18
-rw-r--r--tests/manual/gdbdebugger/simple/simple.pro4
-rw-r--r--tests/manual/gdbdebugger/spacy path/app with space.cpp419
-rw-r--r--tests/manual/gdbdebugger/spacy path/plugin with space.cpp13
-rw-r--r--tests/manual/gdbdebugger/spacy path/spacy app/spacy app.pro9
-rw-r--r--tests/manual/gdbdebugger/spacy path/spacy path.pro4
-rw-r--r--tests/manual/gdbdebugger/spacy path/spacy plugin/spacy plugin.pro18
-rw-r--r--tests/manual/gdbdebugger/spacy-file/app with space.cpp419
-rw-r--r--tests/manual/gdbdebugger/spacy-file/app/app.pro9
-rw-r--r--tests/manual/gdbdebugger/spacy-file/plugin with space.cpp13
-rw-r--r--tests/manual/gdbdebugger/spacy-file/plugin/plugin.pro18
-rw-r--r--tests/manual/gdbdebugger/spacy-file/spacy-file.pro4
-rw-r--r--tests/manual/progressmanager/find.pngbin0 -> 737 bytes
-rw-r--r--tests/manual/progressmanager/main.cpp42
-rw-r--r--tests/manual/progressmanager/roundprogress.cpp70
-rw-r--r--tests/manual/progressmanager/roundprogress.h118
-rw-r--r--tests/manual/progressmanager/roundprogress.pro15
-rw-r--r--tests/manual/progressmanager/roundprogress.ui55
-rw-r--r--tests/manual/proparser/main.cpp47
-rw-r--r--tests/manual/proparser/proparser.pro20
-rw-r--r--tests/manual/proparser/test.pro27
-rw-r--r--tests/qt4projectmanager/test1/a.cpp0
-rw-r--r--tests/qt4projectmanager/test1/a.h0
-rw-r--r--tests/qt4projectmanager/test1/test1.pro4
1675 files changed, 229938 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..0f3b119423
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,100 @@
+# This file is used to ignore files which are generated
+# ----------------------------------------------------------------------------
+
+*~
+*.a
+*.core
+*.moc
+*.o
+*.obj
+*.orig
+*.rej
+*.so
+*_pch.h.cpp
+*_resource.rc
+.#*
+*.*#
+core
+.qmake.cache
+tags
+.DS_Store
+*.debug
+Makefile*
+*.prl
+*.app
+moc_*.cpp
+ui_*.h
+qrc_*.cpp
+
+# xemacs temporary files
+*.flc
+
+# Vim temporary files
+.*.swp
+
+# Visual Studio generated files
+*.ib_pdb_index
+*.idb
+*.ilk
+*.pdb
+*.sln
+*.suo
+*.vcproj
+*vcproj.*.*.user
+*.ncb
+
+# MinGW generated files
+*.Debug
+*.Release
+
+# Directories to ignore
+# ---------------------
+
+debug
+examples/tools/plugandpaint/plugins
+include/*
+include/*/*
+lib/*
+plugins/*/*
+release
+tmp
+doc-build
+doc/html/*
+doc/qch
+doc-build
+.rcc
+.pch
+src/corelib/lib
+src/network/lib
+src/xml/lib/
+
+# Files copied by syncIde
+# -----------------------
+bin/Aggregation.dll
+bin/CodeModel.dll
+bin/ExtensionSystem.dll
+bin/QtConcurrent.dll
+bin/Utils.dll
+bin/qtcreator
+bin/qtcreator.exe
+shared/help/bookmarkdialog.ui
+shared/help/bookmarkmanager.cpp
+shared/help/bookmarkmanager.h
+shared/help/contentwindow.cpp
+shared/help/contentwindow.h
+shared/help/filternamedialog.cpp
+shared/help/filternamedialog.h
+shared/help/filternamedialog.ui
+shared/help/helpviewer.cpp
+shared/help/helpviewer.h
+shared/help/indexwindow.cpp
+shared/help/indexwindow.h
+shared/help/topicchooser.cpp
+shared/help/topicchooser.h
+shared/help/topicchooser.ui
+shared/proparser/abstractproitemvisitor.h
+shared/proparser/profileevaluator.cpp
+shared/proparser/profileevaluator.h
+shared/proparser/proitems.cpp
+shared/proparser/proitems.h
+shared/proparser/proparserutils.h
diff --git a/bin/designer/templates.xml b/bin/designer/templates.xml
new file mode 100644
index 0000000000..738e31cf47
--- /dev/null
+++ b/bin/designer/templates.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<designertemplates version="1.0.0">
+ <template name="Widget Form" description="Create new widget form" uifile="templates/Widget.ui">
+ </template>
+ <template name="Mainwindow Form" description="Create new mainwindow form" uifile="templates/Main_Window.ui">
+ </template>
+ <template name="Dialog without buttons" description="Create a dialog without buttons." uifile="templates/Dialog_without_Buttons.ui">
+ </template>
+ <template name="Dialog with buttons bottom" description="Create a dialog with the buttons at the bottom." uifile="templates/Dialog_with_Buttons_Bottom.ui">
+ </template>
+ <template name="Dialog with buttons right" description="Create a dialog with the buttons at the right." uifile="templates/Dialog_with_Buttons_Right.ui">
+ </template>
+</designertemplates>
diff --git a/bin/designer/templates/Dialog_with_Buttons_Bottom.ui b/bin/designer/templates/Dialog_with_Buttons_Bottom.ui
new file mode 100644
index 0000000000..18d31ab915
--- /dev/null
+++ b/bin/designer/templates/Dialog_with_Buttons_Bottom.ui
@@ -0,0 +1,71 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>30</x>
+ <y>240</y>
+ <width>341</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Dialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/bin/designer/templates/Dialog_with_Buttons_Right.ui b/bin/designer/templates/Dialog_with_Buttons_Right.ui
new file mode 100644
index 0000000000..703d594f4f
--- /dev/null
+++ b/bin/designer/templates/Dialog_with_Buttons_Right.ui
@@ -0,0 +1,71 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>290</x>
+ <y>20</y>
+ <width>81</width>
+ <height>241</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Dialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/bin/designer/templates/Dialog_without_Buttons.ui b/bin/designer/templates/Dialog_without_Buttons.ui
new file mode 100644
index 0000000000..1be629818c
--- /dev/null
+++ b/bin/designer/templates/Dialog_without_Buttons.ui
@@ -0,0 +1,18 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/bin/designer/templates/Main_Window.ui b/bin/designer/templates/Main_Window.ui
new file mode 100644
index 0000000000..e324db8292
--- /dev/null
+++ b/bin/designer/templates/Main_Window.ui
@@ -0,0 +1,27 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+ <property name="objectName" >
+ <string notr="true" >MainWindow</string>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>MainWindow</string>
+ </property>
+ <widget class="QMenuBar" name="menubar" />
+ <widget class="QWidget" name="centralwidget" />
+ <widget class="QStatusBar" name="statusbar" />
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <connections/>
+</ui>
diff --git a/bin/designer/templates/Widget.ui b/bin/designer/templates/Widget.ui
new file mode 100644
index 0000000000..d03fae3871
--- /dev/null
+++ b/bin/designer/templates/Widget.ui
@@ -0,0 +1,24 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Form</class>
+ <widget class="QWidget" name="Form" >
+ <property name="objectName" >
+ <string notr="true" >Form</string>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <connections/>
+</ui>
diff --git a/bin/gdbmacros/GPL_EXCEPTION.TXT b/bin/gdbmacros/GPL_EXCEPTION.TXT
new file mode 100644
index 0000000000..8fa94329fe
--- /dev/null
+++ b/bin/gdbmacros/GPL_EXCEPTION.TXT
@@ -0,0 +1,87 @@
+Nokia Corporation Qt GPL Exception version 1.3
+==============================================
+
+Additional rights granted beyond the GPL (the "Exception").
+
+As a special exception to the terms and conditions of GPL version 2.0 or GPL
+version 3.0, Nokia Corporation hereby grants you the rights described below,
+provided you agree to the terms and conditions in this Exception, including its
+obligations and restrictions on use.
+
+Nothing in this Exception gives you or anyone else the right to change the
+licensing terms of the Qt Open Source Edition.
+
+Below, "Licensed Software" shall refer to the software licensed under the GPL
+version 2.0 or GPL version 3.0 and this exception.
+
+1) The right to use open source licenses not compatible with the GNU
+General Public License version 2.0 or GNU General Public License version
+3.0: You may link software (hereafter referred to as "Your Software")
+against the Licensed Software and/or distribute binaries of Your Software
+linked against the Licensed Software, provided that:
+
+A) Your Software is licensed under one of the following licenses:
+
+
+License name Version(s)/Copyright Date
+Academic Free License 2.0, 2.1, 3.0
+Apache Software License 1.0 or 1.1
+Apache License 2.0
+Apple Public Source License 2.0
+Artistic license (as set forth in the addendum file)
+BSD license "July 22 1999"
+Common Development and Distribution
+ License (CDDL) 1.0
+Common Public License 1.0
+Eclipse Public License 1.0
+GNU Library or "Lesser"
+General Public License (LGPL) 2.0, 2.1, 3.0
+Jabber Open Source License 1.0
+MIT License (as set forth in the addendum file)
+Mozilla Public License (MPL) 1.0 or 1.1
+Open Software License 2.0, 3.0
+OpenSSL license (with original
+SSLeay license) "2003" ("1998")
+PHP License 3.0
+Python license (CNRI Python License) (as set forth in the addendum file)
+Python Software Foundation License 2.1.1
+Q Public License 1.0
+Sleepycat License "1999"
+W3C License "2001"
+X11 License X11R6.6
+Zlib/libpng License (as set forth in the addendum file)
+Zope Public License 2.0, 2.1
+
+
+(Licenses without a specific version number or date are reproduced
+in the file GPL_Exception_Addendum.txt in your source package).
+
+and
+
+B) You must, on request, make a complete package including the complete
+source code of Your Software (as defined in the GNU General Public License
+version 2, section 3, but excluding anything excluded by the special
+exception in the same section) available to Nokia Corporation under the
+same license as that granted to other recipients of the source code of Your
+Software.
+
+and
+
+C) Your or any other contributor's rights to:
+
+ i) distribute the source code of Your Software to anyone for any purpose;
+
+ and
+
+ ii) publicly discuss the development project for Your Software and its
+ goals in any form and in any forum are not prohibited by any legal
+ instrument, including but not limited to contracts, non-disclosure
+ agreements, and employee contracts.
+
+
+2) The right to link non-open source applications with pre-installed versions of
+the Licensed Software: You may link applications with binary pre-installed
+versions of the Licensed Software, provided that such applications have been
+developed and are deployed in accordance with the terms and conditions of the Qt
+Commercial License Agreement.
+
diff --git a/bin/gdbmacros/gdbmacros.cpp b/bin/gdbmacros/gdbmacros.cpp
new file mode 100644
index 0000000000..0d6575db5b
--- /dev/null
+++ b/bin/gdbmacros/gdbmacros.cpp
@@ -0,0 +1,2446 @@
+/****************************************************************************
+** This file is part of Qt Creator
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).*
+**
+** Contact: Qt Software Information (qt-info@nokia.com)**
+**
+** No Commercial Usage
+** This file contains pre-release code and may only be used for evaluation
+** and testing purposes. It may not be used for commercial development. You
+** may use this file in accordance with the terms and conditions contained in
+** the either Technology Preview License Agreement or the Beta Release
+** License Agreement.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html. In addition, as a special
+** exception, Nokia gives you certain additional rights. These rights are
+** described in the Nokia Qt GPL Exception version 1.2, included in the file
+** GPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact Nokia
+** at qt-info@nokia.com
+****************************************************************************/
+
+// {[(
+
+#include <qglobal.h>
+
+// this relies on contents copied from qobject_p.h
+#define PRIVATE_OBJECT_ALLOWED 1
+
+#include <QDateTime>
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QHash>
+#include <QLocale>
+#include <QMap>
+#include <QMetaObject>
+#include <QMetaProperty>
+#include <QModelIndex>
+#include <QObject>
+#include <QPointer>
+#include <QString>
+#include <QTextCodec>
+#include <QVector>
+
+
+/*!
+ \class QDumper
+ \brief Helper class for producing "nice" output in Qt Creator's debugger.
+
+ \internal
+
+ The whole "custom dumper" implementation is currently far less modular
+ than it could be. But as the code is still in a flux, making it nicer
+ from a pure archtectural point of view seems still be a waste of resources.
+
+ Some hints:
+
+ New dumpers for non-templated classes should be mentioned in
+ \c{qDumpObjectData440()} in the \c{protocolVersion == 1} branch.
+
+ Templated classes need extra support on the IDE level
+ (see plugins/debugger/gdbengine.cpp) and should not be mentiond in
+ \c{qDumpObjectData440()}.
+
+ In any case, dumper processesing should end up in
+ \c{handleProtocolVersion2and3()} and needs an entry in the bis switch there.
+
+ Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)}
+ function. At the bare minimum it should contain something like:
+
+
+ \c{
+ const Foo &foo = *reinterpret_cast<const Foo *>(d.data);
+
+ P(d, "value", ...);
+ P(d, "type", "Foo");
+ P(d, "numchild", "0");
+ }
+
+
+ 'P(d, name, value)' roughly expands to:
+ d << (name) << "=\"" << value << "\"";
+
+ Useful (i.e. understood by the IDE) names include:
+
+ \list
+ \o "name" shows up in the first column in the Locals&Watchers view.
+ \o "value" shows up in the second column.
+ \o "valueencoded" should be set to "1" if the value is base64 encoded.
+ Always base64-encode values that might use unprintable or otherwise
+ "confuse" the protocol (like spaces and quotes). [A-Za-z0-9] is "safe".
+ A value of "3" is used for base64-encoded UCS4, "2" denotes
+ base64-encoded UTF16.
+ \o "numchild" return the number of children in the view. Effectively, only
+ 0 and != 0 will be used, so don't try too hard to get the number right.
+ \endlist
+
+ If the current item has children, it might be queried to produce information
+ about thes children. In this case the dumper should use something like
+
+ \c{
+ if (d.dumpChildren) {
+ d << ",children=[";
+ }
+
+ */
+
+int qtGhVersion = QT_VERSION;
+
+#ifdef QT_GUI_LIB
+# include <QPixmap>
+# include <QImage>
+#endif
+
+#include <string>
+#include <vector>
+
+#include <ctype.h>
+#include <stdio.h>
+
+//#include <sys/types.h>
+
+#ifdef Q_OS_WIN
+# include <windows.h>
+#endif
+
+#undef NS
+#ifdef QT_NAMESPACE
+# define STRINGIFY0(s) #s
+# define STRINGIFY1(s) STRINGIFY0(s)
+# define NS STRINGIFY1(QT_NAMESPACE) "::"
+# define NSX "'" STRINGIFY1(QT_NAMESPACE) "::"
+# define NSY "'"
+#else
+# define NS ""
+# define NSX ""
+# define NSY ""
+#endif
+
+
+#if PRIVATE_OBJECT_ALLOWED
+
+#if defined(QT_BEGIN_NAMESPACE)
+QT_BEGIN_NAMESPACE
+#endif
+
+class QVariant;
+class QThreadData;
+class QObjectConnectionListVector;
+
+class QObjectPrivate : public QObjectData
+{
+ Q_DECLARE_PUBLIC(QObject)
+
+public:
+ QObjectPrivate() {}
+ virtual ~QObjectPrivate() {}
+
+ // preserve binary compatibility with code compiled without Qt 3 support
+ QList<QObject *> pendingChildInsertedEvents; // unused
+
+ // id of the thread that owns the object
+ QThreadData *threadData;
+ void moveToThread_helper();
+ void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
+ void _q_reregisterTimers(void *pointer);
+
+ struct Sender
+ {
+ QObject *sender;
+ int signal;
+ int ref;
+ };
+
+ Sender *currentSender; // object currently activating the object
+ QObject *currentChildBeingDeleted;
+
+ QList<QPointer<QObject> > eventFilters;
+
+ struct ExtraData
+ {
+#ifndef QT_NO_USERDATA
+ QVector<QObjectUserData *> userData;
+#endif
+ QList<QByteArray> propertyNames;
+ QList<QVariant> propertyValues;
+ };
+ ExtraData *extraData;
+ mutable quint32 connectedSignals;
+
+ QString objectName;
+
+ // Note: you must hold the signalSlotLock() before accessing the lists below or calling the functions
+ struct Connection
+ {
+ QObject *receiver;
+ int method;
+ uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
+ QBasicAtomicPointer<int> argumentTypes;
+ };
+ typedef QList<Connection> ConnectionList;
+
+ QObjectConnectionListVector *connectionLists;
+ QList<Sender> senders;
+ int *deleteWatch;
+
+ static QObjectPrivate *get(QObject *o) { return o->d_func(); }
+};
+
+#if defined(QT_BEGIN_NAMESPACE)
+QT_END_NAMESPACE
+#endif
+
+#endif // PRIVATE_OBJECT_ALLOWED
+
+
+// this can be mangled typenames of nested templates, each char-by-char
+// comma-separated integer list
+static char qDumpInBuffer[10000];
+static char qDumpBuffer[1000];
+
+namespace {
+
+static bool isPointerType(const QByteArray &type)
+{
+ return type.endsWith("*") || type.endsWith("* const");
+}
+
+static QByteArray stripPointerType(QByteArray type)
+{
+ if (type.endsWith("*"))
+ type.chop(1);
+ if (type.endsWith("* const"))
+ type.chop(7);
+ if (type.endsWith(' '))
+ type.chop(1);
+ return type;
+}
+
+// This is used to abort evaluation of custom data dumpers in a "coordinated"
+// way. Abortion will happen anyway when we try to access a non-initialized
+// non-trivial object, so there is no way to prevent this from occuring at all
+// conceptionally. Gdb will catch SIGSEGV and return to the calling frame.
+// This is just fine provided we only _read_ memory in the custom handlers
+// below.
+
+volatile int qProvokeSegFaultHelper;
+
+static const void *addOffset(const void *p, int offset)
+{
+ return offset + reinterpret_cast<const char *>(p);
+}
+
+static const void *skipvtable(const void *p)
+{
+ return sizeof(void*) + reinterpret_cast<const char *>(p);
+}
+
+static const void *deref(const void *p)
+{
+ return *reinterpret_cast<const char* const*>(p);
+}
+
+static const void *dfunc(const void *p)
+{
+ return deref(skipvtable(p));
+}
+
+static bool isEqual(const char *s, const char *t)
+{
+ return qstrcmp(s, t) == 0;
+}
+
+static bool startsWith(const char *s, const char *t)
+{
+ return qstrncmp(s, t, strlen(t)) == 0;
+}
+
+// provoke segfault when address is not readable
+#define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0)
+#define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
+// provoke segfault unconditionally
+#define qCheck(b) do { if (!b) qProvokeSegFaultHelper = *(char*)0; } while (0)
+
+const char *stripNamespace(const char *type)
+{
+ static const size_t nslen = strlen(NS);
+ return startsWith(type, NS) ? type + nslen : type;
+}
+
+static bool isSimpleType(const char *type)
+{
+ switch (type[0]) {
+ case 'c':
+ return isEqual(type, "char");
+ case 'd':
+ return isEqual(type, "double");
+ case 'f':
+ return isEqual(type, "float");
+ case 'i':
+ return isEqual(type, "int");
+ case 'l':
+ return isEqual(type, "long") || startsWith(type, "long ");
+ case 's':
+ return isEqual(type, "short") || isEqual(type, "signed")
+ || startsWith(type, "signed ");
+ case 'u':
+ return isEqual(type, "unsigned") || startsWith(type, "unsigned ");
+ }
+ return false;
+}
+
+static bool isShortKey(const char *type)
+{
+ return isSimpleType(type) || isEqual(type, "QString");
+}
+
+static bool isMovableType(const char *type)
+{
+ if (isPointerType(type))
+ return true;
+
+ if (isSimpleType(type))
+ return true;
+
+ type = stripNamespace(type);
+
+ switch (type[1]) {
+ case 'B':
+ return isEqual(type, "QBrush")
+ || isEqual(type, "QBitArray")
+ || isEqual(type, "QByteArray") ;
+ case 'C':
+ return isEqual(type, "QCustomTypeInfo");
+ case 'D':
+ return isEqual(type, "QDate")
+ || isEqual(type, "QDateTime");
+ case 'F':
+ return isEqual(type, "QFileInfo")
+ || isEqual(type, "QFixed")
+ || isEqual(type, "QFixedPoint")
+ || isEqual(type, "QFixedSize");
+ case 'H':
+ return isEqual(type, "QHashDummyValue");
+ case 'I':
+ return isEqual(type, "QIcon")
+ || isEqual(type, "QImage");
+ case 'L':
+ return isEqual(type, "QLine")
+ || isEqual(type, "QLineF")
+ || isEqual(type, "QLocal");
+ case 'M':
+ return isEqual(type, "QMatrix")
+ || isEqual(type, "QModelIndex");
+ case 'P':
+ return isEqual(type, "QPoint")
+ || isEqual(type, "QPointF")
+ || isEqual(type, "QPen")
+ || isEqual(type, "QPersistentModelIndex");
+ case 'R':
+ return isEqual(type, "QResourceRoot")
+ || isEqual(type, "QRect")
+ || isEqual(type, "QRectF")
+ || isEqual(type, "QRegExp");
+ case 'S':
+ return isEqual(type, "QSize")
+ || isEqual(type, "QSizeF")
+ || isEqual(type, "QString");
+ case 'T':
+ return isEqual(type, "QTime")
+ || isEqual(type, "QTextBlock");
+ case 'U':
+ return isEqual(type, "QUrl");
+ case 'V':
+ return isEqual(type, "QVariant");
+ case 'X':
+ return isEqual(type, "QXmlStreamAttribute")
+ || isEqual(type, "QXmlStreamNamespaceDeclaration")
+ || isEqual(type, "QXmlStreamNotationDeclaration")
+ || isEqual(type, "QXmlStreamEntityDeclaration");
+ }
+ return false;
+}
+
+struct QDumper
+{
+ explicit QDumper();
+ ~QDumper();
+ void flush();
+ void checkFill();
+ QDumper &operator<<(long c);
+ QDumper &operator<<(int i);
+ QDumper &operator<<(double d);
+ QDumper &operator<<(float d);
+ QDumper &operator<<(unsigned long c);
+ QDumper &operator<<(unsigned int i);
+ QDumper &operator<<(const void *p);
+ QDumper &operator<<(qulonglong c);
+ void put(char c);
+ void addCommaIfNeeded();
+ void putBase64Encoded(const char *buf, int n);
+ QDumper &operator<<(const char *str);
+ QDumper &operator<<(const QByteArray &ba);
+ QDumper &operator<<(const QString &str);
+ void disarm();
+
+ void beginHash(); // start of data hash output
+ void endHash(); // start of data hash output
+
+ void write(const void *buf, int len); // raw write to stdout
+
+ // the dumper arguments
+ int protocolVersion; // dumper protocol version
+ int token; // some token to show on success
+ const char *outertype; // object type
+ const char *iname; // object name used for display
+ const char *exp; // object expression
+ const char *innertype; // 'inner type' for class templates
+ const void *data; // pointer to raw data
+ bool dumpChildren; // do we want to see children?
+
+ // handling of nested templates
+ void setupTemplateParameters();
+ enum { maxTemplateParameters = 10 };
+ const char *templateParameters[maxTemplateParameters + 1];
+ int templateParametersCount;
+
+ // internal state
+ bool success; // are we finished?
+ int pos;
+
+ int extraInt[4];
+};
+
+
+QDumper::QDumper()
+{
+ success = false;
+ pos = 0;
+}
+
+QDumper::~QDumper()
+{
+ flush();
+
+ char buf[30];
+ int len = qsnprintf(buf, sizeof(buf) - 1, "%d^done\n", token);
+ write(buf, len);
+}
+
+void QDumper::write(const void *buf, int len)
+{
+ ::fwrite(buf, len, 1, stdout);
+ ::fflush(stdout);
+}
+
+void QDumper::flush()
+{
+ if (pos != 0) {
+ char buf[30];
+ int len = qsnprintf(buf, sizeof(buf) - 1, "%d#%d,", token, pos);
+ write(buf, len);
+ write(qDumpBuffer, pos);
+ write("\n", 1);
+ pos = 0;
+ }
+}
+
+void QDumper::setupTemplateParameters()
+{
+ char *s = const_cast<char *>(innertype);
+
+ templateParametersCount = 1;
+ templateParameters[0] = s;
+ for (int i = 1; i != maxTemplateParameters + 1; ++i)
+ templateParameters[i] = 0;
+
+ while (*s) {
+ while (*s && *s != '@')
+ ++s;
+ if (*s) {
+ *s = '\0';
+ ++s;
+ templateParameters[templateParametersCount++] = s;
+ }
+ }
+}
+
+QDumper &QDumper::operator<<(unsigned long long c)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%llu", c);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(unsigned long c)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%lu", c);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(float d)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%f", d);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(double d)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%f", d);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(unsigned int i)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%u", i);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(long c)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%ld", c);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(int i)
+{
+ checkFill();
+ pos += sprintf(qDumpBuffer + pos, "%d", i);
+ return *this;
+}
+
+QDumper &QDumper::operator<<(const void *p)
+{
+ static char buf[100];
+ if (p) {
+ sprintf(buf, "%p", p);
+ // we get a '0x' prefix only on some implementations.
+ // if it isn't there, write it out manually.
+ if (buf[1] != 'x') {
+ put('0');
+ put('x');
+ }
+ *this << buf;
+ } else {
+ *this << "<null>";
+ }
+ return *this;
+}
+
+void QDumper::checkFill()
+{
+ if (pos >= int(sizeof(qDumpBuffer)) - 100)
+ flush();
+}
+
+void QDumper::put(char c)
+{
+ checkFill();
+ qDumpBuffer[pos++] = c;
+}
+
+void QDumper::addCommaIfNeeded()
+{
+ if (pos == 0)
+ return;
+ char c = qDumpBuffer[pos - 1];
+ if (c == '}' || c == '"' || c == ']')
+ put(',');
+}
+
+void QDumper::putBase64Encoded(const char *buf, int n)
+{
+ const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+ "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
+ const char padchar = '=';
+ int padlen = 0;
+
+ //int tmpsize = ((n * 4) / 3) + 3;
+
+ int i = 0;
+ while (i < n) {
+ int chunk = 0;
+ chunk |= int(uchar(buf[i++])) << 16;
+ if (i == n) {
+ padlen = 2;
+ } else {
+ chunk |= int(uchar(buf[i++])) << 8;
+ if (i == n)
+ padlen = 1;
+ else
+ chunk |= int(uchar(buf[i++]));
+ }
+
+ int j = (chunk & 0x00fc0000) >> 18;
+ int k = (chunk & 0x0003f000) >> 12;
+ int l = (chunk & 0x00000fc0) >> 6;
+ int m = (chunk & 0x0000003f);
+ put(alphabet[j]);
+ put(alphabet[k]);
+ put(padlen > 1 ? padchar : alphabet[l]);
+ put(padlen > 0 ? padchar : alphabet[m]);
+ }
+}
+
+QDumper &QDumper::operator<<(const char *str)
+{
+ if (!str)
+ return *this << "<null>";
+ while (*str)
+ put(*(str++));
+ return *this;
+}
+
+QDumper &QDumper::operator<<(const QByteArray &ba)
+{
+ putBase64Encoded(ba.constData(), ba.size());
+ return *this;
+}
+
+QDumper &QDumper::operator<<(const QString &str)
+{
+ QByteArray ba = str.toUtf8();
+ putBase64Encoded(ba.constData(), ba.size());
+ return *this;
+}
+
+void QDumper::disarm()
+{
+ flush();
+ success = true;
+}
+
+void QDumper::beginHash()
+{
+ addCommaIfNeeded();
+ put('{');
+}
+
+void QDumper::endHash()
+{
+ put('}');
+}
+
+
+//
+// Some helpers to keep the dumper code short
+//
+
+// dump property=value pair
+#undef P
+#define P(dumper,name,value) \
+ do { \
+ dumper.addCommaIfNeeded(); \
+ dumper << (name) << "=\"" << value << "\""; \
+ } while (0)
+
+// simple string property
+#undef S
+#define S(dumper, name, value) \
+ dumper.beginHash(); \
+ P(dumper, "name", name); \
+ P(dumper, "value", value); \
+ P(dumper, "type", NS"QString"); \
+ P(dumper, "numchild", "0"); \
+ P(dumper, "valueencoded", "1"); \
+ dumper.endHash();
+
+// simple integer property
+#undef I
+#define I(dumper, name, value) \
+ dumper.beginHash(); \
+ P(dumper, "name", name); \
+ P(dumper, "value", value); \
+ P(dumper, "type", "int"); \
+ P(dumper, "numchild", "0"); \
+ dumper.endHash();
+
+// simple boolean property
+#undef BL
+#define BL(dumper, name, value) \
+ dumper.beginHash(); \
+ P(dumper, "name", name); \
+ P(dumper, "value", (value ? "true" : "false")); \
+ P(dumper, "type", "bool"); \
+ P(dumper, "numchild", "0"); \
+ dumper.endHash();
+
+
+// a single QChar
+#undef QC
+#define QC(dumper, name, value) \
+ dumper.beginHash(); \
+ P(dumper, "name", name); \
+ P(dumper, "value", QString(QLatin1String("'%1' (%2, 0x%3)")) \
+ .arg(value).arg(value.unicode()).arg(value.unicode(), 0, 16)); \
+ P(dumper, "valueencoded", "1"); \
+ P(dumper, "type", NS"QChar"); \
+ P(dumper, "numchild", "0"); \
+ dumper.endHash();
+
+#undef TT
+#define TT(type, value) \
+ "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
+
+static void qDumpUnknown(QDumper &d)
+{
+ P(d, "iname", d.iname);
+ P(d, "addr", d.data);
+ P(d, "value", "<internal error>");
+ P(d, "type", d.outertype);
+ P(d, "numchild", "0");
+ d.disarm();
+}
+
+static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
+ const char *key = "value")
+{
+ type = stripNamespace(type);
+ switch (type[1]) {
+ case 'l':
+ if (isEqual(type, "float"))
+ P(d, key, *(float*)addr);
+ return;
+ case 'n':
+ if (isEqual(type, "int"))
+ P(d, key, *(int*)addr);
+ else if (isEqual(type, "unsigned"))
+ P(d, key, *(unsigned int*)addr);
+ else if (isEqual(type, "unsigned int"))
+ P(d, key, *(unsigned int*)addr);
+ else if (isEqual(type, "unsigned long"))
+ P(d, key, *(unsigned long*)addr);
+ else if (isEqual(type, "unsigned long long"))
+ P(d, key, *(qulonglong*)addr);
+ return;
+ case 'o':
+ if (isEqual(type, "bool"))
+ switch (*(bool*)addr) {
+ case 0: P(d, key, "false"); break;
+ case 1: P(d, key, "true"); break;
+ default: P(d, key, *(bool*)addr); break;
+ }
+ else if (isEqual(type, "double"))
+ P(d, key, *(double*)addr);
+ else if (isEqual(type, "long"))
+ P(d, key, *(long*)addr);
+ else if (isEqual(type, "long long"))
+ P(d, key, *(qulonglong*)addr);
+ return;
+ case 'B':
+ if (isEqual(type, "QByteArray")) {
+ d << key << "encoded=\"1\",";
+ P(d, key, *(QByteArray*)addr);
+ }
+ return;
+ case 'L':
+ if (startsWith(type, "QList<")) {
+ const QListData *ldata = reinterpret_cast<const QListData*>(addr);
+ P(d, "value", "<" << ldata->size() << " items>");
+ P(d, "valuedisabled", "true");
+ P(d, "numchild", ldata->size());
+ }
+ return;
+ case 'O':
+ if (isEqual(type, "QObject *")) {
+ if (addr) {
+ const QObject *ob = reinterpret_cast<const QObject *>(addr);
+ P(d, "addr", ob);
+ P(d, "value", ob->objectName());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QObject");
+ P(d, "displayedtype", ob->metaObject()->className());
+ } else {
+ P(d, "value", "0x0");
+ P(d, "type", NS"QObject *");
+ }
+ }
+ return;
+ case 'S':
+ if (isEqual(type, "QString")) {
+ d << key << "encoded=\"1\",";
+ P(d, key, *(QString*)addr);
+ }
+ return;
+ default:
+ return;
+ }
+}
+
+static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
+{
+ P(d, "addr", addr);
+ P(d, "type", type);
+
+ if (!type[0])
+ return;
+
+ qDumpInnerValueHelper(d, type, addr);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void qDumpQByteArray(QDumper &d)
+{
+ const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
+
+ if (!ba.isEmpty()) {
+ qCheckAccess(ba.constData());
+ qCheckAccess(ba.constData() + ba.size());
+ }
+
+ if (ba.size() <= 100)
+ P(d, "value", ba);
+ else
+ P(d, "value", ba.left(100) << " <size: " << ba.size() << ", cut...>");
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QByteArray");
+ P(d, "numchild", ba.size());
+ P(d, "childtype", "char");
+ P(d, "childnumchild", "0");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ char buf[20];
+ for (int i = 0; i != ba.size(); ++i) {
+ unsigned char c = ba.at(i);
+ unsigned char u = isprint(c) && c != '"' ? c : '?';
+ sprintf(buf, "%02x (%u '%c')", c, c, u);
+ d.beginHash();
+ P(d, "name", "[" << i << "]");
+ P(d, "value", buf);
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQDateTime(QDumper &d)
+{
+#ifdef QT_NO_DATESTRING
+ qDumpUnknown(d);
+#else
+ const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
+ if (date.isNull()) {
+ P(d, "value", "(null)");
+ } else {
+ P(d, "value", date.toString());
+ P(d, "valueencoded", "1");
+ }
+ P(d, "type", NS"QDateTime");
+ P(d, "numchild", "3");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ BL(d, "isNull", date.isNull());
+ I(d, "toTime_t", (long)date.toTime_t());
+ S(d, "toString", date.toString());
+ S(d, "toString_(ISO)", date.toString(Qt::ISODate));
+ S(d, "toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
+ S(d, "toString_(Locale)", date.toString(Qt::LocaleDate));
+ S(d, "toString", date.toString());
+
+ #if 0
+ d.beginHash();
+ P(d, "name", "toUTC");
+ P(d, "exp", "(("NSX"QDateTime"NSY"*)" << d.data << ")"
+ "->toTimeSpec('"NS"Qt::UTC')");
+ P(d, "type", NS"QDateTime");
+ P(d, "numchild", "1");
+ d.endHash();
+ #endif
+
+ #if 0
+ d.beginHash();
+ P(d, "name", "toLocalTime");
+ P(d, "exp", "(("NSX"QDateTime"NSY"*)" << d.data << ")"
+ "->toTimeSpec('"NS"Qt::LocalTime')");
+ P(d, "type", NS"QDateTime");
+ P(d, "numchild", "1");
+ d.endHash();
+ #endif
+
+ d << "]";
+ }
+ d.disarm();
+#endif // ifdef QT_NO_DATESTRING
+}
+
+static void qDumpQDir(QDumper &d)
+{
+ const QDir &dir = *reinterpret_cast<const QDir *>(d.data);
+ P(d, "value", dir.path());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QDir");
+ P(d, "numchild", "3");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ S(d, "absolutePath", dir.absolutePath());
+ S(d, "canonicalPath", dir.canonicalPath());
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQFile(QDumper &d)
+{
+ const QFile &file = *reinterpret_cast<const QFile *>(d.data);
+ P(d, "value", file.fileName());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QFile");
+ P(d, "numchild", "2");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ S(d, "fileName", file.fileName());
+ BL(d, "exists", file.exists());
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQFileInfo(QDumper &d)
+{
+ const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data);
+ P(d, "value", info.filePath());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QFileInfo");
+ P(d, "numchild", "3");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ S(d, "absolutePath", info.absolutePath());
+ S(d, "absoluteFilePath", info.absoluteFilePath());
+ S(d, "canonicalPath", info.canonicalPath());
+ S(d, "canonicalFilePath", info.canonicalFilePath());
+ S(d, "completeBaseName", info.completeBaseName());
+ S(d, "completeSuffix", info.completeSuffix());
+ S(d, "baseName", info.baseName());
+#ifdef Q_OS_MACX
+ BL(d, "isBundle", info.isBundle());
+ S(d, "bundleName", info.bundleName());
+#endif
+ S(d, "completeSuffix", info.completeSuffix());
+ S(d, "fileName", info.fileName());
+ S(d, "filePath", info.filePath());
+ S(d, "group", info.group());
+ S(d, "owner", info.owner());
+ S(d, "path", info.path());
+
+ I(d, "groupid", (long)info.groupId());
+ I(d, "ownerid", (long)info.ownerId());
+ //QFile::Permissions permissions () const
+ I(d, "permissions", info.permissions());
+
+ //QDir absoluteDir () const
+ //QDir dir () const
+
+ BL(d, "caching", info.caching());
+ BL(d, "exists", info.exists());
+ BL(d, "isAbsolute", info.isAbsolute());
+ BL(d, "isDir", info.isDir());
+ BL(d, "isExecutable", info.isExecutable());
+ BL(d, "isFile", info.isFile());
+ BL(d, "isHidden", info.isHidden());
+ BL(d, "isReadable", info.isReadable());
+ BL(d, "isRelative", info.isRelative());
+ BL(d, "isRoot", info.isRoot());
+ BL(d, "isSymLink", info.isSymLink());
+ BL(d, "isWritable", info.isWritable());
+
+ d.beginHash();
+ P(d, "name", "created");
+ P(d, "value", info.created().toString());
+ P(d, "valueencoded", "1");
+ P(d, "exp", "(("NSX"QFileInfo"NSY"*)" << d.data << ")->created()");
+ P(d, "type", NS"QDateTime");
+ P(d, "numchild", "1");
+ d.endHash();
+
+ d.beginHash();
+ P(d, "name", "lastModified");
+ P(d, "value", info.lastModified().toString());
+ P(d, "valueencoded", "1");
+ P(d, "exp", "(("NSX"QFileInfo"NSY"*)" << d.data << ")->lastModified()");
+ P(d, "type", NS"QDateTime");
+ P(d, "numchild", "1");
+ d.endHash();
+
+ d.beginHash();
+ P(d, "name", "lastRead");
+ P(d, "value", info.lastRead().toString());
+ P(d, "valueencoded", "1");
+ P(d, "exp", "(("NSX"QFileInfo"NSY"*)" << d.data << ")->lastRead()");
+ P(d, "type", NS"QDateTime");
+ P(d, "numchild", "1");
+ d.endHash();
+
+ d << "]";
+ }
+ d.disarm();
+}
+
+bool isOptimizedIntKey(const char *keyType)
+{
+ return isEqual(keyType, "int")
+#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ || isEqual(keyType, "short")
+ || isEqual(keyType, "ushort")
+#endif
+ || isEqual(keyType, "uint");
+}
+
+int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned valueSize)
+{
+ // int-key optimization, small value
+ struct NodeOS { void *next; uint k; uint v; } nodeOS;
+ // int-key optimiatzion, large value
+ struct NodeOL { void *next; uint k; void *v; } nodeOL;
+ // no optimization, small value
+ struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS;
+ // no optimization, large value
+ struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL;
+ // complex key
+ struct NodeL { void *next; uint h; void *k; void *v; } nodeL;
+
+ if (forKey) {
+ // offsetof(...,...) not yet in Standard C++
+ const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS );
+ const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL );
+ const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS );
+ const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL );
+ const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL );
+ if (optimizedIntKey)
+ return valueSize > sizeof(int) ? nodeOLk : nodeOSk;
+ if (keySize > sizeof(int))
+ return nodeLk;
+ return valueSize > sizeof(int) ? nodeNLk : nodeNSk;
+ } else {
+ const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS );
+ const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL );
+ const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS );
+ const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL );
+ const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL );
+ if (optimizedIntKey)
+ return valueSize > sizeof(int) ? nodeOLv : nodeOSv;
+ if (keySize > sizeof(int))
+ return nodeLv;
+ return valueSize > sizeof(int) ? nodeNLv : nodeNSv;
+ }
+}
+
+
+static void qDumpQHash(QDumper &d)
+{
+ QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
+ const char *keyType = d.templateParameters[0];
+ const char *valueType = d.templateParameters[1];
+
+ qCheckPointer(h->fakeNext);
+ qCheckPointer(h->buckets);
+
+ unsigned keySize = d.extraInt[0];
+ unsigned valueSize = d.extraInt[1];
+
+ int n = h->size;
+
+ if (n < 0)
+ qCheck(false);
+ if (n > 0) {
+ qCheckPointer(h->fakeNext);
+ qCheckPointer(*h->buckets);
+ }
+
+ P(d, "value", "<" << n << " items>");
+ P(d, "numchild", n);
+ if (d.dumpChildren) {
+ if (n > 1000)
+ n = 1000;
+ bool simpleKey = isShortKey(keyType);
+ bool simpleValue = isShortKey(valueType);
+ bool opt = isOptimizedIntKey(keyType);
+ int keyOffset = hashOffset(opt, true, keySize, valueSize);
+ int valueOffset = hashOffset(opt, false, keySize, valueSize);
+
+ P(d, "extra", "simplekey: " << simpleKey << " simpleValue: " << simpleValue
+ << " keySize: " << keyOffset << " valueOffset: " << valueOffset
+ << " opt: " << opt);
+
+ QHashData::Node *node = h->firstNode();
+ QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
+ int i = 0;
+
+ d << ",children=[";
+ while (node != end) {
+ d.beginHash();
+ if (simpleKey) {
+ qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "name");
+ P(d, "nameisindex", "1");
+ if (simpleValue)
+ qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
+ P(d, "type", valueType);
+ P(d, "addr", addOffset(node, valueOffset));
+ } else {
+ P(d, "name", "[" << i << "]");
+ //P(d, "exp", "*(char*)" << node);
+ P(d, "exp", "*('"NS"QHashNode<" << keyType << "," << valueType << " >'*)" << node);
+ P(d, "type", "'"NS"QHashNode<" << keyType << "," << valueType << " >'");
+ }
+ d.endHash();
+ ++i;
+ node = QHashData::nextNode(node);
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQHashNode(QDumper &d)
+{
+ const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
+ const char *keyType = d.templateParameters[0];
+ const char *valueType = d.templateParameters[1];
+
+ P(d, "value", "");
+ P(d, "numchild", 2);
+ if (d.dumpChildren) {
+ unsigned keySize = d.extraInt[0];
+ unsigned valueSize = d.extraInt[1];
+ bool opt = isOptimizedIntKey(keyType);
+ int keyOffset = hashOffset(opt, true, keySize, valueSize);
+ int valueOffset = hashOffset(opt, false, keySize, valueSize);
+
+ // there is a hash specialization in cast the key are integers or shorts
+ d << ",children=[";
+ d.beginHash();
+ P(d, "name", "key");
+ P(d, "type", keyType);
+ P(d, "addr", addOffset(h, keyOffset));
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "value");
+ P(d, "type", valueType);
+ P(d, "addr", addOffset(h, valueOffset));
+ d.endHash();
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQImage(QDumper &d)
+{
+#ifdef QT_GUI_LIB
+ const QImage &im = *reinterpret_cast<const QImage *>(d.data);
+ P(d, "value", "(" << im.width() << "x" << im.height() << ")");
+ P(d, "type", NS"QImage");
+ P(d, "numchild", "0");
+ d.disarm();
+#else
+ Q_UNUSED(d);
+#endif
+}
+
+static void qDumpQList(QDumper &d)
+{
+ // This uses the knowledge that QList<T> has only a single member
+ // of type union { QListData p; QListData::Data *d; };
+ const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
+ const QListData::Data *pdata =
+ *reinterpret_cast<const QListData::Data* const*>(d.data);
+ int nn = ldata.size();
+ if (nn < 0)
+ qCheck(false);
+ if (nn > 0) {
+ qCheckAccess(ldata.d->array);
+ //qCheckAccess(ldata.d->array[0]);
+ //qCheckAccess(ldata.d->array[nn - 1]);
+#if QT_VERSION >= 0x040400
+ if (ldata.d->ref._q_value <= 0)
+ qCheck(false);
+#endif
+ }
+
+ int n = nn;
+ P(d, "value", "<" << n << " items>");
+ P(d, "valuedisabled", "true");
+ P(d, "numchild", n);
+ P(d, "childtype", d.innertype);
+ if (d.dumpChildren) {
+ unsigned innerSize = d.extraInt[0];
+ bool innerTypeIsPointer = isPointerType(d.innertype);
+ QByteArray strippedInnerType = stripPointerType(d.innertype);
+
+ // The exact condition here is:
+ // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
+ // but this data is available neither in the compiled binary nor
+ // in the frontend.
+ // So as first approximation only do the 'isLarge' check:
+ bool isInternal = innerSize <= int(sizeof(void*))
+ && isMovableType(d.innertype);
+
+ P(d, "internal", (int)isInternal);
+
+ P(d, "childtype", d.innertype);
+ if (n > 1000)
+ n = 1000;
+ d << ",children=[";
+ for (int i = 0; i != n; ++i) {
+ d.beginHash();
+ P(d, "name", "[" << i << "]");
+ if (innerTypeIsPointer) {
+ void *p = ldata.d->array + i + pdata->begin;
+ if (p) {
+ //P(d, "value","@" << p);
+ qDumpInnerValue(d, strippedInnerType.data(), deref(p));
+ } else {
+ P(d, "value", "<null>");
+ P(d, "numchild", "0");
+ }
+ } else {
+ void *p = ldata.d->array + i + pdata->begin;
+ if (isInternal) {
+ //qDumpInnerValue(d, d.innertype, p);
+ P(d, "addr", p);
+ qDumpInnerValueHelper(d, d.innertype, p);
+ } else {
+ //qDumpInnerValue(d, d.innertype, deref(p));
+ P(d, "addr", deref(p));
+ qDumpInnerValueHelper(d, d.innertype, deref(p));
+ }
+ }
+ d.endHash();
+ }
+ if (n < nn) {
+ d.beginHash();
+ P(d, "value", "<incomplete>");
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQLocale(QDumper &d)
+{
+ const QLocale &locale = *reinterpret_cast<const QLocale *>(d.data);
+ P(d, "value", locale.name());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QLocale");
+ P(d, "numchild", "8");
+ if (d.dumpChildren) {
+ d << ",children=[";
+
+ d.beginHash();
+ P(d, "name", "country");
+ P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->country()");
+ d.endHash();
+
+ d.beginHash();
+ P(d, "name", "language");
+ P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->language()");
+ d.endHash();
+
+ d.beginHash();
+ P(d, "name", "measurementSystem");
+ P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->measurementSystem()");
+ d.endHash();
+
+ d.beginHash();
+ P(d, "name", "numberOptions");
+ P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->numberOptions()");
+ d.endHash();
+
+ S(d, "timeFormat_(short)", locale.timeFormat(QLocale::ShortFormat));
+ S(d, "timeFormat_(long)", locale.timeFormat(QLocale::LongFormat));
+
+ QC(d, "decimalPoint", locale.decimalPoint());
+ QC(d, "exponential", locale.exponential());
+ QC(d, "percent", locale.percent());
+ QC(d, "zeroDigit", locale.zeroDigit());
+ QC(d, "groupSeparator", locale.groupSeparator());
+ QC(d, "negativeSign", locale.negativeSign());
+
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQMap(QDumper &d)
+{
+ QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
+ const char *keyType = d.templateParameters[0];
+ const char *valueType = d.templateParameters[1];
+
+ int n = h->size;
+
+ if (n < 0)
+ qCheck(false);
+ if (n > 0) {
+ qCheckAccess(h->backward);
+ qCheckAccess(h->forward[0]);
+ qCheckPointer(h->backward->backward);
+ qCheckPointer(h->forward[0]->backward);
+ }
+
+ P(d, "value", "<" << n << " items>");
+ P(d, "numchild", n);
+ if (d.dumpChildren) {
+ if (n > 1000)
+ n = 1000;
+
+ //unsigned keySize = d.extraInt[0];
+ //unsigned valueSize = d.extraInt[1];
+ unsigned mapnodesize = d.extraInt[2];
+ unsigned valueOff = d.extraInt[3];
+
+ bool simpleKey = isShortKey(keyType);
+ bool simpleValue = isShortKey(valueType);
+ // both negative:
+ int keyOffset = 2 * sizeof(void*) - int(mapnodesize);
+ int valueOffset = 2 * sizeof(void*) - int(mapnodesize) + valueOff;
+
+ P(d, "extra", "simplekey: " << simpleKey << " simpleValue: " << simpleValue
+ << " keyOffset: " << keyOffset << " valueOffset: " << valueOffset
+ << " mapnodesize: " << mapnodesize);
+ d << ",children=[";
+
+ QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]);
+ QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h);
+ int i = 0;
+
+ while (node != end) {
+ d.beginHash();
+ if (simpleKey) {
+ P(d, "type", valueType);
+ qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "name");
+
+ P(d, "nameisindex", "1");
+ if (simpleValue)
+ qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
+
+ P(d, "type", valueType);
+ P(d, "addr", addOffset(node, valueOffset));
+ } else {
+ P(d, "name", "[" << i << "]");
+ P(d, "type", NS"QMapNode<" << keyType << "," << valueType << " >");
+ // actually, any type (even 'char') will do...
+ P(d, "exp", "*('"NS"QMapNode<" << keyType << "," << valueType << " >'*)" << node);
+ //P(d, "exp", "*('"NS"QMapData'*)" << (void*)node);
+ //P(d, "exp", "*(char*)" << (void*)node);
+
+ // P(d, "addr", node); does not work as gdb fails to parse
+ // e.g. &((*('"NS"QMapNode<QString,Foo>'*)0x616658))
+ }
+ d.endHash();
+
+ ++i;
+ node = node->forward[0];
+ }
+ d << "]";
+ }
+
+ d.disarm();
+}
+
+static void qDumpQModelIndex(QDumper &d)
+{
+ const QModelIndex *mi = reinterpret_cast<const QModelIndex *>(d.data);
+
+ P(d, "type", NS"QModelIndex");
+ if (mi->isValid()) {
+ P(d, "value", "(" << mi->row() << ", " << mi->column() << ")");
+ P(d, "numchild", 5);
+ if (d.dumpChildren) {
+ d << ",children=[";
+ I(d, "row", mi->row());
+ I(d, "column", mi->column());
+
+ d.beginHash();
+ P(d, "name", "parent");
+ const QModelIndex parent = mi->parent();
+ if (parent.isValid())
+ P(d, "value", "(" << mi->row() << ", " << mi->column() << ")");
+ else
+ P(d, "value", "<invalid>");
+ P(d, "exp", "(("NSX"QModelIndex"NSY"*)" << d.data << ")->parent()");
+ P(d, "type", NS"QModelIndex");
+ P(d, "numchild", "1");
+ d.endHash();
+
+ S(d, "internalId", QString::number(mi->internalId(), 10));
+
+ d.beginHash();
+ P(d, "name", "model");
+ P(d, "value", static_cast<const void *>(mi->model()));
+ P(d, "type", NS"QAbstractItemModel*");
+ P(d, "numchild", "1");
+ d.endHash();
+
+ d << "]";
+ }
+ } else {
+ P(d, "value", "<invalid>");
+ P(d, "numchild", 0);
+ }
+
+ d.disarm();
+}
+
+static void qDumpQMapNode(QDumper &d)
+{
+ const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
+ const char *keyType = d.templateParameters[0];
+ const char *valueType = d.templateParameters[1];
+
+ qCheckAccess(h->backward);
+ qCheckAccess(h->forward[0]);
+
+ P(d, "value", "");
+ P(d, "numchild", 2);
+ if (d.dumpChildren) {
+ //unsigned keySize = d.extraInt[0];
+ //unsigned valueSize = d.extraInt[1];
+ unsigned mapnodesize = d.extraInt[2];
+ unsigned valueOff = d.extraInt[3];
+
+ unsigned keyOffset = 2 * sizeof(void*) - mapnodesize;
+ unsigned valueOffset = 2 * sizeof(void*) - mapnodesize + valueOff;
+
+ d << ",children=[";
+ d.beginHash();
+ P(d, "name", "key");
+ qDumpInnerValue(d, keyType, addOffset(h, keyOffset));
+
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "value");
+ qDumpInnerValue(d, valueType, addOffset(h, valueOffset));
+ d.endHash();
+ d << "]";
+ }
+
+ d.disarm();
+}
+
+static void qDumpQObject(QDumper &d)
+{
+ const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+ const QMetaObject *mo = ob->metaObject();
+ unsigned childrenOffset = d.extraInt[0];
+ P(d, "value", ob->objectName());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QObject");
+ P(d, "displayedtype", mo->className());
+ P(d, "numchild", 4);
+ if (d.dumpChildren) {
+ const QObjectList &children = ob->children();
+ int slotCount = 0;
+ int signalCount = 0;
+ for (int i = mo->methodCount(); --i >= 0; ) {
+ QMetaMethod::MethodType mt = mo->method(i).methodType();
+ signalCount += (mt == QMetaMethod::Signal);
+ slotCount += (mt == QMetaMethod::Slot);
+ }
+ d << ",children=[";
+ d.beginHash();
+ P(d, "name", "properties");
+ // FIXME: Note that when simply using '(QObject*)'
+ // in the cast below, Gdb/MI _sometimes_ misparses
+ // expressions further down in the tree.
+ P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
+ P(d, "type", NS"QObjectPropertyList");
+ P(d, "value", "<" << mo->propertyCount() << " items>");
+ P(d, "numchild", mo->propertyCount());
+ d.endHash();
+#if 0
+ d.beginHash();
+ P(d, "name", "methods");
+ P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
+ P(d, "type", NS"QObjectMethodList");
+ P(d, "value", "<" << mo->methodCount() << " items>");
+ P(d, "numchild", mo->methodCount());
+ d.endHash();
+#endif
+#if 0
+ d.beginHash();
+ P(d, "name", "senders");
+ P(d, "exp", "(*(class '"NS"QObjectPrivate'*)" << dfunc(ob) << ")->senders");
+ P(d, "type", NS"QList<"NS"QObjectPrivateSender>");
+ d.endHash();
+#endif
+#if PRIVATE_OBJECT_ALLOWED
+ d.beginHash();
+ P(d, "name", "signals");
+ P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
+ P(d, "type", NS"QObjectSignalList");
+ P(d, "value", "<" << signalCount << " items>");
+ P(d, "numchild", signalCount);
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "slots");
+ P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
+ P(d, "type", NS"QObjectSlotList");
+ P(d, "value", "<" << slotCount << " items>");
+ P(d, "numchild", slotCount);
+ d.endHash();
+#endif
+ d.beginHash();
+ P(d, "name", "children");
+ // works always, but causes additional traffic on the list
+ //P(d, "exp", "((class '"NS"QObject'*)" << d.data << ")->children()");
+ //
+ //P(d, "addr", addOffset(dfunc(ob), childrenOffset));
+ //P(d, "type", NS"QList<QObject *>");
+ //P(d, "value", "<" << children.size() << " items>");
+ qDumpInnerValue(d, NS"QList<"NS"QObject *>",
+ addOffset(dfunc(ob), childrenOffset));
+ P(d, "numchild", children.size());
+ d.endHash();
+#if 0
+ // Unneeded (and not working): Connections are listes as childen
+ // of the signal or slot they are connected to.
+ // d.beginHash();
+ // P(d, "name", "connections");
+ // P(d, "exp", "*(*(class "NS"QObjectPrivate*)" << dfunc(ob) << ")->connectionLists");
+ // P(d, "type", NS"QVector<"NS"QList<"NS"QObjectPrivate::Connection> >");
+ // d.endHash();
+#endif
+#if 0
+ d.beginHash();
+ P(d, "name", "objectprivate");
+ P(d, "type", NS"QObjectPrivate");
+ P(d, "addr", dfunc(ob));
+ P(d, "value", "");
+ P(d, "numchild", "1");
+ d.endHash();
+#endif
+ d.beginHash();
+ P(d, "name", "parent");
+ qDumpInnerValueHelper(d, NS"QObject *", ob->parent());
+ d.endHash();
+#if 1
+ d.beginHash();
+ P(d, "name", "className");
+ P(d, "value",ob->metaObject()->className());
+ P(d, "type", "");
+ P(d, "numchild", "0");
+ d.endHash();
+#endif
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQObjectPropertyList(QDumper &d)
+{
+ const QObject *ob = (const QObject *)d.data;
+ const QMetaObject *mo = ob->metaObject();
+ P(d, "addr", "<synthetic>");
+ P(d, "type", NS"QObjectPropertyList");
+ P(d, "numchild", mo->propertyCount());
+ if (d.dumpChildren) {
+ d << ",children=[";
+ for (int i = mo->propertyCount(); --i >= 0; ) {
+ const QMetaProperty & prop = mo->property(i);
+ d.beginHash();
+ P(d, "name", prop.name());
+ P(d, "exp", "((" << mo->className() << "*)" << ob
+ << ")->" << prop.name() << "()");
+ if (isEqual(prop.typeName(), "QString")) {
+ P(d, "value", prop.read(ob).toString());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QString");
+ P(d, "numchild", "0");
+ } else if (isEqual(prop.typeName(), "bool")) {
+ P(d, "value", (prop.read(ob).toBool() ? "true" : "false"));
+ P(d, "numchild", "0");
+ } else if (isEqual(prop.typeName(), "int")) {
+ P(d, "value", prop.read(ob).toInt());
+ P(d, "numchild", "0");
+ }
+ P(d, "type", prop.typeName());
+ P(d, "numchild", "1");
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQObjectMethodList(QDumper &d)
+{
+ const QObject *ob = (const QObject *)d.data;
+ const QMetaObject *mo = ob->metaObject();
+ P(d, "addr", "<synthetic>");
+ P(d, "type", NS"QObjectMethodList");
+ P(d, "numchild", mo->methodCount());
+ P(d, "childtype", "QMetaMethod::Method");
+ P(d, "childnumchild", "0");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ for (int i = 0; i != mo->methodCount(); ++i) {
+ const QMetaMethod & method = mo->method(i);
+ int mt = method.methodType();
+ d.beginHash();
+ P(d, "name", "[" << i << "] " << mo->indexOfMethod(method.signature())
+ << " " << method.signature());
+ P(d, "value", (mt == QMetaMethod::Signal ? "<Signal>" : "<Slot>") << " (" << mt << ")");
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+#if PRIVATE_OBJECT_ALLOWED
+const char * qConnectionTypes[] ={
+ "auto",
+ "direct",
+ "queued",
+ "autocompat",
+ "blockingqueued"
+};
+
+#if QT_VERSION >= 0x040400
+static const QObjectPrivate::ConnectionList &qConnectionList(const QObject *ob, int signalNumber)
+{
+ static const QObjectPrivate::ConnectionList emptyList;
+ const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
+ if (!p->connectionLists)
+ return emptyList;
+ typedef QVector<QObjectPrivate::ConnectionList> ConnLists;
+ const ConnLists *lists = reinterpret_cast<const ConnLists *>(p->connectionLists);
+ // there's an optimization making the lists only large enough to hold the
+ // last non-empty item
+ if (signalNumber >= lists->size())
+ return emptyList;
+ return lists->at(signalNumber);
+}
+#endif
+
+static void qDumpQObjectSignal(QDumper &d)
+{
+ unsigned signalNumber = d.extraInt[0];
+
+ P(d, "addr", "<synthetic>");
+ P(d, "numchild", "1");
+ P(d, "type", NS"QObjectSignal");
+
+#if QT_VERSION >= 0x040400
+ if (d.dumpChildren) {
+ const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+ d << ",children=[";
+ const QObjectPrivate::ConnectionList &connList = qConnectionList(ob, signalNumber);
+ for (int i = 0; i != connList.size(); ++i) {
+ const QObjectPrivate::Connection &conn = connList.at(i);
+ d.beginHash();
+ P(d, "name", "[" << i << "] receiver");
+ qDumpInnerValueHelper(d, NS"QObject *", conn.receiver);
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "[" << i << "] slot");
+ P(d, "type", "");
+ P(d, "value", conn.receiver->metaObject()->method(conn.method).signature());
+ P(d, "numchild", "0");
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "[" << i << "] type");
+ P(d, "type", "");
+ P(d, "value", "<" << qConnectionTypes[conn.method] << " connection>");
+ P(d, "numchild", "0");
+ d.endHash();
+ }
+ d << "]";
+ P(d, "numchild", connList.size());
+ }
+#endif
+ d.disarm();
+}
+
+static void qDumpQObjectSignalList(QDumper &d)
+{
+ const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+ const QMetaObject *mo = ob->metaObject();
+ int count = 0;
+ for (int i = mo->methodCount(); --i >= 0; )
+ count += (mo->method(i).methodType() == QMetaMethod::Signal);
+ P(d, "addr", d.data);
+ P(d, "numchild", count);
+#if QT_VERSION >= 0x040400
+ if (d.dumpChildren) {
+ d << ",children=[";
+ for (int i = 0; i != mo->methodCount(); ++i) {
+ const QMetaMethod & method = mo->method(i);
+ if (method.methodType() == QMetaMethod::Signal) {
+ int k = mo->indexOfSignal(method.signature());
+ const QObjectPrivate::ConnectionList &connList = qConnectionList(ob, k);
+ d.beginHash();
+ P(d, "name", "[" << k << "]");
+ P(d, "value", method.signature());
+ P(d, "numchild", connList.size());
+ //P(d, "numchild", "1");
+ P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
+ P(d, "type", NS"QObjectSignal");
+ d.endHash();
+ }
+ }
+ d << "]";
+ }
+#endif
+ d.disarm();
+}
+
+static void qDumpQObjectSlot(QDumper &d)
+{
+ int slotNumber = d.extraInt[0];
+
+ P(d, "addr", d.data);
+ P(d, "numchild", "1");
+ P(d, "type", NS"QObjectSlot");
+
+#if QT_VERSION >= 0x040400
+ if (d.dumpChildren) {
+ d << ",children=[";
+ int numchild = 0;
+ const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+ const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
+ for (int s = 0; s != p->senders.size(); ++s) {
+ const QObjectPrivate::Sender &sender = p->senders.at(s);
+ const QObjectPrivate::ConnectionList &connList
+ = qConnectionList(sender.sender, sender.signal);
+ for (int i = 0; i != connList.size(); ++i) {
+ const QObjectPrivate::Connection &conn = connList.at(i);
+ if (conn.receiver == ob && conn.method == slotNumber) {
+ ++numchild;
+ const QMetaMethod & method =
+ sender.sender->metaObject()->method(sender.signal);
+ d.beginHash();
+ P(d, "name", "[" << s << "] sender");
+ qDumpInnerValueHelper(d, NS"QObject *", sender.sender);
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "[" << s << "] signal");
+ P(d, "type", "");
+ P(d, "value", method.signature());
+ P(d, "numchild", "0");
+ d.endHash();
+ d.beginHash();
+ P(d, "name", "[" << s << "] type");
+ P(d, "type", "");
+ P(d, "value", "<" << qConnectionTypes[conn.method] << " connection>");
+ P(d, "numchild", "0");
+ d.endHash();
+ }
+ }
+ }
+ d << "]";
+ P(d, "numchild", numchild);
+ }
+#endif
+ d.disarm();
+}
+
+static void qDumpQObjectSlotList(QDumper &d)
+{
+ const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+#if QT_VERSION >= 0x040400
+ const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
+#endif
+ const QMetaObject *mo = ob->metaObject();
+
+ int count = 0;
+ for (int i = mo->methodCount(); --i >= 0; )
+ count += (mo->method(i).methodType() == QMetaMethod::Slot);
+
+ P(d, "addr", d.data);
+ P(d, "numchild", count);
+#if QT_VERSION >= 0x040400
+ if (d.dumpChildren) {
+ d << ",children=[";
+ for (int i = 0; i != mo->methodCount(); ++i) {
+ const QMetaMethod & method = mo->method(i);
+ if (method.methodType() == QMetaMethod::Slot) {
+ d.beginHash();
+ int k = mo->indexOfSlot(method.signature());
+ P(d, "name", "[" << k << "]");
+ P(d, "value", method.signature());
+
+ // count senders. expensive...
+ int numchild = 0;
+ for (int s = 0; s != p->senders.size(); ++s) {
+ const QObjectPrivate::Sender & sender = p->senders.at(s);
+ const QObjectPrivate::ConnectionList &connList
+ = qConnectionList(sender.sender, sender.signal);
+ for (int c = 0; c != connList.size(); ++c) {
+ const QObjectPrivate::Connection &conn = connList.at(c);
+ if (conn.receiver == ob && conn.method == k)
+ ++numchild;
+ }
+ }
+ P(d, "numchild", numchild);
+ P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
+ P(d, "type", NS"QObjectSlot");
+ d.endHash();
+ }
+ }
+ d << "]";
+ }
+#endif
+ d.disarm();
+}
+#endif // PRIVATE_OBJECT_ALLOWED
+
+
+static void qDumpQPixmap(QDumper &d)
+{
+#ifdef QT_GUI_LIB
+ const QPixmap &im = *reinterpret_cast<const QPixmap *>(d.data);
+ P(d, "value", "(" << im.width() << "x" << im.height() << ")");
+ P(d, "type", NS"QPixmap");
+ P(d, "numchild", "0");
+ d.disarm();
+#else
+ Q_UNUSED(d);
+#endif
+}
+
+static void qDumpQSet(QDumper &d)
+{
+ // This uses the knowledge that QHash<T> has only a single member
+ // of union { QHashData *d; QHashNode<Key, T> *e; };
+ QHashData *hd = *(QHashData**)d.data;
+ QHashData::Node *node = hd->firstNode();
+
+ int n = hd->size;
+ if (n < 0)
+ qCheck(false);
+ if (n > 0) {
+ qCheckAccess(node);
+ qCheckPointer(node->next);
+ }
+
+ P(d, "value", "<" << n << " items>");
+ P(d, "valuedisabled", "true");
+ P(d, "numchild", 2 * n);
+ if (d.dumpChildren) {
+ if (n > 100)
+ n = 100;
+ d << ",children=[";
+ int i = 0;
+ for (int bucket = 0; bucket != hd->numBuckets; ++bucket) {
+ for (node = hd->buckets[bucket]; node->next; node = node->next) {
+ d.beginHash();
+ P(d, "name", "[" << i << "]");
+ P(d, "type", d.innertype);
+ P(d, "exp", "(('QHashNode<" << d.innertype
+ << ",QHashDummyValue>'*)"
+ << static_cast<const void*>(node) << ")->key"
+ );
+ d.endHash();
+ ++i;
+ }
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQString(QDumper &d)
+{
+ const QString &str = *reinterpret_cast<const QString *>(d.data);
+
+ if (!str.isEmpty()) {
+ qCheckAccess(str.unicode());
+ qCheckAccess(str.unicode() + str.size());
+ }
+
+ P(d, "value", str);
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QString");
+ //P(d, "editvalue", str); // handled generically below
+ P(d, "numchild", "0");
+
+ d.disarm();
+}
+
+static void qDumpQStringList(QDumper &d)
+{
+ const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
+ int n = list.size();
+ if (n < 0)
+ qCheck(false);
+ if (n > 0) {
+ qCheckAccess(&list.front());
+ qCheckAccess(&list.back());
+ }
+
+ P(d, "value", "<" << n << " items>");
+ P(d, "valuedisabled", "true");
+ P(d, "numchild", n);
+ P(d, "childtype", NS"QString");
+ P(d, "childnumchild", "0");
+ if (d.dumpChildren) {
+ if (n > 1000)
+ n = 1000;
+ d << ",children=[";
+ for (int i = 0; i != n; ++i) {
+ d.beginHash();
+ P(d, "name", "[" << i << "]");
+ P(d, "value", list[i]);
+ P(d, "valueencoded", "1");
+ d.endHash();
+ }
+ if (n < list.size()) {
+ d.beginHash();
+ P(d, "name", "Warning:");
+ P(d, "value", "<incomplete>");
+ P(d, "type", "");
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQTextCodec(QDumper &d)
+{
+ const QTextCodec &codec = *reinterpret_cast<const QTextCodec *>(d.data);
+ P(d, "value", codec.name());
+ P(d, "valueencoded", "1");
+ P(d, "type", NS"QTextCodec");
+ P(d, "numchild", "2");
+ if (d.dumpChildren) {
+ d << ",children=[";
+ S(d, "name", codec.name());
+ I(d, "mibEnum", codec.mibEnum());
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQVariantHelper(const void *data, QString *value,
+ QString *exp, int *numchild)
+{
+ const QVariant &v = *reinterpret_cast<const QVariant *>(data);
+ switch (v.type()) {
+ case QVariant::Invalid:
+ *value = QLatin1String("<invalid>");
+ *numchild = 0;
+ break;
+ case QVariant::String:
+ *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
+ *numchild = 0;
+ break;
+ case QVariant::StringList:
+ *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c"))
+ .arg((quintptr)data);
+ *numchild = v.toStringList().size();
+ break;
+ case QVariant::Int:
+ *value = QString::number(v.toInt());
+ *numchild= 0;
+ break;
+ case QVariant::Double:
+ *value = QString::number(v.toDouble());
+ *numchild = 0;
+ break;
+ default: {
+ char buf[1000];
+ const char *format = (v.typeName()[0] == 'Q')
+ ? "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)%p)"
+ : "'%s "NS"qVariantValue<%s >'(*('"NS"QVariant'*)%p)";
+ qsnprintf(buf, sizeof(buf) - 1, format, v.typeName(), v.typeName(), data);
+ *exp = QLatin1String(buf);
+ *numchild = 1;
+ break;
+ }
+ }
+}
+
+static void qDumpQVariant(QDumper &d)
+{
+ const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
+ QString value;
+ QString exp;
+ int numchild = 0;
+ qDumpQVariantHelper(d.data, &value, &exp, &numchild);
+ bool isInvalid = (v.typeName() == 0);
+ if (isInvalid) {
+ P(d, "value", "(invalid)");
+ } else if (value.isEmpty()) {
+ P(d, "value", "(" << v.typeName() << ") " << qPrintable(value));
+ } else {
+ QByteArray ba;
+ ba += '(';
+ ba += v.typeName();
+ ba += ") ";
+ ba += qPrintable(value);
+ P(d, "value", ba);
+ P(d, "valueencoded", "1");
+ }
+ P(d, "type", NS"QVariant");
+ P(d, "numchild", (isInvalid ? "0" : "1"));
+ if (d.dumpChildren) {
+ d << ",children=[";
+ d.beginHash();
+ P(d, "name", "value");
+ if (!exp.isEmpty())
+ P(d, "exp", qPrintable(exp));
+ if (!value.isEmpty()) {
+ P(d, "value", value);
+ P(d, "valueencoded", "1");
+ }
+ P(d, "type", v.typeName());
+ P(d, "numchild", numchild);
+ d.endHash();
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpQVector(QDumper &d)
+{
+ QVectorData *v = *reinterpret_cast<QVectorData *const*>(d.data);
+
+ // Try to provoke segfaults early to prevent the frontend
+ // from asking for unavailable child details
+ int nn = v->size;
+ if (nn < 0)
+ qCheck(false);
+ if (nn > 0) {
+ //qCheckAccess(&vec.front());
+ //qCheckAccess(&vec.back());
+ }
+
+ unsigned innersize = d.extraInt[0];
+ unsigned typeddatasize = d.extraInt[1];
+
+ int n = nn;
+ P(d, "value", "<" << n << " items>");
+ P(d, "valuedisabled", "true");
+ P(d, "numchild", n);
+ if (d.dumpChildren) {
+ bool innerTypeIsPointer = isPointerType(d.innertype);
+ QByteArray strippedInnerType = stripPointerType(d.innertype);
+
+ if (n > 1000)
+ n = 1000;
+ d << ",children=[";
+ for (int i = 0; i != n; ++i) {
+ d.beginHash();
+ P(d, "name", "[" << i << "]");
+ const void *p = addOffset(v, i * innersize + typeddatasize);
+ if (innerTypeIsPointer) {
+ if (deref(p)) {
+ //P(d, "value","@" << p);
+ qDumpInnerValue(d, strippedInnerType.data(), deref(p));
+ } else {
+ P(d, "type", d.innertype);
+ P(d, "value", "<null>");
+ P(d, "numchild", "0");
+ }
+ } else {
+ qDumpInnerValue(d, d.innertype, p);
+ }
+ d.endHash();
+ }
+ if (n < nn) {
+ d.beginHash();
+ P(d, "name", "[...]");
+ P(d, "value", "<incomplete>");
+ P(d, "type", d.innertype);
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpStdString(QDumper &d)
+{
+ const std::string &str = *reinterpret_cast<const std::string *>(d.data);
+
+ if (!str.empty()) {
+ qCheckAccess(str.c_str());
+ qCheckAccess(str.c_str() + str.size() - 1);
+ }
+
+ d << ",value=\"";
+ d.putBase64Encoded(str.c_str(), str.size());
+ d << "\"";
+ P(d, "valueencoded", "1");
+ P(d, "type", "std::string");
+ P(d, "numchild", "0");
+
+ d.disarm();
+}
+
+static void qDumpStdWString(QDumper &d)
+{
+ const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data);
+
+ if (!str.empty()) {
+ qCheckAccess(str.c_str());
+ qCheckAccess(str.c_str() + str.size() - 1);
+ }
+
+ d << "value=\"";
+ d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
+ d << "\"";
+ P(d, "valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
+ P(d, "type", "std::wstring");
+ P(d, "numchild", "0");
+
+ d.disarm();
+}
+
+static void qDumpStdVector(QDumper &d)
+{
+ // Correct type would be something like:
+ // std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl
+ struct VectorImpl {
+ char *start;
+ char *finish;
+ char *end_of_storage;
+ };
+ const VectorImpl *v = static_cast<const VectorImpl *>(d.data);
+
+ // Try to provoke segfaults early to prevent the frontend
+ // from asking for unavailable child details
+ int nn = (v->finish - v->start) / d.extraInt[0];
+ if (nn < 0)
+ qCheck(false);
+ if (nn > 0) {
+ qCheckAccess(v->start);
+ qCheckAccess(v->finish);
+ qCheckAccess(v->end_of_storage);
+ }
+
+ int n = nn;
+ P(d, "value", "<" << n << " items>");
+ P(d, "valuedisabled", "true");
+ P(d, "numchild", n);
+ if (d.dumpChildren) {
+ unsigned innersize = d.extraInt[0];
+ bool innerTypeIsPointer = isPointerType(d.innertype);
+ QByteArray strippedInnerType = stripPointerType(d.innertype);
+
+ if (n > 1000)
+ n = 1000;
+ d << ",children=[";
+ for (int i = 0; i != n; ++i) {
+ d.beginHash();
+ P(d, "name", "[" << i << "]");
+ const void *p = addOffset(v->start, i * innersize);
+ if (innerTypeIsPointer) {
+ if (deref(p)) {
+ //P(d, "value","@" << p);
+ qDumpInnerValue(d, strippedInnerType.data(), deref(p));
+ } else {
+ P(d, "type", d.innertype);
+ P(d, "value", "<null>");
+ P(d, "numchild", "0");
+ }
+ } else {
+ qDumpInnerValue(d, d.innertype, p);
+ }
+ d.endHash();
+ }
+ if (n < nn) {
+ d.beginHash();
+ P(d, "name", "[...]");
+ P(d, "value", "<incomplete>");
+ P(d, "type", d.innertype);
+ d.endHash();
+ }
+ d << "]";
+ }
+ d.disarm();
+}
+
+static void qDumpStdVectorBool(QDumper &d)
+{
+ // FIXME
+ return qDumpStdVector(d);
+}
+
+static void handleProtocolVersion2and3(QDumper & d)
+{
+ if (!d.outertype[0]) {
+ qDumpUnknown(d);
+ return;
+ }
+
+ d.setupTemplateParameters();
+ P(d, "iname", d.iname);
+ P(d, "addr", d.data);
+
+#ifdef QT_NO_QDATASTREAM
+ if (d.protocolVersion == 3) {
+ QVariant::Type type = QVariant::nameToType(d.outertype);
+ if (type != QVariant::Invalid) {
+ QVariant v(type, d.data);
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::WriteOnly);
+ ds << v;
+ P(d, "editvalue", ba);
+ }
+ }
+#endif
+
+ const char *type = stripNamespace(d.outertype);
+ // type[0] is usally 'Q', so don't use it
+ switch (type[1]) {
+ case 'B':
+ if (isEqual(type, "QByteArray"))
+ qDumpQByteArray(d);
+ break;
+ case 'D':
+ if (isEqual(type, "QDateTime"))
+ qDumpQDateTime(d);
+ else if (isEqual(type, "QDir"))
+ qDumpQDir(d);
+ break;
+ case 'F':
+ if (isEqual(type, "QFile"))
+ qDumpQFile(d);
+ else if (isEqual(type, "QFileInfo"))
+ qDumpQFileInfo(d);
+ break;
+ case 'H':
+ if (isEqual(type, "QHash"))
+ qDumpQHash(d);
+ else if (isEqual(type, "QHashNode"))
+ qDumpQHashNode(d);
+ break;
+ case 'I':
+ if (isEqual(type, "QImage"))
+ qDumpQImage(d);
+ break;
+ case 'L':
+ if (isEqual(type, "QList"))
+ qDumpQList(d);
+ else if (isEqual(type, "QLocale"))
+ qDumpQLocale(d);
+ break;
+ case 'M':
+ if (isEqual(type, "QMap"))
+ qDumpQMap(d);
+ else if (isEqual(type, "QMapNode"))
+ qDumpQMapNode(d);
+ else if (isEqual(type, "QModelIndex"))
+ qDumpQModelIndex(d);
+ break;
+ case 'O':
+ if (isEqual(type, "QObject"))
+ qDumpQObject(d);
+ else if (isEqual(type, "QObjectPropertyList"))
+ qDumpQObjectPropertyList(d);
+ else if (isEqual(type, "QObjectMethodList"))
+ qDumpQObjectMethodList(d);
+ #if PRIVATE_OBJECT_ALLOWED
+ else if (isEqual(type, "QObjectSignal"))
+ qDumpQObjectSignal(d);
+ else if (isEqual(type, "QObjectSignalList"))
+ qDumpQObjectSignalList(d);
+ else if (isEqual(type, "QObjectSlot"))
+ qDumpQObjectSlot(d);
+ else if (isEqual(type, "QObjectSlotList"))
+ qDumpQObjectSlotList(d);
+ #endif
+ break;
+ case 'P':
+ if (isEqual(type, "QPixmap"))
+ qDumpQPixmap(d);
+ break;
+ case 'S':
+ if (isEqual(type, "QSet"))
+ qDumpQSet(d);
+ else if (isEqual(type, "QString"))
+ qDumpQString(d);
+ else if (isEqual(type, "QStringList"))
+ qDumpQStringList(d);
+ break;
+ case 'T':
+ if (isEqual(type, "QTextCodec"))
+ qDumpQTextCodec(d);
+ break;
+ case 'V':
+ if (isEqual(type, "QVariant"))
+ qDumpQVariant(d);
+ else if (isEqual(type, "QVector"))
+ qDumpQVector(d);
+ break;
+ case 's':
+ if (isEqual(type, "wstring"))
+ qDumpStdWString(d);
+ break;
+ case 't':
+ if (isEqual(type, "std::vector"))
+ qDumpStdVector(d);
+ else if (isEqual(type, "std::vector::bool"))
+ qDumpStdVectorBool(d);
+ else if (isEqual(type, "string"))
+ qDumpStdString(d);
+ else if (isEqual(type, "std::string"))
+ qDumpStdString(d);
+ else if (isEqual(type, "std::wstring"))
+ qDumpStdWString(d);
+ break;
+ }
+
+ if (!d.success)
+ qDumpUnknown(d);
+}
+
+} // anonymous namespace
+
+
+extern "C" Q_DECL_EXPORT
+void qDumpObjectData440(
+ int protocolVersion,
+ int token,
+ void *data,
+ bool dumpChildren,
+ int extraInt0,
+ int extraInt1,
+ int extraInt2,
+ int extraInt3)
+{
+ if (protocolVersion == -2) {
+ // close socket
+ QDumper d;
+ d.protocolVersion = protocolVersion;
+ d.token = token;
+ d.flush();
+ d.disarm();
+ }
+
+ else if (protocolVersion == -1) {
+ // finalize Startup
+ QDumper d;
+ d.protocolVersion = protocolVersion;
+ d.token = token;
+ d.disarm();
+ }
+
+ else if (protocolVersion == 0) {
+ QDumper d;
+ d.protocolVersion = protocolVersion;
+ d.token = token;
+ // used to test whether error output gets through
+ //fprintf(stderr, "using stderr, qDebug follows: %d\n", token);
+ //qDebug() << "using qDebug, stderr already used: " << token;
+ d.disarm();
+ }
+
+ else if (protocolVersion == 1) {
+ QDumper d;
+ d.protocolVersion = protocolVersion;
+ d.token = token;
+
+ //qDebug() << "SOCKET: after connect: state: " << qDumperSocket.state();
+ // simpledumpers is a list of all available dumpers that are
+ // _not_ templates. templates currently require special
+ // hardcoded handling in the debugger plugin.
+ // don't mention them here in this list
+ d << "simpledumpers=["
+ "\""NS"QByteArray\","
+ "\""NS"QDir\","
+ "\""NS"QImage\","
+ "\""NS"QFile\","
+ "\""NS"QFileInfo\","
+ "\""NS"QLocale\","
+ "\""NS"QModelIndex\","
+ //"\""NS"QHash\"," // handled on GH side
+ //"\""NS"QHashNode\","
+ //"\""NS"QMap\"," // handled on GH side
+ //"\""NS"QMapNode\","
+ "\""NS"QObject\","
+ "\""NS"QObjectMethodList\"," // hack to get nested properties display
+ "\""NS"QObjectPropertyList\","
+ #if PRIVATE_OBJECT_ALLOWED
+ "\""NS"QObjectSignal\","
+ "\""NS"QObjectSignalList\","
+ "\""NS"QObjectSlot\","
+ "\""NS"QObjectSlotList\","
+ #endif // PRIVATE_OBJECT_ALLOWED
+ "\""NS"QString\","
+ "\""NS"QStringList\","
+ "\""NS"QTextCodec\","
+ "\""NS"QVariant\","
+ "\""NS"QWidget\","
+ "\""NS"QDateTime\","
+ "\"string\","
+ "\"wstring\","
+ "\"std::string\","
+ "\"std::wstring\","
+ // << "\""NS"QRegion\","
+ "]";
+ d << ",namespace=\""NS"\"";
+ d.disarm();
+ }
+
+ else if (protocolVersion == 2 || protocolVersion == 3) {
+ QDumper d;
+
+ d.protocolVersion = protocolVersion;
+ d.token = token;
+ d.data = data;
+ d.dumpChildren = dumpChildren;
+ d.extraInt[0] = extraInt0;
+ d.extraInt[1] = extraInt1;
+ d.extraInt[2] = extraInt2;
+ d.extraInt[3] = extraInt3;
+
+ const char *inbuffer = qDumpInBuffer;
+ d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+ d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+ d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+ d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+ d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+
+ handleProtocolVersion2and3(d);
+ }
+
+ else {
+ qDebug() << "Unsupported protocol version" << protocolVersion;
+ }
+}
+
+
+// ]})
diff --git a/bin/gdbmacros/gdbmacros.pro b/bin/gdbmacros/gdbmacros.pro
new file mode 100644
index 0000000000..bd1c07b968
--- /dev/null
+++ b/bin/gdbmacros/gdbmacros.pro
@@ -0,0 +1,3 @@
+TEMPLATE = lib
+CONFIG += shared
+SOURCES=gdbmacros.cpp
diff --git a/bin/license.txt b/bin/license.txt
new file mode 100644
index 0000000000..8e4678abe4
--- /dev/null
+++ b/bin/license.txt
@@ -0,0 +1,615 @@
+For individuals and/or legal entities resident in the Americas (North
+America, Central America and South America), the applicable licensing
+terms are specified under the heading "Technology Preview License
+Agreement: The Americas".
+
+For individuals and/or legal entities not resident in The Americas, the
+applicable licensing terms are specified under the heading "Technology
+Preview License Agreement: Rest of the World".
+
+
+TECHNOLOGY PREVIEW LICENSE AGREEMENT: The Americas
+Agreement version 2.3
+
+This Technology Preview License Agreement ("Agreement") is a legal
+agreement between Nokia Inc. ("Nokia"), with its registered office at
+6021 Connection Drive, Irving, TX 75039, U.S.A. and you (either an
+individual or a legal entity) ("Licensee") for the Licensed Software (as
+defined below).
+
+1. DEFINITIONS
+
+"Affiliate" of a Party shall mean an entity (i) which is directly or
+indirectly controlling such Party; (ii) which is under the same direct
+or indirect ownership or control as such Party; or (iii) which is
+directly or indirectly owned or controlled by such Party. For these
+purposes, an entity shall be treated as being controlled by another if
+that other entity has fifty percent (50 %) or more of the votes in such
+entity, is able to direct its affairs and/or to control the composition
+of its board of directors or equivalent body.
+
+"Term" shall mean the period of time six (6) months from the later of
+(a) the Effective Date; or (b) the date the Licensed Software was
+initially delivered to Licensee by Nokia. If no specific Effective Date
+is set forth in the Agreement, the Effective Date shall be deemed to be
+the date the Licensed Software was initially delivered to Licensee.
+
+"Licensed Software" shall mean the computer software, "online" or
+electronic documentation, associated media and printed materials,
+including the source code, example programs and the documentation
+delivered by Nokia to Licensee in conjunction with this Agreement.
+
+"Party" or "Parties" shall mean Licensee and/or Nokia.
+
+
+2. OWNERSHIP
+
+The Licensed Software is protected by copyright laws and international
+copyright treaties, as well as other intellectual property laws and
+treaties. The Licensed Software is licensed, not sold.
+
+If Licensee provides any findings, proposals, suggestions or other
+feedback ("Feedback") to Nokia regarding the Licensed Software, Nokia
+shall own all right, title and interest including the intellectual
+property rights in and to such Feedback, excluding however any existing
+patent rights of Licensee. To the extent Licensee owns or controls any
+patents for such Feedback Licensee hereby grants to Nokia and its
+Affiliates, a worldwide, perpetual, non-transferable, sublicensable,
+royalty-free license to (i) use, copy and modify Feedback and to create
+derivative works thereof, (ii) to make (and have made), use, import,
+sell, offer for sale, lease, dispose, offer for disposal or otherwise
+exploit any products or services of Nokia containing Feedback,, and
+(iii) sublicense all the foregoing rights to third party licensees and
+customers of Nokia and/or its Affiliates.
+
+
+3. VALIDITY OF THE AGREEMENT
+
+By installing, copying, or otherwise using the Licensed Software,
+Licensee agrees to be bound by the terms of this Agreement. If Licensee
+does not agree to the terms of this Agreement, Licensee may not install,
+copy, or otherwise use the Licensed Software. Upon Licensee's acceptance
+of the terms and conditions of this Agreement, Nokia grants Licensee the
+right to use the Licensed Software in the manner provided below.
+
+
+4. LICENSES
+
+4.1. Using and Copying
+
+Nokia grants to Licensee a non-exclusive, non-transferable, time-limited
+license to use and copy the Licensed Software for sole purpose of
+evaluating and testing the Licensed Software during the Term.
+
+Licensee may install copies of the Licensed Software on an unlimited
+number of computers provided that (a) if an individual, only such
+individual; or (b) if a legal entity only its employees; use the
+Licensed Software for the authorized purposes.
+
+4.2 No Distribution or Modifications
+
+Licensee may not disclose, modify, sell, market, commercialise,
+distribute, loan, rent, lease, or license the Licensed Software or any
+copy of it or use the Licensed Software for any purpose that is not
+expressly granted in this Section 4. Licensee may not alter or remove
+any details of ownership, copyright, trademark or other property right
+connected with the Licensed Software. Licensee may not distribute any
+software statically or dynamically linked with the Licensed Software.
+
+4.3 No Technical Support
+
+Nokia has no obligation to furnish Licensee with any technical support
+whatsoever. Any such support is subject to separate agreement between
+the Parties.
+
+
+5. PRE-RELEASE CODE
+The Licensed Software contains pre-release code that is not at the level
+of performance and compatibility of a final, generally available,
+product offering. The Licensed Software may not operate correctly and
+may be substantially modified prior to the first commercial product
+release, if any. Nokia is not obligated to make this or any later
+version of the Licensed Software commercially available. The License
+Software is "Not for Commercial Use" and may only be used for the
+purposes described in Section 4. The Licensed Software may not be used
+in a live operating environment where it may be relied upon to perform
+in the same manner as a commercially released product or with data that
+has not been sufficiently backed up.
+
+6. THIRD PARTY SOFTWARE
+
+The Licensed Software may provide links to third party libraries or code
+(collectively "Third Party Software") to implement various functions.
+Third Party Software does not comprise part of the Licensed Software. In
+some cases, access to Third Party Software may be included along with
+the Licensed Software delivery as a convenience for development and
+testing only. Such source code and libraries may be listed in the
+".../src/3rdparty" source tree delivered with the Licensed Software or
+documented in the Licensed Software where the Third Party Software is
+used, as may be amended from time to time, do not comprise the Licensed
+Software. Licensee acknowledges (1) that some part of Third Party
+Software may require additional licensing of copyright and patents from
+the owners of such, and (2) that distribution of any of the Licensed
+Software referencing any portion of a Third Party Software may require
+appropriate licensing from such third parties.
+
+
+7. LIMITED WARRANTY AND WARRANTY DISCLAIMER
+
+The Licensed Software is licensed to Licensee "as is". To the maximum
+extent permitted by applicable law, Nokia on behalf of itself and its
+suppliers, disclaims all warranties and conditions, either express or
+implied, including, but not limited to, implied warranties of
+merchantability, fitness for a particular purpose, title and
+non-infringement with regard to the Licensed Software.
+
+
+8. LIMITATION OF LIABILITY
+
+If, Nokia's warranty disclaimer notwithstanding, Nokia is held liable to
+Licensee, whether in contract, tort or any other legal theory, based on
+the Licensed Software, Nokia's entire liability to Licensee and
+Licensee's exclusive remedy shall be, at Nokia's option, either (A)
+return of the price Licensee paid for the Licensed Software, or (B)
+repair or replacement of the Licensed Software, provided Licensee
+returns to Nokia all copies of the Licensed Software as originally
+delivered to Licensee. Nokia shall not under any circumstances be liable
+to Licensee based on failure of the Licensed Software if the failure
+resulted from accident, abuse or misapplication, nor shall Nokia under
+any circumstances be liable for special damages, punitive or exemplary
+damages, damages for loss of profits or interruption of business or for
+loss or corruption of data. Any award of damages from Nokia to Licensee
+shall not exceed the total amount Licensee has paid to Nokia in
+connection with this Agreement.
+
+
+9. CONFIDENTIALITY
+
+Each party acknowledges that during the Term of this Agreement it shall
+have access to information about the other party's business, business
+methods, business plans, customers, business relations, technology, and
+other information, including the terms of this Agreement, that is
+confidential and of great value to the other party, and the value of
+which would be significantly reduced if disclosed to third parties (the
+"Confidential Information"). Accordingly, when a party (the "Receiving
+Party") receives Confidential Information from another party (the
+"Disclosing Party"), the Receiving Party shall, and shall obligate its
+employees and agents and employees and agents of its Affiliates to: (i)
+maintain the Confidential Information in strict confidence; (ii) not
+disclose the Confidential Information to a third party without the
+Disclosing Party's prior written approval; and (iii) not, directly or
+indirectly, use the Confidential Information for any purpose other than
+for exercising its rights and fulfilling its responsibilities pursuant
+to this Agreement. Each party shall take reasonable measures to protect
+the Confidential Information of the other party, which measures shall
+not be less than the measures taken by such party to protect its own
+confidential and proprietary information.
+
+"Confidential Information" shall not include information that (a) is or
+becomes generally known to the public through no act or omission of the
+Receiving Party; (b) was in the Receiving Party's lawful possession
+prior to the disclosure hereunder and was not subject to limitations on
+disclosure or use; (c) is developed by the Receiving Party without
+access to the Confidential Information of the Disclosing Party or by
+persons who have not had access to the Confidential Information of the
+Disclosing Party as proven by the written records of the Receiving
+Party; (d) is lawfully disclosed to the Receiving Party without
+restrictions, by a third party not under an obligation of
+confidentiality; or (e) the Receiving Party is legally compelled to
+disclose the information, in which case the Receiving Party shall assert
+the privileged and confidential nature of the information and cooperate
+fully with the Disclosing Party to protect against and prevent
+disclosure of any Confidential Information and to limit the scope of
+disclosure and the dissemination of disclosed Confidential Information
+by all legally available means.
+
+The obligations of the Receiving Party under this Section shall continue
+during the Initial Term and for a period of five (5) years after
+expiration or termination of this Agreement. To the extent that the
+terms of the Non-Disclosure Agreement between Nokia and Licensee
+conflict with the terms of this Section 8, this Section 8 shall be
+controlling over the terms of the Non-Disclosure Agreement.
+
+
+10. GENERAL PROVISIONS
+
+10.1 No Assignment
+
+Licensee shall not be entitled to assign or transfer all or any of its
+rights, benefits and obligations under this Agreement without the prior
+written consent of Nokia, which shall not be unreasonably withheld.
+
+10.2 Termination
+
+Nokia may terminate the Agreement at any time immediately upon written
+notice by Nokia to Licensee if Licensee breaches this Agreement.
+
+Upon termination of this Agreement, Licensee shall return to Nokia all
+copies of Licensed Software that were supplied by Nokia. All other
+copies of Licensed Software in the possession or control of Licensee
+must be erased or destroyed. An officer of Licensee must promptly
+deliver to Nokia a written confirmation that this has occurred.
+
+10.3 Surviving Sections
+
+Any terms and conditions that by their nature or otherwise reasonably
+should survive a cancellation or termination of this Agreement shall
+also be deemed to survive. Such terms and conditions include, but are
+not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4,
+10.5, 10.6, 10.7, and 10.8 of this Agreement.
+
+10.4 Entire Agreement
+
+This Agreement constitutes the complete agreement between the parties
+and supersedes all prior or contemporaneous discussions,
+representations, and proposals, written or oral, with respect to the
+subject matters discussed herein, with the exception of the
+non-disclosure agreement executed by the parties in connection with this
+Agreement ("Non-Disclosure Agreement"), if any, shall be subject to
+Section 8. No modification of this Agreement shall be effective unless
+contained in a writing executed by an authorized representative of each
+party. No term or condition contained in Licensee's purchase order shall
+apply unless expressly accepted by Nokia in writing. If any provision of
+the Agreement is found void or unenforceable, the remainder shall remain
+valid and enforceable according to its terms. If any remedy provided is
+determined to have failed for its essential purpose, all limitations of
+liability and exclusions of damages set forth in this Agreement shall
+remain in effect.
+
+10.5 Export Control
+
+Licensee acknowledges that the Licensed Software may be subject to
+export control restrictions of various countries. Licensee shall fully
+comply with all applicable export license restrictions and requirements
+as well as with all laws and regulations relating to the importation of
+the Licensed Software and shall procure all necessary governmental
+authorizations, including without limitation, all necessary licenses,
+approvals, permissions or consents, where necessary for the
+re-exportation of the Licensed Software.,
+
+10.6 Governing Law and Legal Venue
+
+This Agreement shall be governed by and construed in accordance with the
+federal laws of the United States of America and the internal laws of
+the State of New York without given effect to any choice of law rule
+that would result in the application of the laws of any other
+jurisdiction. The United Nations Convention on Contracts for the
+International Sale of Goods (CISG) shall not apply. Each Party (a)
+hereby irrevocably submits itself to and consents to the jurisdiction of
+the United States District Court for the Southern District of New York
+(or if such court lacks jurisdiction, the state courts of the State of
+New York) for the purposes of any action, claim, suit or proceeding
+between the Parties in connection with any controversy, claim, or
+dispute arising out of or relating to this Agreement; and (b) hereby
+waives, and agrees not to assert by way of motion, as a defense or
+otherwise, in any such action, claim, suit or proceeding, any claim that
+is not personally subject to the jurisdiction of such court(s), that the
+action, claim, suit or proceeding is brought in an inconvenient forum or
+that the venue of the action, claim, suit or proceeding is improper.
+Notwithstanding the foregoing, nothing in this Section 9.6 is intended
+to, or shall be deemed to, constitute a submission or consent to, or
+selection of, jurisdiction, forum or venue for any action for patent
+infringement, whether or not such action relates to this Agreement.
+
+10.7 No Implied License
+
+There are no implied licenses or other implied rights granted under this
+Agreement, and all rights, save for those expressly granted hereunder,
+shall remain with Nokia and its licensors. In addition, no licenses or
+immunities are granted to the combination of the Licensed Software with
+any other software or hardware not delivered by Nokia under this
+Agreement.
+
+10.8 Government End Users
+
+A "U.S. Government End User" shall mean any agency or entity of the
+government of the United States. The following shall apply if Licensee
+is a U.S. Government End User. The Licensed Software is a "commercial
+item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995),
+consisting of "commercial computer software" and "commercial computer
+software documentation," as such terms are used in 48 C.F.R. 12.212
+(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
+through 227.7202-4 (June 1995), all U.S. Government End Users acquire
+the Licensed Software with only those rights set forth herein. The
+Licensed Software (including related documentation) is provided to U.S.
+Government End Users: (a) only as a commercial end item; and (b) only
+pursuant to this Agreement.
+
+
+
+
+
+TECHNOLOGY PREVIEW LICENSE AGREEMENT: Rest of the World
+Agreement version 2.3
+
+This Technology Preview License Agreement ("Agreement") is a legal
+agreement between Nokia Corporation ("Nokia"), with its registered
+office at Keilalahdentie 4, 02150 Espoo, Finland and you (either an
+individual or a legal entity) ("Licensee") for the Licensed Software (as
+defined below).
+
+1. DEFINITIONS
+
+"Affiliate" of a Party shall mean an entity (i) which is directly or
+indirectly controlling such Party; (ii) which is under the same direct
+or indirect ownership or control as such Party; or (iii) which is
+directly or indirectly owned or controlled by such Party. For these
+purposes, an entity shall be treated as being controlled by another if
+that other entity has fifty percent (50 %) or more of the votes in such
+entity, is able to direct its affairs and/or to control the composition
+of its board of directors or equivalent body.
+
+"Term" shall mean the period of time six (6) months from the later of
+(a) the Effective Date; or (b) the date the Licensed Software was
+initially delivered to Licensee by Nokia. If no specific Effective Date
+is set forth in the Agreement, the Effective Date shall be deemed to be
+the date the Licensed Software was initially delivered to Licensee.
+
+"Licensed Software" shall mean the computer software, "online" or
+electronic documentation, associated media and printed materials,
+including the source code, example programs and the documentation
+delivered by Nokia to Licensee in conjunction with this Agreement.
+
+"Party" or "Parties" shall mean Licensee and/or Nokia.
+
+
+2. OWNERSHIP
+
+The Licensed Software is protected by copyright laws and international
+copyright treaties, as well as other intellectual property laws and
+treaties. The Licensed Software is licensed, not sold.
+
+If Licensee provides any findings, proposals, suggestions or other
+feedback ("Feedback") to Nokia regarding the Licensed Software, Nokia
+shall own all right, title and interest including the intellectual
+property rights in and to such Feedback, excluding however any existing
+patent rights of Licensee. To the extent Licensee owns or controls any
+patents for such Feedback Licensee hereby grants to Nokia and its
+Affiliates, a worldwide, perpetual, non-transferable, sublicensable,
+royalty-free license to (i) use, copy and modify Feedback and to create
+derivative works thereof, (ii) to make (and have made), use, import,
+sell, offer for sale, lease, dispose, offer for disposal or otherwise
+exploit any products or services of Nokia containing Feedback,, and
+(iii) sublicense all the foregoing rights to third party licensees and
+customers of Nokia and/or its Affiliates.
+
+3. VALIDITY OF THE AGREEMENT
+
+By installing, copying, or otherwise using the Licensed Software,
+Licensee agrees to be bound by the terms of this Agreement. If Licensee
+does not agree to the terms of this Agreement, Licensee may not install,
+copy, or otherwise use the Licensed Software. Upon Licensee's acceptance
+of the terms and conditions of this Agreement, Nokia grants Licensee the
+right to use the Licensed Software in the manner provided below.
+
+
+4. LICENSES
+
+4.1. Using and Copying
+
+Nokia grants to Licensee a non-exclusive, non-transferable, time-limited
+license to use and copy the Licensed Software for sole purpose of
+evaluating and testing the Licensed Software during the Term.
+
+Licensee may install copies of the Licensed Software on an unlimited
+number of computers provided that (a) if an individual, only such
+individual; or (b) if a legal entity only its employees; use the
+Licensed Software for the authorized purposes.
+
+4.2 No Distribution or Modifications
+
+Licensee may not disclose, modify, sell, market, commercialise,
+distribute, loan, rent, lease, or license the Licensed Software or any
+copy of it or use the Licensed Software for any purpose that is not
+expressly granted in this Section 4. Licensee may not alter or remove
+any details of ownership, copyright, trademark or other property right
+connected with the Licensed Software. Licensee may not distribute any
+software statically or dynamically linked with the Licensed Software.
+
+4.3 No Technical Support
+
+Nokia has no obligation to furnish Licensee with any technical support
+whatsoever. Any such support is subject to separate agreement between
+the Parties.
+
+
+5. PRE-RELEASE CODE
+
+The Licensed Software contains pre-release code that is not at the level
+of performance and compatibility of a final, generally available,
+product offering. The Licensed Software may not operate correctly and
+may be substantially modified prior to the first commercial product
+release, if any. Nokia is not obligated to make this or any later
+version of the Licensed Software commercially available. The License
+Software is "Not for Commercial Use" and may only be used for the
+purposes described in Section 4. The Licensed Software may not be used
+in a live operating environment where it may be relied upon to perform
+in the same manner as a commercially released product or with data that
+has not been sufficiently backed up.
+
+6. THIRD PARTY SOFTWARE
+
+The Licensed Software may provide links to third party libraries or code
+(collectively "Third Party Software") to implement various functions.
+Third Party Software does not comprise part of the Licensed Software. In
+some cases, access to Third Party Software may be included along with
+the Licensed Software delivery as a convenience for development and
+testing only. Such source code and libraries may be listed in the
+".../src/3rdparty" source tree delivered with the Licensed Software or
+documented in the Licensed Software where the Third Party Software is
+used, as may be amended from time to time, do not comprise the Licensed
+Software. Licensee acknowledges (1) that some part of Third Party
+Software may require additional licensing of copyright and patents from
+the owners of such, and (2) that distribution of any of the Licensed
+Software referencing any portion of a Third Party Software may require
+appropriate licensing from such third parties.
+
+
+7. LIMITED WARRANTY AND WARRANTY DISCLAIMER
+
+The Licensed Software is licensed to Licensee "as is". To the maximum
+extent permitted by applicable law, Nokia on behalf of itself and its
+suppliers, disclaims all warranties and conditions, either express or
+implied, including, but not limited to, implied warranties of
+merchantability, fitness for a particular purpose, title and
+non-infringement with regard to the Licensed Software.
+
+
+8. LIMITATION OF LIABILITY
+
+If, Nokia's warranty disclaimer notwithstanding, Nokia is held liable to
+Licensee, whether in contract, tort or any other legal theory, based on
+the Licensed Software, Nokia's entire liability to Licensee and
+Licensee's exclusive remedy shall be, at Nokia's option, either (A)
+return of the price Licensee paid for the Licensed Software, or (B)
+repair or replacement of the Licensed Software, provided Licensee
+returns to Nokia all copies of the Licensed Software as originally
+delivered to Licensee. Nokia shall not under any circumstances be liable
+to Licensee based on failure of the Licensed Software if the failure
+resulted from accident, abuse or misapplication, nor shall Nokia under
+any circumstances be liable for special damages, punitive or exemplary
+damages, damages for loss of profits or interruption of business or for
+loss or corruption of data. Any award of damages from Nokia to Licensee
+shall not exceed the total amount Licensee has paid to Nokia in
+connection with this Agreement.
+
+
+9. CONFIDENTIALITY
+
+Each party acknowledges that during the Term of this Agreement it shall
+have access to information about the other party's business, business
+methods, business plans, customers, business relations, technology, and
+other information, including the terms of this Agreement, that is
+confidential and of great value to the other party, and the value of
+which would be significantly reduced if disclosed to third parties (the
+"Confidential Information"). Accordingly, when a party (the "Receiving
+Party") receives Confidential Information from another party (the
+"Disclosing Party"), the Receiving Party shall, and shall obligate its
+employees and agents and employees and agents of its Affiliates to: (i)
+maintain the Confidential Information in strict confidence; (ii) not
+disclose the Confidential Information to a third party without the
+Disclosing Party's prior written approval; and (iii) not, directly or
+indirectly, use the Confidential Information for any purpose other than
+for exercising its rights and fulfilling its responsibilities pursuant
+to this Agreement. Each party shall take reasonable measures to protect
+the Confidential Information of the other party, which measures shall
+not be less than the measures taken by such party to protect its own
+confidential and proprietary information.
+
+"Confidential Information" shall not include information that (a) is or
+becomes generally known to the public through no act or omission of the
+Receiving Party; (b) was in the Receiving Party's lawful possession
+prior to the disclosure hereunder and was not subject to limitations on
+disclosure or use; (c) is developed by the Receiving Party without
+access to the Confidential Information of the Disclosing Party or by
+persons who have not had access to the Confidential Information of the
+Disclosing Party as proven by the written records of the Receiving
+Party; (d) is lawfully disclosed to the Receiving Party without
+restrictions, by a third party not under an obligation of
+confidentiality; or (e) the Receiving Party is legally compelled to
+disclose the information, in which case the Receiving Party shall assert
+the privileged and confidential nature of the information and cooperate
+fully with the Disclosing Party to protect against and prevent
+disclosure of any Confidential Information and to limit the scope of
+disclosure and the dissemination of disclosed Confidential Information
+by all legally available means.
+
+The obligations of the Receiving Party under this Section shall continue
+during the Initial Term and for a period of five (5) years after
+expiration or termination of this Agreement. To the extent that the
+terms of the Non-Disclosure Agreement between Nokia and Licensee
+conflict with the terms of this Section 8, this Section 8 shall be
+controlling over the terms of the Non-Disclosure Agreement.
+
+
+10. GENERAL PROVISIONS
+
+10.1 No Assignment
+
+Licensee shall not be entitled to assign or transfer all or any of its
+rights, benefits and obligations under this Agreement without the prior
+written consent of Nokia, which shall not be unreasonably withheld.
+
+10.2 Termination
+
+Nokia may terminate the Agreement at any time immediately upon written
+notice by Nokia to Licensee if Licensee breaches this Agreement.
+
+Upon termination of this Agreement, Licensee shall return to Nokia all
+copies of Licensed Software that were supplied by Nokia. All other
+copies of Licensed Software in the possession or control of Licensee
+must be erased or destroyed. An officer of Licensee must promptly
+deliver to Nokia a written confirmation that this has occurred.
+
+10.3 Surviving Sections
+
+Any terms and conditions that by their nature or otherwise reasonably
+should survive a cancellation or termination of this Agreement shall
+also be deemed to survive. Such terms and conditions include, but are
+not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4,
+10.5, 10.6, 10.7, and 10.8 of this Agreement.
+
+10.4 Entire Agreement
+
+This Agreement constitutes the complete agreement between the parties
+and supersedes all prior or contemporaneous discussions,
+representations, and proposals, written or oral, with respect to the
+subject matters discussed herein, with the exception of the
+non-disclosure agreement executed by the parties in connection with this
+Agreement ("Non-Disclosure Agreement"), if any, shall be subject to
+Section 8. No modification of this Agreement shall be effective unless
+contained in a writing executed by an authorized representative of each
+party. No term or condition contained in Licensee's purchase order shall
+apply unless expressly accepted by Nokia in writing. If any provision of
+the Agreement is found void or unenforceable, the remainder shall remain
+valid and enforceable according to its terms. If any remedy provided is
+determined to have failed for its essential purpose, all limitations of
+liability and exclusions of damages set forth in this Agreement shall
+remain in effect.
+
+10.5 Export Control
+
+Licensee acknowledges that the Licensed Software may be subject to
+export control restrictions of various countries. Licensee shall fully
+comply with all applicable export license restrictions and requirements
+as well as with all laws and regulations relating to the importation of
+the Licensed Software and shall procure all necessary governmental
+authorizations, including without limitation, all necessary licenses,
+approvals, permissions or consents, where necessary for the
+re-exportation of the Licensed Software.,
+
+10.6 Governing Law and Legal Venue
+
+This Agreement shall be construed and interpreted in accordance with the
+laws of Finland, excluding its choice of law provisions. Any disputes
+arising out of or relating to this Agreement shall be resolved in
+arbitration under the Rules of Arbitration of the Chamber of Commerce of
+Helsinki, Finland. The arbitration tribunal shall consist of one (1), or
+if either Party so requires, of three (3), arbitrators. The award shall
+be final and binding and enforceable in any court of competent
+jurisdiction. The arbitration shall be held in Helsinki, Finland and the
+process shall be conducted in the English language.
+
+10.7 No Implied License
+
+There are no implied licenses or other implied rights granted under this
+Agreement, and all rights, save for those expressly granted hereunder,
+shall remain with Nokia and its licensors. In addition, no licenses or
+immunities are granted to the combination of the Licensed Software with
+any other software or hardware not delivered by Nokia under this
+Agreement.
+
+10.8 Government End Users
+
+A "U.S. Government End User" shall mean any agency or entity of the
+government of the United States. The following shall apply if Licensee
+is a U.S. Government End User. The Licensed Software is a "commercial
+item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995),
+consisting of "commercial computer software" and "commercial computer
+software documentation," as such terms are used in 48 C.F.R. 12.212
+(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
+through 227.7202-4 (June 1995), all U.S. Government End Users acquire
+the Licensed Software with only those rights set forth herein. The
+Licensed Software (including related documentation) is provided to U.S.
+Government End Users: (a) only as a commercial end item; and (b) only
+pursuant to this Agreement.
diff --git a/bin/runInTerminal.command b/bin/runInTerminal.command
new file mode 100755
index 0000000000..89195e3d10
--- /dev/null
+++ b/bin/runInTerminal.command
@@ -0,0 +1,7 @@
+#!/bin/bash
+osascript >/dev/null 2>&1 <<EOF
+ tell application "Terminal"
+ activate
+ do script with command "$@; exit"
+ end tell
+EOF
diff --git a/bin/schemes/MS_Visual_C++.kms b/bin/schemes/MS_Visual_C++.kms
new file mode 100644
index 0000000000..696b96bb42
--- /dev/null
+++ b/bin/schemes/MS_Visual_C++.kms
@@ -0,0 +1,495 @@
+<!DOCTYPE KeyboardMappingScheme>
+<mapping>
+ <shortcut id="Debugger.JumpToLine" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.ToggleBreak" >
+ <key value="F9" />
+ </shortcut>
+ <shortcut id="Debugger.BreakByFunction" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.BreakAtMain" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.SkipKnownFrames" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.UseCustomDumpers" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.UseFastStart" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.AddToWatch" >
+ <key value="Alt+D, Alt+W" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.GdbDebugger.Mode.Debug" >
+ <key value="Ctrl+3" />
+ </shortcut>
+ <shortcut id="Qt Script Editor.Run" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FindFilter.Files on Disk" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FindFilter.All Projects" >
+ <key value="Ctrl+Shift+F" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.TaskList" >
+ <key value="Alt+1" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.SearchResults" >
+ <key value="Alt+2" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.ApplicationOutput" >
+ <key value="Alt+3" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.Compile" >
+ <key value="Alt+4" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.Perforce" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.General" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.Edit.Delete" >
+ <key value="Del" />
+ </shortcut>
+ <shortcut id="FormEditor.WidgetEditor" >
+ <key value="F3" />
+ </shortcut>
+ <shortcut id="FormEditor.SignalsSlotsEditor" >
+ <key value="F4" />
+ </shortcut>
+ <shortcut id="FormEditor.BuddyEditor" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.TabOrderEditor" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutHorizontally" >
+ <key value="Ctrl+H" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutVertically" >
+ <key value="Ctrl+L" />
+ </shortcut>
+ <shortcut id="FormEditor.SplitHorizontal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.SplitVertical" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutForm" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutGrid" >
+ <key value="Ctrl+G" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutBreak" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutAdjustSize" >
+ <key value="Ctrl+J" />
+ </shortcut>
+ <shortcut id="FormEditor.SimplifyLayout" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.ReturnToEditor" >
+ <key value="Esc" />
+ </shortcut>
+ <shortcut id="QtCreator.New" >
+ <key value="Ctrl+N" />
+ </shortcut>
+ <shortcut id="FormEditor.Lower" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Open" >
+ <key value="Ctrl+O" />
+ </shortcut>
+ <shortcut id="FormEditor.Raise" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.OpenWith" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.Preview" >
+ <key value="Ctrl+Alt+R" />
+ </shortcut>
+ <shortcut id="QtCreator.Save" >
+ <key value="Ctrl+S" />
+ </shortcut>
+ <shortcut id="QtCreator.SaveAs" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.SaveAll" >
+ <key value="Ctrl+Shift+S" />
+ </shortcut>
+ <shortcut id="QtCreator.Print" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Exit" >
+ <key value="Ctrl+Q" />
+ </shortcut>
+ <shortcut id="QtCreator.Undo" >
+ <key value="Ctrl+Z" />
+ </shortcut>
+ <shortcut id="QtCreator.Redo" >
+ <key value="Ctrl+Shift+Z" />
+ </shortcut>
+ <shortcut id="QtCreator.Cut" >
+ <key value="Ctrl+X" />
+ </shortcut>
+ <shortcut id="QtCreator.Copy" >
+ <key value="Ctrl+C" />
+ </shortcut>
+ <shortcut id="QtCreator.Paste" >
+ <key value="Ctrl+V" />
+ </shortcut>
+ <shortcut id="QtCreator.SelectAll" >
+ <key value="Ctrl+A" />
+ </shortcut>
+ <shortcut id="QtCreator.Goto" >
+ <key value="Ctrl+G" />
+ </shortcut>
+ <shortcut id="QtCreator.Options" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.ToggleSidebar" >
+ <key value="Alt+0" />
+ </shortcut>
+ <shortcut id="QtCreator.AboutWorkbench" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.AboutPlugins" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.RevertToSaved" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Windows" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Motif" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.CDE" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Plastique" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Cleanlooks" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.ViewCode" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.FormSettings" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Close" >
+ <key value="Ctrl+W" />
+ </shortcut>
+ <shortcut id="QtCreator.CloseAll" >
+ <key value="Ctrl+Shift+W" />
+ </shortcut>
+ <shortcut id="QtCreator.DuplicateDocument" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoPreviousInHistory" >
+ <key value="Ctrl+Tab" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoNextInHistory" >
+ <key value="Ctrl+Shift+Tab" />
+ </shortcut>
+ <shortcut id="QtCreator.Horizontal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Vertical" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Remove" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.SaveAsDefaultLayout" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.RestoreDefaultLayout" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoPreviousTabGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoNextTabGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.DocumentToPreviousGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.DocumentToNextGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.QtCreator.Mode.Output" >
+ <key value="Ctrl+6" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.QtCreator.Mode.Welcome" >
+ <key value="Ctrl+1" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.QtCreator.Mode.Edit" >
+ <key value="Ctrl+2" />
+ </shortcut>
+ <shortcut id="Find.FindInCurrentDocument" >
+ <key value="Ctrl+F" />
+ </shortcut>
+ <shortcut id="Find.FindNext" >
+ <key value="F3" />
+ </shortcut>
+ <shortcut id="Find.FindPrevious" >
+ <key value="Shift+F3" />
+ </shortcut>
+ <shortcut id="Find.ReplaceNext" >
+ <key value="Ctrl+=" />
+ </shortcut>
+ <shortcut id="Find.ReplacePrevious" >
+ <key value="Ctrl+Shift+=" />
+ </shortcut>
+ <shortcut id="Find.ReplaceAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Find.CaseSensitive" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Find.WholeWords" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.View.QuickOpen.ToolWindow" >
+ <key value="Ctrl+D" />
+ </shortcut>
+ <shortcut id="Help.Home" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Previous" >
+ <key value="Backspace" />
+ </shortcut>
+ <shortcut id="Help.Next" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.AddBookmark" >
+ <key value="Ctrl+M" />
+ </shortcut>
+ <shortcut id="Help.Index" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Contents" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Search" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Context" >
+ <key value="F1" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.Help.HelpMode" >
+ <key value="Ctrl+5" />
+ </shortcut>
+ <shortcut id="Help.IndexShortcut" >
+ <key value="Ctrl+I" />
+ </shortcut>
+ <shortcut id="Help.ContentsShortcut" >
+ <key value="Ctrl+T" />
+ </shortcut>
+ <shortcut id="Help.SearchShortcut" >
+ <key value="Ctrl+S" />
+ </shortcut>
+ <shortcut id="TextEditor.CompleteThis" >
+ <key value="Ctrl+Space" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.ProjectExplorer.Mode.Session" >
+ <key value="Ctrl+4" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.NewSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.NewProject" >
+ <key value="Ctrl+Shift+N" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Load" >
+ <key value="Ctrl+Shift+O" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.OpenFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Unload" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.ClearSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.BuildSession" >
+ <key value="F7" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.RebuildSession" >
+ <key value="Ctrl+Shift+F7" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.CleanSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Build" >
+ <key value="Ctrl+Shift+B" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Rebuild" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Clean" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Run" >
+ <key value="Ctrl+F5" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.GoToTaskWindow" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.CancelBuild" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Debug" >
+ <key value="F5" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Dependencies" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.AddNewFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.AddExistingFiles" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.RemoveFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.RenameFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.Toggle" >
+ <key value="Ctrl+K, Ctrl+K" />
+ </shortcut>
+ <shortcut id="Bookmarks.MoveUp" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.MoveDown" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.Previous" >
+ <key value="Shift+F2" />
+ </shortcut>
+ <shortcut id="Bookmarks.Next" >
+ <key value="F2" />
+ </shortcut>
+ <shortcut id="Bookmarks.Previous.Document" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.Next.Document" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="CppTools.SwitchHeaderSource" >
+ <key value="F4" />
+ </shortcut>
+ <shortcut id="CppEditor.JumpToDefinition" >
+ <key value="Ctrl+F12" />
+ </shortcut>
+ <shortcut id="CppEditor.SwitchDeclarationDefinition" >
+ <key value="Ctrl+Shift+F12" />
+ </shortcut>
+ <shortcut id="Qt4Builder.RunQMake" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Qt4Builder.RunQMakeContextMenu" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Edit" >
+ <key value="Alt+P, Alt+E" />
+ </shortcut>
+ <shortcut id="Perforce.Add" >
+ <key value="Alt+P, Alt+A" />
+ </shortcut>
+ <shortcut id="Perforce.Delete" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Revert" >
+ <key value="Alt+P, Alt+R" />
+ </shortcut>
+ <shortcut id="Perforce.DiffCurrent" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.DiffProject" >
+ <key value="Alt+P, Alt+D" />
+ </shortcut>
+ <shortcut id="Perforce.DiffAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Opened" >
+ <key value="Alt+P, Alt+O" />
+ </shortcut>
+ <shortcut id="Perforce.Submit" >
+ <key value="Alt+P, Alt+S" />
+ </shortcut>
+ <shortcut id="Perforce.PendingChanges" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Describe" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.AnnotateCurrent" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Annotate" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.FilelogCurrent" >
+ <key value="Alt+P, Alt+F" />
+ </shortcut>
+ <shortcut id="Perforce.Filelog" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Nokia.Perforce.SubmitCurrentLog" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Nokia.Perforce.DiffSelectedFilesInLog" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.StartExternal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.AttachExternal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.Interrupt" >
+ <key value="Shift+F5" />
+ </shortcut>
+ <shortcut id="Debugger.Reset" >
+ <key value="Ctrl+Shift+F5" />
+ </shortcut>
+ <shortcut id="Debugger.NextLine" >
+ <key value="F10" />
+ </shortcut>
+ <shortcut id="Debugger.StepLine" >
+ <key value="F11" />
+ </shortcut>
+ <shortcut id="Debugger.StepOut" >
+ <key value="Shift+F11" />
+ </shortcut>
+ <shortcut id="Debugger.NextInstruction" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.StepInstruction" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.RunToLine" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.RunToFunction" >
+ <key value="" />
+ </shortcut>
+</mapping>
diff --git a/bin/schemes/Xcode.kms b/bin/schemes/Xcode.kms
new file mode 100644
index 0000000000..30653822df
--- /dev/null
+++ b/bin/schemes/Xcode.kms
@@ -0,0 +1,585 @@
+<!DOCTYPE KeyboardMappingScheme>
+<mapping>
+ <shortcut id="QtCreator.ReturnToEditor" >
+ <key value="Esc" />
+ </shortcut>
+ <shortcut id="QtCreator.New" >
+ <key value="Ctrl+N" />
+ </shortcut>
+ <shortcut id="QtCreator.Open" >
+ <key value="Ctrl+O" />
+ </shortcut>
+ <shortcut id="QtCreator.OpenWith" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Save" >
+ <key value="Ctrl+S" />
+ </shortcut>
+ <shortcut id="QtCreator.SaveAs" >
+ <key value="Ctrl+Shift+S" />
+ </shortcut>
+ <shortcut id="QtCreator.SaveAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Print" >
+ <key value="Ctrl+P" />
+ </shortcut>
+ <shortcut id="QtCreator.Exit" >
+ <key value="Ctrl+Q" />
+ </shortcut>
+ <shortcut id="QtCreator.Undo" >
+ <key value="Ctrl+Z" />
+ </shortcut>
+ <shortcut id="QtCreator.Redo" >
+ <key value="Ctrl+Shift+Z" />
+ </shortcut>
+ <shortcut id="QtCreator.Cut" >
+ <key value="Ctrl+X" />
+ </shortcut>
+ <shortcut id="QtCreator.Copy" >
+ <key value="Ctrl+C" />
+ </shortcut>
+ <shortcut id="QtCreator.Paste" >
+ <key value="Ctrl+V" />
+ </shortcut>
+ <shortcut id="QtCreator.SelectAll" >
+ <key value="Ctrl+A" />
+ </shortcut>
+ <shortcut id="QtCreator.Goto" >
+ <key value="Ctrl+L" />
+ </shortcut>
+ <shortcut id="QtCreator.Options" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.MinimizeWindow" >
+ <key value="Ctrl+M" />
+ </shortcut>
+ <shortcut id="QtCreator.ZoomWindow" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.ToggleSidebar" >
+ <key value="Ctrl+0" />
+ </shortcut>
+ <shortcut id="QtCreator.AboutWorkbench" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.AboutPlugins" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.RevertToSaved" >
+ <key value="Ctrl+U" />
+ </shortcut>
+ <shortcut id="QtCreator.Close" >
+ <key value="Ctrl+Shift+W" />
+ </shortcut>
+ <shortcut id="QtCreator.CloseAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.DuplicateDocument" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoPreviousInHistory" >
+ <key value="Alt+Tab" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoNextInHistory" >
+ <key value="Alt+Shift+Tab" />
+ </shortcut>
+ <shortcut id="QtCreator.GoBack" >
+ <key value="Ctrl+Alt+Left" />
+ </shortcut>
+ <shortcut id="QtCreator.Horizontal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Vertical" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Remove" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.SaveAsDefaultLayout" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.RestoreDefaultLayout" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoPreviousTabGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.GotoNextTabGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.DocumentToPreviousGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.DocumentToNextGroup" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.QtCreator.Mode.Output" >
+ <key value="Meta+6" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.QtCreator.Mode.Welcome" >
+ <key value="Meta+1" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.QtCreator.Mode.Edit" >
+ <key value="Meta+2" />
+ </shortcut>
+ <shortcut id="Find.FindInCurrentDocument" >
+ <key value="Ctrl+F" />
+ </shortcut>
+ <shortcut id="Find.EnterFindString" >
+ <key value="Ctrl+E" />
+ </shortcut>
+ <shortcut id="Find.FindNext" >
+ <key value="Ctrl+G" />
+ </shortcut>
+ <shortcut id="Find.FindPrevious" >
+ <key value="Ctrl+Shift+G" />
+ </shortcut>
+ <shortcut id="Find.ReplaceNext" >
+ <key value="Ctrl+=" />
+ </shortcut>
+ <shortcut id="Find.ReplacePrevious" >
+ <key value="Ctrl+Shift+=" />
+ </shortcut>
+ <shortcut id="Find.ReplaceAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Find.CaseSensitive" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Find.WholeWords" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.View.QuickOpen.ToolWindow" >
+ <key value="Ctrl+Shift+D" />
+ </shortcut>
+ <shortcut id="TextEditor.CompleteThis" >
+ <key value="Alt+Esc" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.ProjectExplorer.Mode.Session" >
+ <key value="Meta+4" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.NewSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.NewProject" >
+ <key value="Ctrl+Shift+N" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Load" >
+ <key value="Ctrl+Shift+O" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.OpenFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Unload" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.ClearSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.BuildSession" >
+ <key value="Ctrl+B" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.RebuildSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.CleanSession" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Build" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Rebuild" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Clean" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Run" >
+ <key value="Ctrl+R" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.GoToTaskWindow" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.CancelBuild" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Debug" >
+ <key value="Ctrl+Y" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.Dependencies" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.AddNewFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.AddExistingFiles" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.RemoveFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="ProjectExplorer.RenameFile" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="CppTools.SwitchHeaderSource" >
+ <key value="Ctrl+Alt+Up" />
+ </shortcut>
+ <shortcut id="CppEditor.JumpToDefinition" >
+ <key value="F2" />
+ </shortcut>
+ <shortcut id="CppEditor.SwitchDeclarationDefinition" >
+ <key value="Shift+F2" />
+ </shortcut>
+ <shortcut id="FormEditor.Edit.Delete" >
+ <key value="Del" />
+ </shortcut>
+ <shortcut id="FormEditor.WidgetEditor" >
+ <key value="F3" />
+ </shortcut>
+ <shortcut id="FormEditor.SignalsSlotsEditor" >
+ <key value="F4" />
+ </shortcut>
+ <shortcut id="FormEditor.BuddyEditor" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.TabOrderEditor" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutHorizontally" >
+ <key value="Ctrl+H" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutVertically" >
+ <key value="Ctrl+L" />
+ </shortcut>
+ <shortcut id="FormEditor.SplitHorizontal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.SplitVertical" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutForm" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutGrid" >
+ <key value="Ctrl+G" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutBreak" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.LayoutAdjustSize" >
+ <key value="Ctrl+J" />
+ </shortcut>
+ <shortcut id="FormEditor.SimplifyLayout" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.Lower" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.Raise" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.Preview" >
+ <key value="Ctrl+Alt+R" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Windows" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Motif" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.CDE" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Plastique" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Cleanlooks" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Formeditor.Menu.Preview.Macintosh (aqua)" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FormEditor.FormSettings" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.Diff" >
+ <key value="Alt+G, Alt+D" />
+ </shortcut>
+ <shortcut id="Git.Status" >
+ <key value="Alt+G, Alt+S" />
+ </shortcut>
+ <shortcut id="Git.Log" >
+ <key value="Alt+G, Alt+L" />
+ </shortcut>
+ <shortcut id="Git.Blame" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.Undo" >
+ <key value="Alt+G, Alt+U" />
+ </shortcut>
+ <shortcut id="Git.Add" >
+ <key value="Alt+G, Alt+A" />
+ </shortcut>
+ <shortcut id="Git.DiffProject" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.StatusProject" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.LogProject" >
+ <key value="Alt+G, Alt+K" />
+ </shortcut>
+ <shortcut id="Git.UndoProject" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.ShowCommit" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.Commit" >
+ <key value="Alt+G, Alt+C" />
+ </shortcut>
+ <shortcut id="Git.Pull" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Git.Push" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Home" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Previous" >
+ <key value="Backspace" />
+ </shortcut>
+ <shortcut id="Help.Next" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.AddBookmark" >
+ <key value="Ctrl+D" />
+ </shortcut>
+ <shortcut id="Help.Index" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Contents" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Search" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Help.Context" >
+ <key value="F1" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.Help.HelpMode" >
+ <key value="Meta+5" />
+ </shortcut>
+ <shortcut id="Help.IndexShortcut" >
+ <key value="Ctrl+I" />
+ </shortcut>
+ <shortcut id="Help.ContentsShortcut" >
+ <key value="Ctrl+T" />
+ </shortcut>
+ <shortcut id="Help.SearchShortcut" >
+ <key value="Ctrl+S" />
+ </shortcut>
+ <shortcut id="Qt4Builder.RunQMake" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Qt4Builder.RunQMakeContextMenu" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Qt Script Editor.Run" >
+ <key value="Ctrl+R" />
+ </shortcut>
+ <shortcut id="CodePaster.post" >
+ <key value="Alt+C, Alt+P" />
+ </shortcut>
+ <shortcut id="CodePaster.fetch" >
+ <key value="Alt+C, Alt+F" />
+ </shortcut>
+ <shortcut id="Debugger.StartExternal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.AttachExternal" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.Interrupt" >
+ <key value="Ctrl+Alt+P" />
+ </shortcut>
+ <shortcut id="Debugger.Reset" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.NextLine" >
+ <key value="Ctrl+Shift+O" />
+ </shortcut>
+ <shortcut id="Debugger.StepLine" >
+ <key value="Ctrl+Shift+I" />
+ </shortcut>
+ <shortcut id="Debugger.StepOut" >
+ <key value="Ctrl+Shift+T" />
+ </shortcut>
+ <shortcut id="Debugger.NextInstruction" >
+ <key value="Ctrl+Alt+Shift+O" />
+ </shortcut>
+ <shortcut id="Debugger.StepInstruction" >
+ <key value="Ctrl+Alt+Shift+I" />
+ </shortcut>
+ <shortcut id="Debugger.RunToLine" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.RunToFunction" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.JumpToLine" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.ToggleBreak" >
+ <key value="Ctrl+\" />
+ </shortcut>
+ <shortcut id="Debugger.BreakByFunction" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.BreakAtMain" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.SkipKnownFrames" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.UseCustomDumpers" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.UseFastStart" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Debugger.DumpLog" >
+ <key value="Ctrl+Shift+F11" />
+ </shortcut>
+ <shortcut id="Debugger.AddToWatch" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Mode.Debugger.Mode.Debug" >
+ <key value="Meta+3" />
+ </shortcut>
+ <shortcut id="Perforce.Edit" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Add" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Delete" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Revert" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.DiffCurrent" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.DiffProject" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.DiffAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Opened" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Submit" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.PendingChanges" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Describe" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.AnnotateCurrent" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Annotate" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.FilelogCurrent" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Perforce.Filelog" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Nokia.Perforce.SubmitCurrentLog" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Nokia.Perforce.DiffSelectedFilesInLog" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.Toggle" >
+ <key value="Ctrl+D" />
+ </shortcut>
+ <shortcut id="Bookmarks.MoveUp" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.MoveDown" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.Previous" >
+ <key value="Meta+," />
+ </shortcut>
+ <shortcut id="Bookmarks.Next" >
+ <key value="Meta+." />
+ </shortcut>
+ <shortcut id="Bookmarks.Previous.Document" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="Bookmarks.Next.Document" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="TextEditor.SelectEncoding" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="TextEditor.AutoIndentSelection" >
+ <key value="Ctrl+I" />
+ </shortcut>
+ <shortcut id="TextEditor.VisualizeWhitespace" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="TextEditor.TextWrapping" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="TextEditor.UnCommentSelection" >
+ <key value="Ctrl+/" />
+ </shortcut>
+ <shortcut id="TextEditor.DeleteLine" >
+ <key value="Shift+Del" />
+ </shortcut>
+ <shortcut id="TextEditor.UnCollapseAll" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FindFilter.Files on Disk" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="FindFilter.All Projects" >
+ <key value="Ctrl+Shift+F" />
+ </shortcut>
+ <shortcut id="FindFilter.Current Project" >
+ <key value="Ctrl+Alt+F" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.Problems" >
+ <key value="Ctrl+1" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.SearchResults" >
+ <key value="Ctrl+2" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.ApplicationOutput" >
+ <key value="Ctrl+3" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.Compile" >
+ <key value="Ctrl+4" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.Git" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.Perforce" >
+ <key value="" />
+ </shortcut>
+ <shortcut id="QtCreator.Pane.General" >
+ <key value="" />
+ </shortcut>
+</mapping>
diff --git a/bin/snippets/class_generic.snp b/bin/snippets/class_generic.snp
new file mode 100644
index 0000000000..1f196c3dac
--- /dev/null
+++ b/bin/snippets/class_generic.snp
@@ -0,0 +1,26 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >Class - Generic</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates a new generic class</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Classes</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >cl</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[class $anchor$MyClass$cursor$
+{
+ $selection$
+};]]></value>
+ </data>
+</qtworkbench> \ No newline at end of file
diff --git a/bin/snippets/class_qobject.snp b/bin/snippets/class_qobject.snp
new file mode 100644
index 0000000000..784233e546
--- /dev/null
+++ b/bin/snippets/class_qobject.snp
@@ -0,0 +1,29 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >Class - QObject</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates a new class deriving from QObject</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Classes</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >cl</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[class $anchor$MyClass$cursor$ : public QObject
+{
+ Q_OBJECT
+
+public:
+ $selection$
+};]]></value>
+ </data>
+</qtworkbench>
diff --git a/bin/snippets/class_qwidget.snp b/bin/snippets/class_qwidget.snp
new file mode 100644
index 0000000000..1edb2d2cc7
--- /dev/null
+++ b/bin/snippets/class_qwidget.snp
@@ -0,0 +1,29 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >Class - QWidget</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates a new class deriving from QWidget</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Classes</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >cl</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[class $anchor$MyClass$cursor$ : public QWidget
+{
+ Q_OBJECT
+
+public:
+ $selection$
+};]]></value>
+ </data>
+</qtworkbench> \ No newline at end of file
diff --git a/bin/snippets/comment.snp b/bin/snippets/comment.snp
new file mode 100644
index 0000000000..bd909a7e7a
--- /dev/null
+++ b/bin/snippets/comment.snp
@@ -0,0 +1,23 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >/* ... */ Comment</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates comment</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Other</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >/*</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[/* $anchor$$selection$$cursor$ */]]></value>
+ </data>
+</qtworkbench>
diff --git a/bin/snippets/for.snp b/bin/snippets/for.snp
new file mode 100644
index 0000000000..16aa633faf
--- /dev/null
+++ b/bin/snippets/for.snp
@@ -0,0 +1,48 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >for loop</value>
+ </data>
+
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This inserts an incrementing for loop</value>
+ </data>
+
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Common Statements</value>
+ </data>
+
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >fo</value>
+ </data>
+
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[for (%1 %2 = 0; %2 < %3; ++%2) {
+ $anchor$$selection$$cursor$
+}]]></value>
+ </data>
+
+ <data>
+ <variable>Arguments</variable>
+ <valuemap type="QVariantMap" >
+ <value key="1" type="QString"><![CDATA[<tt>for (<b>TYPE</b> VAR = 0; VAR &lt; CONDITION; ++VAR)...</tt>]]></value>
+ <value key="2" type="QString"><![CDATA[<tt>for (%1 <b>VAR</b> = 0; <b>VAR</b> &lt; 10; ++<b>VAR</b>)...</tt>]]></value>
+ <value key="3" type="QString"><![CDATA[<tt>for (%1 %2 = 0; %2 &lt; <b>CONDITION</b>; ++%2)...</tt>]]></value>
+ </valuemap>
+ </data>
+
+ <data>
+ <variable>ArgumentDefaults</variable>
+ <valuemap type="QVariantMap" >
+ <value key="1" type="QString">int</value>
+ <value key="2" type="QString">i</value>
+ </valuemap>
+ </data>
+
+</qtworkbench> \ No newline at end of file
diff --git a/bin/snippets/foreach.snp b/bin/snippets/foreach.snp
new file mode 100644
index 0000000000..c00beb99e5
--- /dev/null
+++ b/bin/snippets/foreach.snp
@@ -0,0 +1,25 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >foreach statement</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates a foreach statement</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Common Statements</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >fo</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[foreach ($cursor$) {
+ $selection$
+}]]></value>
+ </data>
+</qtworkbench>
diff --git a/bin/snippets/if.snp b/bin/snippets/if.snp
new file mode 100644
index 0000000000..2888590efa
--- /dev/null
+++ b/bin/snippets/if.snp
@@ -0,0 +1,25 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >if Statement</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates a if statement</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Common Statements</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >if</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[if ($cursor$) {
+ $selection$
+}]]></value>
+ </data>
+</qtworkbench>
diff --git a/bin/snippets/ifelse.snp b/bin/snippets/ifelse.snp
new file mode 100644
index 0000000000..39428555ca
--- /dev/null
+++ b/bin/snippets/ifelse.snp
@@ -0,0 +1,27 @@
+<!DOCTYPE QtWorkbenchSnippet>
+<qtworkbench>
+ <data>
+ <variable>Name</variable>
+ <value type="QString" >if - else Statement</value>
+ </data>
+ <data>
+ <variable>Description</variable>
+ <value type="QString" >This creates a if...else statement</value>
+ </data>
+ <data>
+ <variable>Category</variable>
+ <value type="QString" >Common Statements</value>
+ </data>
+ <data>
+ <variable>Shortcut</variable>
+ <value type="QString" >if</value>
+ </data>
+ <data>
+ <variable>Contents</variable>
+ <value type="QString" ><![CDATA[if ($cursor$) {
+ $selection$
+} else {
+
+}]]></value>
+ </data>
+</qtworkbench>
diff --git a/bin/templates/qt4project/main.cpp b/bin/templates/qt4project/main.cpp
new file mode 100644
index 0000000000..e1e39f6f26
--- /dev/null
+++ b/bin/templates/qt4project/main.cpp
@@ -0,0 +1,10 @@
+#include <%QAPP_INCLUDE%>
+#include "%INCLUDE%"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ %CLASS% w;
+ w.show();
+ return a.exec();
+}
diff --git a/bin/templates/qt4project/mywidget.cpp b/bin/templates/qt4project/mywidget.cpp
new file mode 100644
index 0000000000..ae355e98dd
--- /dev/null
+++ b/bin/templates/qt4project/mywidget.cpp
@@ -0,0 +1,11 @@
+#include "%INCLUDE%"
+
+%CLASS%::%CLASS%(QWidget *parent)
+ : %BASECLASS%(parent)
+{
+}
+
+%CLASS%::~%CLASS%()
+{
+
+}
diff --git a/bin/templates/qt4project/mywidget.h b/bin/templates/qt4project/mywidget.h
new file mode 100644
index 0000000000..88ee4d9506
--- /dev/null
+++ b/bin/templates/qt4project/mywidget.h
@@ -0,0 +1,15 @@
+#ifndef %PRE_DEF%
+#define %PRE_DEF%
+
+#include <QtGui/%BASECLASS%>
+
+class %CLASS% : public %BASECLASS%
+{
+ Q_OBJECT
+
+public:
+ %CLASS%(QWidget *parent = 0);
+ ~%CLASS%();
+};
+
+#endif // %PRE_DEF%
diff --git a/bin/templates/qt4project/mywidget_form.cpp b/bin/templates/qt4project/mywidget_form.cpp
new file mode 100644
index 0000000000..33b14afab8
--- /dev/null
+++ b/bin/templates/qt4project/mywidget_form.cpp
@@ -0,0 +1,13 @@
+#include "%INCLUDE%"
+#include "%UI_HDR%"
+
+%CLASS%::%CLASS%(QWidget *parent)
+ : %BASECLASS%(parent), ui(new Ui::%CLASS%Class)
+{
+ ui->setupUi(this);
+}
+
+%CLASS%::~%CLASS%()
+{
+ delete ui;
+}
diff --git a/bin/templates/qt4project/mywidget_form.h b/bin/templates/qt4project/mywidget_form.h
new file mode 100644
index 0000000000..fd4d373277
--- /dev/null
+++ b/bin/templates/qt4project/mywidget_form.h
@@ -0,0 +1,23 @@
+#ifndef %PRE_DEF%
+#define %PRE_DEF%
+
+#include <QtGui/%BASECLASS%>
+
+namespace Ui
+{
+ class %CLASS%Class;
+}
+
+class %CLASS% : public %BASECLASS%
+{
+ Q_OBJECT
+
+public:
+ %CLASS%(QWidget *parent = 0);
+ ~%CLASS%();
+
+private:
+ Ui::%CLASS%Class *ui;
+};
+
+#endif // %PRE_DEF%
diff --git a/bin/templates/qt4project/widget.ui b/bin/templates/qt4project/widget.ui
new file mode 100644
index 0000000000..6c78aeebc4
--- /dev/null
+++ b/bin/templates/qt4project/widget.ui
@@ -0,0 +1,23 @@
+<ui version="4.0" stdsetdef="1" >
+ <class>%CLASS%Class</class>
+ <widget class="%BASECLASS%" name="%CLASS%Class" >
+ <property name="objectName" >
+ <cstring>%CLASS%Class</cstring>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>400</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>%CLASS%</string>
+ </property>%CENTRAL_WIDGET%
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/doc/classic.css b/doc/classic.css
new file mode 100644
index 0000000000..400ee71168
--- /dev/null
+++ b/doc/classic.css
@@ -0,0 +1,102 @@
+h3.fn,span.fn
+{
+ margin-left: 1cm;
+ text-indent: -1cm;
+}
+
+a:link
+{
+ color: #004faf;
+ text-decoration: none
+}
+
+a:visited
+{
+ color: #672967;
+ text-decoration: none
+}
+
+td.postheader
+{
+ font-family: sans-serif
+}
+
+tr.address
+{
+ font-family: sans-serif
+}
+
+body
+{
+ background: #ffffff;
+ color: black
+}
+
+table tr.odd {
+ background: #f0f0f0;
+ color: black;
+}
+
+table tr.even {
+ background: #e4e4e4;
+ color: black;
+}
+
+table.annotated th {
+ padding: 3px;
+ text-align: left
+}
+
+table.annotated td {
+ padding: 3px;
+}
+
+table tr pre
+{
+ padding-top: none;
+ padding-bottom: none;
+ padding-left: none;
+ padding-right: none;
+ border: none;
+ background: none
+}
+
+tr.qt-style
+{
+ background: #a2c511;
+ color: black
+}
+
+body pre
+{
+ padding: 0.2em;
+ border: #e7e7e7 1px solid;
+ background: #f1f1f1;
+ color: black
+}
+
+span.preprocessor, span.preprocessor a
+{
+ color: darkblue;
+}
+
+span.comment
+{
+ color: darkred;
+ font-style: italic
+}
+
+span.string,span.char
+{
+ color: darkgreen;
+}
+
+.subtitle
+{
+ font-size: 0.8em
+}
+
+.small-subtitle
+{
+ font-size: 0.65em
+}
diff --git a/doc/doc.pri b/doc/doc.pri
new file mode 100644
index 0000000000..5d58a28c3e
--- /dev/null
+++ b/doc/doc.pri
@@ -0,0 +1,25 @@
+# Generate docs. Does not work for shadow builds and never will.
+# (adding a "docs" make target).
+
+unix {
+ QDOC = SRCDIR=$$PWD OUTDIR=$$OUT_PWD/html $$(QTDIR)/tools/qdoc3/qdoc3
+ HELPGENERATOR = qhelpgenerator
+} else {
+ QDOC = $$(QTDIR)\tools\qdoc3\release\qdoc3.exe
+ HELPGENERATOR = qhelpgenerator
+}
+
+QHP_FILE = $$OUT_PWD/html/qtcreator.qhp
+QCH_FILE = $$OUT_PWD/qtcreator.qch
+
+html_docs.commands =$$QDOC $$PWD/qtcreator.qdocconf
+html_docs.depends += $$PWD/qtcreator.qdoc $$PWD/qtcreator.qdocconf
+html_docs.files = $$QHP_FILE
+
+qch_docs.commands = $$HELPGENERATOR -o $$QCH_FILE $$QHP_FILE
+qch_docs.depends += html_docs
+qch_docs.files = $$QCH_FILE
+
+docs.depends = qch_docs
+
+QMAKE_EXTRA_TARGETS += html_docs qch_docs docs
diff --git a/doc/doc.pro b/doc/doc.pro
new file mode 100644
index 0000000000..8337190b22
--- /dev/null
+++ b/doc/doc.pro
@@ -0,0 +1 @@
+include(doc.pri)
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
new file mode 100644
index 0000000000..c984e71e42
--- /dev/null
+++ b/doc/doxygen/Doxyfile
@@ -0,0 +1,1306 @@
+# Doxyfile 1.5.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = QWorkbench
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = YES
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class " \
+ "The $name widget " \
+ "The $name file " \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}',
+# where file will be replaced with the base name of the file that contains the anonymous
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text "
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../../src
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.cpp *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = moc_* \
+ ui_* \
+ Ui_*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH
+# then you must also enable this option. If you don't then doxygen will produce
+# a warning and turn it on anyway
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = NO
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the number
+# of direct children of the root node in a graph is already larger than
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 1000
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = YES
diff --git a/doc/example/textfinder/input.txt b/doc/example/textfinder/input.txt
new file mode 100644
index 0000000000..044545418a
--- /dev/null
+++ b/doc/example/textfinder/input.txt
@@ -0,0 +1,2 @@
+These forms are processed at run-time to produce dynamically-generated user interfaces. In order to generate a form at run-time, a resource file containing a .ui file is needed. Applications that use the form handling classes need to be configured to be built against the QtUiTools module. This is done by including the following declaration in a qmake project file to ensure that the application is compiled and linked appropriately. A form loader object, provided by the QUiLoader class, is used to construct the user interface. This user interface
+can be retrieved from any QIODevice; for example, a QFile object can be used to obtain a form stored in a project's resources. The QUiLoader::load() function takes the user interface description contained in the file and constructs the form widget. \ No newline at end of file
diff --git a/doc/example/textfinder/main.cpp b/doc/example/textfinder/main.cpp
new file mode 100644
index 0000000000..7f8c63d951
--- /dev/null
+++ b/doc/example/textfinder/main.cpp
@@ -0,0 +1,43 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QApplication>
+#include "textfinder.h"
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(textfinder);
+ QApplication a(argc, argv);
+ TextFinder w;
+ w.show();
+ return a.exec();
+}
diff --git a/doc/example/textfinder/textfinder.cpp b/doc/example/textfinder/textfinder.cpp
new file mode 100644
index 0000000000..a524f1c869
--- /dev/null
+++ b/doc/example/textfinder/textfinder.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QMessageBox>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include "textfinder.h"
+
+TextFinder::TextFinder(QWidget *parent, Qt::WFlags flags)
+ : QWidget(parent, flags)
+{
+ ui.setupUi(this);
+ loadTextFile();
+ isFirstTime = true;
+}
+
+TextFinder::~TextFinder()
+{
+}
+
+void TextFinder::loadTextFile()
+{
+ QFile inputFile(":/input.txt");
+ inputFile.open(QIODevice::ReadOnly);
+
+ QTextStream in(&inputFile);
+ QString line = in.readAll();
+ inputFile.close();
+
+ ui.textEdit->setPlainText(line);
+ QTextCursor cursor = ui.textEdit->textCursor();
+ cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1);
+}
+
+void TextFinder::on_findButton_clicked()
+{
+ QString searchString = ui.lineEdit->text();
+ QTextDocument *document = ui.textEdit->document();
+
+ bool found = false;
+
+ ui.textEdit->find(searchString, QTextDocument::FindWholeWords);
+ QTextCursor cursor = ui.textEdit->textCursor();
+ if (!cursor.isNull())
+ found = true;
+}
diff --git a/doc/example/textfinder/textfinder.h b/doc/example/textfinder/textfinder.h
new file mode 100644
index 0000000000..2563a2016a
--- /dev/null
+++ b/doc/example/textfinder/textfinder.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTFINDER_H
+#define TEXTFINDER_H
+
+#include <QtGui/QWidget>
+#include "ui_textfinder.h"
+
+class QPushButton;
+class QTextEdit;
+class QLineEdit;
+
+class TextFinder : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TextFinder(QWidget *parent = 0, Qt::WFlags flags = 0);
+ ~TextFinder();
+
+private slots:
+ void on_findButton_clicked();
+
+private:
+ Ui::Form ui;
+ void loadTextFile();
+
+ QPushButton *ui_findButton;
+ QTextEdit *ui_textEdit;
+ QLineEdit *ui_lineEdit;
+ bool isFirstTime;
+};
+
+#endif // TEXTFINDER_H
diff --git a/doc/example/textfinder/textfinder.pro b/doc/example/textfinder/textfinder.pro
new file mode 100644
index 0000000000..4dd25ca402
--- /dev/null
+++ b/doc/example/textfinder/textfinder.pro
@@ -0,0 +1,12 @@
+TARGET = TextFinder
+TEMPLATE = app
+
+
+SOURCES += main.cpp\
+ textfinder.cpp
+
+HEADERS += textfinder.h
+
+FORMS += textfinder.ui
+
+RESOURCES += textfinder.qrc
diff --git a/doc/example/textfinder/textfinder.qrc b/doc/example/textfinder/textfinder.qrc
new file mode 100644
index 0000000000..03cc512f4d
--- /dev/null
+++ b/doc/example/textfinder/textfinder.qrc
@@ -0,0 +1,5 @@
+ <!DOCTYPE RCC><RCC version="1.0">
+ <qresource>
+ <file>input.txt</file>
+ </qresource>
+ </RCC> \ No newline at end of file
diff --git a/doc/example/textfinder/textfinder.ui b/doc/example/textfinder/textfinder.ui
new file mode 100644
index 0000000000..1cb72c5747
--- /dev/null
+++ b/doc/example/textfinder/textfinder.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>378</width>
+ <height>158</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Find Text</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QGridLayout">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="searchLabel">
+ <property name="text">
+ <string>&amp;Keyword:</string>
+ </property>
+ <property name="buddy">
+ <cstring>lineEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="findButton">
+ <property name="text">
+ <string>&amp;Find</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="textEdit"/>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>lineEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>findButton</receiver>
+ <slot>animateClick()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>261</x>
+ <y>17</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>320</x>
+ <y>17</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/doc/qt-logo.png b/doc/qt-logo.png
new file mode 100644
index 0000000000..3e2e480b32
--- /dev/null
+++ b/doc/qt-logo.png
Binary files differ
diff --git a/doc/qtcreator-add-resource-wizard.png b/doc/qtcreator-add-resource-wizard.png
new file mode 100644
index 0000000000..92c21e5b54
--- /dev/null
+++ b/doc/qtcreator-add-resource-wizard.png
Binary files differ
diff --git a/doc/qtcreator-add-resource.png b/doc/qtcreator-add-resource.png
new file mode 100644
index 0000000000..8a068987f1
--- /dev/null
+++ b/doc/qtcreator-add-resource.png
Binary files differ
diff --git a/doc/qtcreator-application-output.png b/doc/qtcreator-application-output.png
new file mode 100644
index 0000000000..c574835114
--- /dev/null
+++ b/doc/qtcreator-application-output.png
Binary files differ
diff --git a/doc/qtcreator-breakdown.png b/doc/qtcreator-breakdown.png
new file mode 100644
index 0000000000..9b9f070695
--- /dev/null
+++ b/doc/qtcreator-breakdown.png
Binary files differ
diff --git a/doc/qtcreator-buildenvironment.png b/doc/qtcreator-buildenvironment.png
new file mode 100644
index 0000000000..fb9af43b0e
--- /dev/null
+++ b/doc/qtcreator-buildenvironment.png
Binary files differ
diff --git a/doc/qtcreator-buildsettings.png b/doc/qtcreator-buildsettings.png
new file mode 100644
index 0000000000..37e5214ef9
--- /dev/null
+++ b/doc/qtcreator-buildsettings.png
Binary files differ
diff --git a/doc/qtcreator-buildsettingstab.png b/doc/qtcreator-buildsettingstab.png
new file mode 100644
index 0000000000..c6768cda63
--- /dev/null
+++ b/doc/qtcreator-buildsettingstab.png
Binary files differ
diff --git a/doc/qtcreator-buildsteps.png b/doc/qtcreator-buildsteps.png
new file mode 100644
index 0000000000..7e23662faf
--- /dev/null
+++ b/doc/qtcreator-buildsteps.png
Binary files differ
diff --git a/doc/qtcreator-class-info.png b/doc/qtcreator-class-info.png
new file mode 100644
index 0000000000..757eb12856
--- /dev/null
+++ b/doc/qtcreator-class-info.png
Binary files differ
diff --git a/doc/qtcreator-compile-pane.png b/doc/qtcreator-compile-pane.png
new file mode 100644
index 0000000000..52ef37916a
--- /dev/null
+++ b/doc/qtcreator-compile-pane.png
Binary files differ
diff --git a/doc/qtcreator-context-sensitive-help.png b/doc/qtcreator-context-sensitive-help.png
new file mode 100644
index 0000000000..77fd2ffa5e
--- /dev/null
+++ b/doc/qtcreator-context-sensitive-help.png
Binary files differ
diff --git a/doc/qtcreator-debug-mode.png b/doc/qtcreator-debug-mode.png
new file mode 100644
index 0000000000..0499f88191
--- /dev/null
+++ b/doc/qtcreator-debug-mode.png
Binary files differ
diff --git a/doc/qtcreator-debugging-buttons.png b/doc/qtcreator-debugging-buttons.png
new file mode 100644
index 0000000000..f2f41f002d
--- /dev/null
+++ b/doc/qtcreator-debugging-buttons.png
Binary files differ
diff --git a/doc/qtcreator-formedit.png b/doc/qtcreator-formedit.png
new file mode 100644
index 0000000000..9627317e60
--- /dev/null
+++ b/doc/qtcreator-formedit.png
Binary files differ
diff --git a/doc/qtcreator-intro-and-location.png b/doc/qtcreator-intro-and-location.png
new file mode 100644
index 0000000000..e0d8c9f150
--- /dev/null
+++ b/doc/qtcreator-intro-and-location.png
Binary files differ
diff --git a/doc/qtcreator-navigate-customfilter.png b/doc/qtcreator-navigate-customfilter.png
new file mode 100644
index 0000000000..15f2ec87a3
--- /dev/null
+++ b/doc/qtcreator-navigate-customfilter.png
Binary files differ
diff --git a/doc/qtcreator-navigate-popup.png b/doc/qtcreator-navigate-popup.png
new file mode 100644
index 0000000000..175b0a41b4
--- /dev/null
+++ b/doc/qtcreator-navigate-popup.png
Binary files differ
diff --git a/doc/qtcreator-new-project.png b/doc/qtcreator-new-project.png
new file mode 100644
index 0000000000..6f7832e5cb
--- /dev/null
+++ b/doc/qtcreator-new-project.png
Binary files differ
diff --git a/doc/qtcreator-run.png b/doc/qtcreator-run.png
new file mode 100644
index 0000000000..845bd48e2e
--- /dev/null
+++ b/doc/qtcreator-run.png
Binary files differ
diff --git a/doc/qtcreator-search-pane.png b/doc/qtcreator-search-pane.png
new file mode 100644
index 0000000000..d630da337b
--- /dev/null
+++ b/doc/qtcreator-search-pane.png
Binary files differ
diff --git a/doc/qtcreator-select-modules.png b/doc/qtcreator-select-modules.png
new file mode 100644
index 0000000000..b5b2ead006
--- /dev/null
+++ b/doc/qtcreator-select-modules.png
Binary files differ
diff --git a/doc/qtcreator-setting-breakpoint1.png b/doc/qtcreator-setting-breakpoint1.png
new file mode 100644
index 0000000000..5a4a5d99ae
--- /dev/null
+++ b/doc/qtcreator-setting-breakpoint1.png
Binary files differ
diff --git a/doc/qtcreator-setting-breakpoint2.png b/doc/qtcreator-setting-breakpoint2.png
new file mode 100644
index 0000000000..668c46b8a6
--- /dev/null
+++ b/doc/qtcreator-setting-breakpoint2.png
Binary files differ
diff --git a/doc/qtcreator-task-list.png b/doc/qtcreator-task-list.png
new file mode 100644
index 0000000000..221d599939
--- /dev/null
+++ b/doc/qtcreator-task-list.png
Binary files differ
diff --git a/doc/qtcreator-textfinder-screenshot.png b/doc/qtcreator-textfinder-screenshot.png
new file mode 100644
index 0000000000..07f2c566ee
--- /dev/null
+++ b/doc/qtcreator-textfinder-screenshot.png
Binary files differ
diff --git a/doc/qtcreator-textfinder-ui.png b/doc/qtcreator-textfinder-ui.png
new file mode 100644
index 0000000000..2d6be91296
--- /dev/null
+++ b/doc/qtcreator-textfinder-ui.png
Binary files differ
diff --git a/doc/qtcreator-watcher.png b/doc/qtcreator-watcher.png
new file mode 100644
index 0000000000..8495e1c678
--- /dev/null
+++ b/doc/qtcreator-watcher.png
Binary files differ
diff --git a/doc/qtcreator.png b/doc/qtcreator.png
new file mode 100644
index 0000000000..93cc70137d
--- /dev/null
+++ b/doc/qtcreator.png
Binary files differ
diff --git a/doc/qtcreator.qch b/doc/qtcreator.qch
new file mode 100644
index 0000000000..00473f3458
--- /dev/null
+++ b/doc/qtcreator.qch
Binary files differ
diff --git a/doc/qtcreator.qdoc b/doc/qtcreator.qdoc
new file mode 100644
index 0000000000..d589d533ba
--- /dev/null
+++ b/doc/qtcreator.qdoc
@@ -0,0 +1,1153 @@
+/*!
+ \contentspage{index.html}{Qt Creator}
+ \page index.html
+ \nextpage qtcreator-quick-tour.html
+
+ \title Qt Creator Manual
+
+ \section1 Version 0.9 - Technical Preview
+
+ The goal of Qt Creator is to provide a cross-platform, complete Integrated
+ Development Environment (IDE) to develop Qt projects. It is available for
+ the Linux, Mac OS X and Windows platforms.
+
+ \note Qt Creator is currently released as a Technical Preview. It is
+ possible to edit source code, compile, run and debug applications; other
+ features are still under development. Please send bug reports and
+ suggestions to qt-creator@trolltech.com. To subscribe, send a
+ message with the word \e subscribe to qt-creator-request@trolltech.com.
+ For more information on Qt mailing lists, visit http://lists.trolltech.com
+
+ \table
+ \row
+ \o \inlineimage qtcreator.png
+ \o Qt Creator includes a wide range of useful features. Among them are:
+ \list 1
+ \o \bold{Qt4 Project Generating Wizard}: This wizard allows the user
+ to generate a project for a console application, a GUI application,
+ or a C++ library.
+ \o \bold{Qt Help Integration}: Qt's entire documentation can be
+ accessed easily by clicking on the \gui{Help} button.
+ \o \bold{Qt Designer Integration}: User interface forms can be designed
+ within Qt Creator. Simply double-click on a \c{.ui} file within the
+ \gui{Project Explorer} to launch the integration.
+ \o \bold{Navigation tools}: Powerful navigation tools let the user
+ navigate around files and classes with minimal keystrokes.
+ \o \bold{Support for qmake's .pro file format}: The project's \c{.pro}
+ file is used as a project description file.
+ \o \bold{Debugging Interface to GDB}: Applications can be debugged
+ within Qt Creator using a graphical frontend to the GNU symbolic
+ debugger.
+ \endlist
+ \endtable
+
+ To learn more about the Qt Creator, click on one of the links below:
+
+ \list
+ \o \l{A Quick Tour Around Qt Creator}
+ \o \l{Creating a Project in Qt Creator}
+ \o \l{Build Settings}
+ \o \l{Writing a Simple Program with Qt Creator}
+ \o \l{Quick Navigation}
+ \o \l{Debugging with Qt Creator}
+ \o \l{Tips and Tricks}
+ \o \l{Glossary}
+ \o \l{Known Issues for Version 0.9 (Technical Preview)}
+ \endlist
+
+*/
+
+/*!
+ \contentspage index.html
+ \page creator-quick-tour.html
+ \nextpage creator-build-settings.html
+
+ \title A Quick Tour Around Qt Creator
+
+ The labeled screenshot below shows some of the components of Qt Creator,
+ in \gui Edit mode.
+
+ \image qtcreator-breakdown.png
+
+ \seection1 The Mode Selectors
+
+ When working in Qt Creator, you can be in one of five modes: \bold Project,
+ \bold Edit, \bold Debug, \bold Help, and \bold Output.
+
+ Mode selectors allow you to quickly switch between tasks: Editing,
+ browsing the Qt manual, setting up the build environment, etc. You can
+ activate a mode by either clicking on its mode selector, or using the
+ \l{keyboard-shortcuts}{corresponding shortcut}. Certain actions also
+ trigger a mode change, e.g., \gui{Debug}/\gui{Start Debugging} will switch
+ to the \gui Debug mode.
+
+
+ \list
+
+ \o \gui{Welcome Mode} - Displays a welcome screen allowing you to quickly
+ load recent sessions or individual projects. This is the first mode
+ displayed if Qt Creator is run without command line switches.
+
+ \o \gui{Edit Mode} - You can edit both project and source files here. An
+ optional sidebar on the left provides different views to navigate between
+ files.
+
+ \o \gui{Debug Mode} - Provides various ways to inspect the state of the
+ program while debugging. See \l{qtcreator-debugging}{Debugging With Qt
+ Creator} for a hands-on description of the mode.
+
+ \o \gui{Build & Run Mode} - Lets you configure how projects can be built
+ and executed. Under the list of projects, there are tabs to configure the
+ build and run settings.
+
+ \o \gui{Help Mode} - Shows any documentation registered by Qt Assistant,
+ such as the Qt library and Qt Creator documentation.
+
+ \o \gui{Output Mode} - Lets you examine various logs in detail, for example
+ the task list, the compiler and application output. Some of these logs can
+ also be viewed in the output panes.
+
+ \endlist
+
+
+ \section1 The Output Panes
+
+ The task pane in Qt Creator can display one out of four different panes:
+ Task List, Search Results, Application Output, and Compile Output. These
+ panes are available in all modes.
+
+ \section2 Task List
+
+ The Task List provides a list of important tasks such as error messages
+ that need to be fixed. It filters out irrelevant output from the compiler
+ and collects them in the form of tasks.
+
+ \image qtcreator-task-list.png
+
+ \section2 Search Results
+
+ The Search Results pane displays the results for global searches such as
+ searching within a current document, files on disk, or all projects.
+ In the screenshot below, we searched for all occurrences of \c{textfinder}
+ within the "/TextFinder" folder.
+
+ \image qtcreator-search-pane.png
+
+ \section2 Application Output
+
+ This pane displays the status of the program when it is executed, as
+ well as debug output, for example, output from qDebug().
+
+ \image qtcreator-application-output.png
+
+ \section2 Compile Output
+
+ The Compile Output provides all the output from the compiler. In other
+ words, it is a more verbose version of the Task List.
+
+ \image qtcreator-compile-pane.png
+
+ \section1 Qt Help Integration
+
+ Qt Creator comes fully integrated with all of Qt's documentation and
+ examples via the Qt Help plugin. To view the documentation, you can switch
+ to the \gui{Help} mode. To obtain context sensitive help, move your text
+ cursor to a Qt class or function and press \key{F1}. The documentation
+ will be displayed within a panel on the right, as shown in the screenshot
+ below.
+
+ External Documentation provided by the user can be used to augment or
+ replace the documentation shipped with Qt Creator and Qt.
+
+ \image qtcreator-context-sensitive-help.png
+
+
+ \section1 Qt Designer Integration
+
+ Qt Creator is fully integrated with Qt Designer to help you design user
+ interface forms just like you would with the standalone version. The Qt
+ Designer integration also includes project management and code completion.
+
+ \image qtcreator-formedit.png
+
+
+ \section1 Keyboard Navigation
+
+ Even though Qt Creator can be used with a mouse, it also caters to the
+ needs of developers who are more comfortable with the keyboard. A wide
+ range of \l{keyboard-shortcuts}{keyboard} and \l{Quick Navigation}
+ {navigation} shortcuts are available to help speed up the process of
+ developing your application.
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-quick-tour.html
+ \page creator-build-settings.html
+ \nextpage creator-creating-project.html
+
+ \title Build Settings
+
+ \table
+ \row
+ \i \bold{Warning:} Qt Creator currently supports qmake only.
+ Makefile and CMake support is not yet available.
+ \endtable
+
+ To modify the build settings of your project, switch to the
+ \gui{Build & Run} mode using the mouse or by pressing \key{Ctrl+4}.
+
+ \image qtcreator-buildsettings.png
+
+ Action items to create, clone, or delete build configurations can be found
+ on the right of the dialog. You can have as many build configurations
+ as you need. By default Qt Creator creates a \bold{debug} and
+ \bold{release} build configuration. Both these configurations use the
+ \l{glossary-default-qt}{Default Qt Version}.
+
+ In the tree on the left, a list of build configurations and their settings
+ are displayed. The screenshot below shows the \bold{debug} and
+ \bold{release} configurations and their corresponding settings:
+ \bold{Build Environment} and \bold{Build Steps}.
+
+ \image qtcreator-buildsettingstab.png
+
+ When you select a build configuration in the tree, a configuration page for
+ general build settings will be displayed. Here you can specify which
+ \l{glossary-project-qt}{Qt version} to use to build your project, whether
+ to \l{glossary-shadow-build}{shadow build} the project, and if a special
+ debugging helper is linked into the project or not.
+
+ The debugging helper enables the gdb integration to show the contents of
+ Qt data types. Enabling this option means that an additional file will be
+ compiled and linked to your project.
+
+ \image qtcreator-buildenvironment.png
+
+ In the \bold{Build Environment} page you can specify the environment used
+ for building. By default the environment in which Qt Creator was started
+ is used and modified to include the Qt version. Depending on the selected
+ Qt version, Qt Creator will automatically add the necessary environment
+ variables.
+
+ \image qtcreator-buildsteps.png
+
+ The build system of Qt Creator is built on top of \c qmake and \c make. The
+ settings for \c qmake and \c make can be changed in the
+ \bold{Build Settings} page. Qt Creator will run the make command using the
+ correct Qt version.
+
+ \note The default qmake arguments \c{-after SOURCES*=gdbmacros.cpp
+ -after QT*=network} are due to the debugging helper described above. If the
+ debugging helper seems to break your build or your application, you can
+ turn it off. You will still be able to debug applications, but the contents
+ of Qt data types will not be displayed properly.
+
+
+ \section1 Qt Version Management
+
+ Qt Creator allows you to use multiple versions of Qt installed on your hard
+ disk and switch between them easily.
+
+ Qt Creator automatically detects if \c qmake is in the environment variable
+ \c PATH. This \l{glossary-system-qt}{version of Qt} is referred to as
+ \bold{System Qt}. If you intend to use only one version of Qt - it is
+ already in your path and correctly set up for command line usage - you do
+ not need to manually configure your Qt version.
+
+ Otherwise, you can add your Qt version in
+ \gui{Tools -> Options... -> Qt Versions}. If you are on the Windows
+ platform and use MinGW to compile Qt, you need to tell Qt Creator where
+ MinGW is installed. This is done by setting the \gui{MinGW Directory}
+ under \gui{Tools -> Options... -> Qt4 -> Qt Versions -> MinGw Directory}.
+ If your Qt version is compiled with Microsoft Visual C++'s compiler, Qt
+ Creator will automatically set the correct environment variables for
+ compilation.
+
+ \note By default projects are compiled with the
+ \l{glossary-default-qt}{default Qt version}. You can override this in the
+ \gui{Build Configuration}.
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-quick-tour.html
+ \page creator-creating-project.html
+ \nextpage creator-writing-program.html
+
+ \title Creating a Project in Qt Creator
+
+ \table
+ \row
+ \i \inlineimage qtcreator-new-project.png
+ \i \bold{Creating a New Project}
+
+ To create a new project, select \gui{New Project} from the \gui{File} menu.
+ You can create one of the following three projects:
+
+ \list
+ \o Qt4 Console Application
+ \o Qt4 Gui Application
+ \o C++ Library
+ \endlist
+
+ In this example, we select a \e{Qt4 Gui Application} and click \gui{OK}.
+
+ \row
+ \i \inlineimage qtcreator-intro-and-location.png
+ \i \bold{Setting The Project Name and Location}
+
+ Next, we set the project's name and its path. Click on the \gui{...}
+ button to browse and select your path.
+
+ Ideally, the path should not contain spaces or special characters.
+
+ \row
+ \i \inlineimage qtcreator-select-modules.png
+ \i \bold{Selecting The Necessary Qt Modules}
+
+ Click on the check boxes of each Qt Module you would like to include in
+ your project.
+
+ Since we started a Qt4 Gui Application, the Core and Gui modules are
+ set, but you are free to add more.
+
+ \row
+ \i \inlineimage qtcreator-class-info.png
+ \i \bold{Specifying Class Information}
+
+ Lastly, specify the name of the class you would like to create. The
+ \e{Header file}, \e{Source file} and \e{Form file} fields will update
+ themselves according to your choice of class name.
+
+ You also have to select the base class for your class, either a
+ QWidget, QDialog or QMainWindow, from the drop down box. Click
+ \gui{Done} and your project will be generated.
+
+ \endtable
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-creating-project.html
+ \page creator-writing-program.html
+ \nextpage creator-navigation.html
+
+ \title Writing a Simple Program with Qt Creator
+
+ \table
+ \row
+ \o \note This tutorial assumes that the user has experience writing
+ basic Qt applications, designing user interfaces with Qt Designer
+ and and using the Qt Resource System.
+ \endtable
+
+
+ In this example, we will describe the steps involve in using Qt Creator
+ to create a small Qt program, Text Finder. Inspired by the QtUiTools'
+ \l{http://doc.trolltech.com/uitools-textfinder.html}{Text Finder}
+ example, we will write a similar but simplified version of it, as shown
+ below.
+
+ \image qtcreator-textfinder-screenshot.png
+
+ \section1 Setting Up Your Environment
+
+ Once you have installed Qt Creator, it will automatically detect if Qt's
+ location is in your \c PATH variable. If Qt's location is not in your
+ \c PATH, you can set it in one of the following ways, depending on your
+ platform:
+
+ \list
+ \o On Windows and Linux: in the \gui{Tools} menu, under \gui{Options}.
+ \o On Mac OS X: in \gui{Preferences}, under \gui{Qt4}.
+ \endlist
+
+ \note If Qt was compiled with Visual Studio, all environment variables set
+ in Visual Studio will be added to Qt Creator as well.
+
+ \section1 Setting Up The Project
+
+ We begin with a Qt4 Gui Application project generated by Qt Creator. The
+ \l{Creating a Project in Qt Creator} document describes this process in
+ detail. Remember to select QWidget as the Text Finder's base class.
+
+ Once your project is generated, you will have the following files:
+
+ \list
+ \o \c{textfinder.h}
+ \o \c{textfinder.cpp}
+ \o \c{main.cpp}
+ \o \c{textfinder.ui}
+ \o \c{textfinder.pro}
+ \endlist
+
+ The \c{.h} and \c{.cpp} files come with the necessary boiler plate code;
+ the \c{.pro} file is also complete.
+
+ \section1 Filling In The Missing Pieces
+
+ We will begin by designing the user interface and then move on to filling
+ in the missing code. Finally, we will add the find functionality.
+
+ \section2 Designing the User Interface
+
+ To begin designing the user interface, double-click on the
+ \c{textfinder.ui} file in your \gui{Project Explorer}. This will launch the
+ integrated Qt Designer.
+
+ \image qtcreator-textfinder-ui.png
+
+ Design the form above using a QLabel, QLineEdit, QPushButton and a
+ QTextEdit. We recommend that you use a QGridLayout to lay out the QLabel,
+ QLineEdit and QPushButton. The QTextEdit can then be added to a
+ QVBoxLayout, along with the QGridLayout. If you are new to designing forms
+ with \QD, you can take a look at the
+ \l{http://doc.trolltech.com/designer-manual.html}{Designer Manual}.
+
+ \section2 The Header File
+
+ The \c{textfinder.h} file already has the necessary includes, a
+ constructor, a destructor, and the \c{Ui} object. We need to add a private
+ slot, \c{on_findButton_clicked()}, to carry out our find operation. We
+ also need a private function, \c{loadTextFile()}, to read and display the
+ contents of our input text file in the QTextEdit. This is done with the
+ following code:
+
+ \code
+ private slots:
+ void on_findButton_clicked();
+
+ private:
+ Ui::Form ui;
+ void loadTextFile();
+ \endcode
+
+ \note The \c{Ui::Form} object is already provided.
+
+ \section2 The Source File
+
+ Now that our header file is complete we move on to our source file,
+ \c{textfinder.cpp}. We begin by filling in the functionality to load a
+ text file. The code snippet below describes this:
+
+ \code
+ void TextFinder::loadTextFile()
+ {
+ QFile inputFile(":/input.txt");
+ inputFile.open(QIODevice::ReadOnly);
+
+ QTextStream in(&inputFile);
+ QString line = in.readAll();
+ inputFile.close();
+
+ ui.textEdit->setPlainText(line);
+ QTextCursor cursor = ui.textEdit->textCursor();
+ }
+ \endcode
+
+ Basically, we load a text file using QFile, read it with QTextStream, and
+ then display it on \c{textEdit} with \l{QTextEdit::}{setPlainText()}.
+
+ For the \c{on_findButton_clicked()} slot, we extract the search string and
+ use the \l{QTextEdit::}{find()} function to look for the search string
+ within the text file. The code snippet below further describes it:
+
+ \code
+ void TextFinder::on_findButton_clicked()
+ {
+ QString searchString = ui.lineEdit->text();
+ ui.textEdit->find(searchString, QTextDocument::FindWholeWords);
+ }
+ \endcode
+
+ Once we have both these functions complete, we call \c{loadTextFile()} in
+ our constructor.
+
+ \code
+ TextFinder::TextFinder(QWidget *parent, Qt::WFlags flags)
+ : QWidget(parent, flags)
+ {
+ ui.setupUi(this);
+ loadTextFile();
+ }
+ \endcode
+
+ The \c{on_findButton_clicked()} slot will be called automatically due to
+ this line of code:
+
+ \code
+ QMetaObject::connectSlotsByName(Form);
+ \endcode
+
+ in the uic generated \c{ui_textfinder.h} file.
+
+ \section2 The Resource File
+
+ We require a resource file (\c{.qrc}) within which we will embed the input
+ text file. This can be any \c{.txt} file with a paragraph of text. To add
+ a resource file, right click on \gui{Resource Files} in the
+ \gui{Project Explorer} and select \gui{Add New File...}. You will see the
+ wizard dialog displayed below.
+
+ \image qtcreator-add-resource-wizard.png
+
+ Enter "textfinder" in the \gui{Name} field and use the given \gui{Path}.
+ Then, click \gui{Done}.
+
+ Your resource file will now be displayed with the Resource Editor. Click
+ on the \gui{Add} drop down box and select \gui{Add Prefix}. The prefix we
+ require is just a slash (\c{/}). Click \gui{Add} again but this time,
+ select \gui{Add File}. Locate the text file you are going to use, we use
+ \c{input.txt}.
+
+ \image qtcreator-add-resource.png
+
+ The screenshot above shows what you can expect to see once you have added
+ the resource file successfully.
+
+ \section1 Compiling and Running Your Program
+
+ Now that you have all the necessary files, you can compile your program by
+ clicking on the
+ \inlineimage qtcreator-run.png
+ button.
+
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-writing-program.html
+ \page creator-navigation.html
+ \nextpage creator-debugging.html
+
+ \title Quick Navigation
+
+ With Qt Creator, navigating to different locations in your project or on
+ your disk, such as files, classes and methods, is trivial using the input
+ field at the bottom left of the application window.
+
+ ### SCREENSHOT
+
+ To open for example the file \c{main.cpp} of your project, click into the
+ input field (or use \key{Ctrl+K} to get there), type the file name, and
+ finally press the \key{Return} key. The file will open in the editor.
+ You can also type only a part of a file name, and use the wildcard
+ characters \c{*} and \c{?} which match \c{any number of any characters} and
+ \c{any single character}, respectively - you will get a list of all matching
+ files to choose from.
+
+ As mentioned above, files are not the only type of locations you can
+ jump to. The different types of locations are organized in what we
+ call \c{filters}. There are filters for jumping to
+ \list
+ \o files mentioned in your \c{.pro} files, such as source and header,
+ resource and \c{.ui} files,
+ \o a specific line in your current text document,
+ \o class and method definitions in your project or anywhere referenced
+ from your project,
+ \o help topics, including the Qt API reference documentation,
+ \o files anywhere on your hard disk (by browsing through the file system),
+ \o any open document,
+ \o files from a subdirectory structure you define.
+ \endlist
+ Some of these filters are not used by default if you just start typing in the
+ input field, but require you to type a "prefix" in front, that is
+ assigned to that filter. The prefix is usually a single character,
+ followed by a space. As an example, to jump to the definition of the class
+ \c{QDataStream} type \key{Ctrl+K}, \key{:}, \key{Space}, and the class name.
+ You find a full list of filters and their prefixes below.
+
+ \image qtcreator-navigate-popup.png
+
+ You can add filters that provide quick navigation to files in a
+ subdirectory structure that you define. This way you have quick access to
+ files that are not directly mentioned in your project, but still relate to it.
+ Click on the little magnifier glass in the input field and choose
+ \gui{Configure...} from the menu that appears. This opens the preferences
+ dialog for navigation filters. Click the \gui{Add} button to create a new
+ filter. Give it a name, choose directories, set (a comma separated list of)
+ file patterns, and give it a prefix string. After closing the preferences
+ dialog the directories you specified are searched for files that match the
+ file patterns, and the information is cached. From now on you can jump to
+ these files by just typing part of the file name into the navigation input
+ field. You can force an update of the cached information about the files via
+ the \gui{Refresh} menu item in the magnifier menu.
+
+ \image qtcreator-navigate-customfilter.png
+
+ The following table gives an overview on the currently available filters:
+
+ \table
+ \header
+ \o Function
+ \o Key Combination
+ \row
+ \o Go to a Line in the Current Document
+ \o Ctrl + K, l, Space, and the line number
+ \row
+ \o Go to a Function Definitions
+ \o Ctrl + K, :, Space, and the function name
+ \row
+ \o Go to a Help Topic
+ \o Ctrl + K, ?, Space, and the topic
+ \row
+ \o Go to an Already Opened Document
+ \o Ctrl + K, o, Space, and the document name.
+ \row
+ \o Go to a File in the File System (browsing the file system)
+ \o Ctrl + K, f, Space, and the file name.
+ \row
+ \o Go to a File in any Loaded Project
+ \o Ctrl + K, a, Space, and the function name.
+ \row
+ \o Go to a File in the Current Project
+ \o Ctrl + K, p, Space, and the function name.
+ \endtable
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage creator-navigation.html
+ \page creator-debugging.html
+ \nextpage creator-tips.html
+
+ \title Debugging With Qt Creator
+
+ \table
+ \row
+ \i \note Qt Creator's debugger integration currently does not
+ support debugging applications created with the Microsoft Visual
+ Studio Compiler.
+ \endtable
+
+ Qt Creator does not have its own debugger. Instead, it provides a graphical
+ frontend to the GNU Symbolic Debugger (gdb). This frontend allows you to
+ step through a program line-by-line or instruction-by-instruction,
+ interrupt running programs, set breakpoints, examine the contents of the
+ call stack, local and global variables, etc.
+
+
+ Within Qt Creator, the raw information provided by gdb is displayed in a
+ clear and concise manner, simplifying the process of debugging.
+
+ In addition to generic IDE functionality: stack view, views for locals and
+ watchers, registers, etc, Qt Creator comes with additional features to make
+ debugging Qt-based applications easy. The debugger frontend knows about the
+ internal layout of several Qt classes such as QString, the QTL containers,
+ and most importantly QObject (and classes derived from it). Therefore, it
+ is able to present Qt's data clearly.
+
+
+ \section1 Interacting with the Debugger
+
+ In \gui Debug mode, several dock widgets are used to interact with the
+ program you are debugging. The frequently used dock widgets are visible by
+ default; the rarely used ones are hidden. To change the default settings,
+ select \gui Debug and then select \gui View.
+
+ ####SCREENSHOT
+
+ Here, you can lock or unlock the location of your views as well as display
+ or hide them. Among the views you can display are \gui Breakpoints,
+ \gui Disassembler, \gui Modules, \gui Registers, \gui Gdb, \gui Stack, and
+ \gui Thread. The position of your dock widgets will be saved for future
+ sessions.
+
+
+ \section2 Breakpoints
+
+ Breakpoints are shown in the \gui{Breakpoints} view which is enabled by
+ by default. This view is also accessible when the debugger and the program
+ being debugged is not running.
+
+ A breakpoint represents a position or sets of positions in the code that,
+ when executed, stops the program being debugged and passing the control to
+ the user. The user is then free to examine the state of the interrupted
+ program, or continue execution line-by-line or continuously.
+
+ Typically, breakpoints are associated with a source code file and line, or
+ the start of a function -- both allowed in Qt Creator.
+
+ Also, the interruption of a program by a breakpoint can be restricted with
+ certain conditions.
+
+ You can set a breakpoint:
+
+ \list
+ \o At a particular line you want the program to stop -- click on the
+ left margin or press \key F9 (\key F8 for Mac Os X).
+ \o At the name of a function that you want the program to stop -- enter
+ the function's name in \gui{Set Breakpoint at Function...} under the
+ \gui Debug menu.
+ \endlist
+
+ You can remove a breakpoint:
+
+ \list
+ \o By clicking on the breakpoint marker in the text editor.
+ \o By selecting the breakpoint in the breakpoint view and pressing
+ \key{Delete}.
+ \o By selecting \gui{Delete Breakpoint} from the breakpoint's context
+ menu in the \gui Breakpoints view.
+ \endlist
+
+ Breakpoints can be set and deleted before the program has actually started
+ running or while it is running under the debugger's control. Also,
+ breakpoints are saved together with a session.
+
+
+ \section2 Running
+
+ To start a program under the debugger's control, select the \gui{Debug}
+ menu and \gui{Start Debugging}, or simply press \key{F5}. Qt Creator then
+ checks whether the compiled program is up-to-date, rebuilding it if
+ necessary. The debugger then takes over and starts the program.
+
+ \note Starting a program in the debugger will take considerable amount of
+ time, typically in the range of several seconds to minutes if complex
+ features (like QtWebKit) are used.
+
+ Once the program starts running, it behaves as usual; performance-wise as
+ well. The user can interrupt a running program by selecting
+ \gui {Interrupt} from the \gui{Debug} menu. The program is automatically
+ interrupted as soon as a breakpoint is hit.
+
+ \omit (and, if set, its associated conditions are met). \endomit
+
+ Once the program stops, Qt Creator:
+
+ \list
+ \o Retrieves data representing the call stack at the program's current
+ position.
+ \o Retrieves the contents of local variables.
+ \o Examines \gui Watchers.
+ \o Updates the \gui Registers, \gui Modules, and \gui Disassembler
+ views.
+ \endlist
+
+
+ You can use the debugger views to examine the data in more detail.
+
+ To finish debugging, Press \key{Shift+F5}. A line of code can be executed
+ as a whole with \key F10; to execute a function or a sub-function, use
+ \key F11. Alternatively, you can continue running the program with \key F5.
+
+ ###REWORD
+ There is also the possibility to continue execution until the current
+ function finishes, or, for advanced use, to jump to an arbitrary
+ possition in the current function.
+
+
+ \section2 Stack
+
+ When the program being debugged is stopped, Qt Creator displays the nested
+ function calls leading to the current position as a \e call stack trace.
+ This stack trace is built up from \e call stack frames, each representing a
+ particular function. For each function, Qt Creator will try to retrieve the
+ file name and line number of the corresponding source files. This data is
+ shown in the \gui Stack view.
+
+ Since the call stack leading to the current position may originate or go
+ through code for which no debug information is available, not all stack
+ frames will have corresponding source locations. These frames will be
+ greyed out in the \gui Stack view.
+
+ ###SCREENSHOT
+
+
+ If you click on a frame with a known source location, the text editor will
+ jump to the corresponding location and update the \gui{Locals and Watchers}
+ view, making it seem like the program stopped before entering the function.
+
+
+ \section2 Threads
+
+
+ The \gui Thread view displays the state of the program being debugged one
+ thread at a time. If a multi-threaded program is stopped, the \gui Thread
+ view or the combobox named \gui Thread in the debugger's status bar can
+ be used to switch from one thread to another. The \gui Stack view will
+ adjust itself accordingly.
+
+
+ \section2 Locals and Watchers
+
+ Whenever a program stops under the control of the debugger, it retrieves
+ information about the topmost stack frame and displays it in the
+ \gui{Locals and Watchers} view. This typically includes information about
+ parameters of the function in that frame as well as the local variables.
+
+ Compound variables of struct or class type will be displayed as
+ "expandable" in the view. C lick on the "+" to expand the entry and show
+ all members. Together with the display of value and type, the user can
+ examine and traverse the low-level layout of an object's data.
+
+
+ \table
+ \row
+ \i \bold{Note:}
+ \i Gdb, and therefore Qt Creator's debugger works for optimized builds
+ on Linux and Mac OS X. However, optimization may lead to re-ordering of
+ instructions or sometimes even complete removal of some local variables.
+ In this case, the \gui{Locals and Watchers} view may show unexpected data.
+ \endtable
+
+ \note
+
+ \bold{Note:} The debug information provided by gcc does not include
+ enough information about the time at which a variable is initialized.
+ Qt Creator therefore can not tell whether the contents of a local
+ variable contains "real data", or "initial noise". If an QObject
+ appears uninitialized, its value will be reported as "out of scope".
+ Not all uninitialized objects can be recognized as such, though.
+
+ The \gui{Locals and Watchers View} also gives accesst to the most powerful
+ feature of the Qt Creator Debugger: The comprehensive display of data
+ of objects of some of Qt's basic classes.
+
+ To start using that feature, select \gui{Debug} and \gui{Use Custom
+ Display for Qt Objects}. The \gui{Locals and Watchers View} will
+ be re-organized to give a more high-level view of the objects
+ in question. So instead of displaying a pointer to some private
+ data structure in case of QObject, a list of children, signals
+ and slots will be shown.
+
+ Similarily, instead of showing a bunch of pointers and ints,
+ a QHash or QMap will display its contents in an orderly fashion,
+ a QFileInfo will expose e.g. access data, and the otherwise
+ "opaque" QVariant gives access to the "real" contents.
+
+ The \gui{Locals and Watchers View} can be used to change the
+ contents of variables of simple data types like int or float
+ while the program is stopped. To do so, click into the 'Value'
+ column, modify the value there, and hit \key{Return}.
+
+
+
+ \section2 Modules
+
+ The \gui{Modules View} is hidden by default and only useful in
+ connection with the experimental feature of delayed debug
+ information loading. This feature is accessible by selecting
+ \gui{Debug} and \gui{Fast Debugger Start}. When using the
+ feature, debug information coming from the Qt library itself
+ are not loaded on application startup, thereby reducing the
+ startup times for some applications. The \gui{Modules View}
+ can then be used to load this information manually if needed.
+ Note that the debugger may fail to set some breakpoints in
+ this scenarios.
+
+ \section2 Disassembler View and Registers View
+
+ Both the \gui{Disassembler View} and \gui{Registers View} are hidden
+ by default. The former shows the disassembled code of the current
+ function, the latter the current state of the CPU registers.
+ Both views are mainly useful in connection with the low-level
+ \gui{Step single instruction} and \gui{Step over single instruction}
+ commands
+
+
+
+ \section1 A short walk through the debugger frontend
+
+ In our \l{Writing a Simple Program with Qt Creator}{TextFinder}
+ example, we read a text file into a QString and then display it with a
+ QTextEdit. Suppose, you would like to look at this QString, \c{line},
+ and see what data it actually stores. Follow the steps described below
+ to place a break point and view the QString object's data.
+
+ \table
+ \row
+ \i \inlineimage qtcreator-setting-breakpoint1.png
+ \i \bold{Setting a Breakpoint}
+
+ First, we set a breakpoint on the line where we invoke
+ \l{QTextEdit::}{setPlainText()} by clicking between the line number and
+ the window border. Then, select \gui{Start Debugging} from the
+ \gui{Debug} menu or press \key{F5}.
+ \endtable
+
+ Breakpoints are visible in the \gui{Breakpoints} view, shown below, in
+ \gui{Debug} mode. If you wish to remove a breakpoint, simply right
+ click on it and select \gui{Delete breakpoint} from the context menu.
+
+ \image qtcreator-setting-breakpoint2.png
+
+ To view the contents of \c{line}, take a look at the \gui{Locals and
+ Watchers} view.
+
+ \image qtcreator-watcher.png
+
+ Suppose we modify our \c{on_findButton_clicked()} function to move back
+ to the start of the document and continue searching once the cursor
+ hits the end of the document. Adding this functionality can be done
+ with the code snippet below:
+
+ \code
+ void TextFinder::on_findButton_clicked()
+ {
+ QString searchString = ui.lineEdit->text();
+
+ QTextDocument *document = ui.textEdit->document();
+ QTextCursor cursor = ui.textEdit->textCursor();
+ cursor = document->find(searchString, cursor,
+ QTextDocument::FindWholeWords);
+ ui.textEdit->setTextCursor(cursor);
+
+ bool found = cursor.isNull();
+
+ if (!found && previouslyFound == true) {
+ int ret = QMessageBox::question(this, tr("End of Document"),
+ tr("I have reached the end of the document. Would you like "
+ "me to start searching from the beginning of the document?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ cursor = document->find(searchString,
+ QTextDocument::FindWholeWords);
+ ui.textEdit->setTextCursor(cursor);
+ } else
+ return;
+ }
+ previouslyFound = found;
+ }
+ \endcode
+
+ However, if you compile and run this code, the application will not
+ work correctly due to a logic error. To locate this logic error, you
+ can step through the code using the following buttons:
+
+ \image qtcreator-debugging-buttons.png
+*/
+
+
+/*!
+ \contentspage index.html
+ \previouspage creator-debugging.html
+ \page creator-tips.html
+ \nextpage creator-glossary.html
+
+ \title Tips and Tricks
+
+ \bold{Quick mode switch}
+
+ You can quickly switch between modes by pressing \key{Ctrl+1},
+ \key{Ctrl+2}, etc.
+
+ \bold{Other keyboard shortcuts}
+
+ There are a lot of other \l{keyboard-shortcuts}{keyboard shortcuts}.
+
+ \bold{Command line}
+
+ You can start Qt Creator from a command prompt with an already
+ existing session or \c{.pro} file by giving the name as argument on the
+ command line.
+
+ \bold{Sidebar}
+
+ You can hide/unhide the sidebar in the edit and debug mode
+ by clicking on the corresponding icon on the left bottom.
+ Keyboard shortcut is \key{Alt+0}.
+
+ \bold{Display signals and slots}
+
+ If you have an instance of a class derived from QObject and
+ want to find all other objects connected to one of its
+ slots by Qt's signals-and-slots mechanism, enable
+ \gui{Debug} and \gui{Use Custom Display for Qt Objects}.
+ In the \gui{Locals and Watchers View}, expand the object's
+ entry and open the wanted slot in the "slots" subitem. The
+ objects connect to this slot are exposed as children of
+ this slot. The same works with signals.
+
+ \bold{Low level display}
+
+ If the special debugging of Qt objects fails due to data
+ corruption within the debugged objects, you can switch the
+ special debugging off in the \gui{Debug} menu. This will make
+ the low-level structures visible again.
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-tips.html
+ \page creator-glossary.html
+ \nextpage creator-known-issues.html
+
+ \title Glossary
+
+ \bold{System Qt}
+
+ \target glossary-system-qt
+ The version of Qt installed on your system.
+ This is the one whose \c qmake command is found in the \c PATH.
+
+ \bold{Default Qt}
+
+ \target glossary-default-qt
+ The version of Qt configured in \gui{Tools
+ -> Options -> Qt 4 -> Default Qt Version}. This is the version
+ used by new projects. It defaults to the System Qt.
+
+ \bold{Project Qt}
+
+ \target glossary-project-qt
+ The version of Qt configured in \gui{Build&Run
+ -> Build Settings -> Build Configurations}. This is the version
+ actually used by the project. It defaults to the Default Qt.
+
+ \bold{Shadow Build}
+
+ \target glossary-shadow-build
+ Shadow building means building the project not in the source directory,
+ but in a seperate \bold{build directory}. This has the benefit of keeping
+ the source directory clean. It is also considered "best practice" if
+ you need many build configurations for a single set of sources.
+
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-glossary.html
+ \page creator-keyboard-shortcuts.html
+
+ \title Keyboard Shortcuts
+
+ Qt Creator provides various keyboard shortcuts to aid in the development
+ process. These shortcuts are listed in the table below:
+
+ \table
+ \header
+ \o Function
+ \o Key Combination
+ \row
+ \o Activate Build & Run Mode
+ \o Ctrl + 4
+ \row
+ \o Activate Debug Mode
+ \o Ctrl + 3
+ \row
+ \o Activate Edit Mode
+ \o Ctrl + 2
+ \row
+ \o Activate Help Mode
+ \o Ctrl + 5
+ \row
+ \o Activate Output Mode
+ \o Ctrl + 6
+ \row
+ \o Activate Welcome Mode
+ \o Ctrl + 1
+ \row
+ \o Find
+ \o Ctrl + F
+ \row
+ \o Find Next
+ \o F3
+ \row
+ \o Go back to Code Editor (May require more than one press)
+ \o Esc
+ \row
+ \o Go to a Line
+ \o Ctrl + L
+ \row
+ \o Start Debugging
+ \o F5
+ \row
+ \o Stop Debugging
+ \o Shift + F5
+ \row
+ \o Toggle Application Output
+ \o Alt + 3
+ \row
+ \o Toggle Code Declaration and Definition
+ \o F2
+ \row
+ \o Toggle Header File and Source File
+ \o F4
+ \row
+ \o Toggle Side Bar
+ \o Alt + 0
+ \row
+ \o Toggle Task List
+ \o Alt + 1
+ \row
+ \o Toggle Search Results
+ \o Alt + 2
+ \row
+ \o Toggle Compile Output
+ \o Alt + 4
+ \row
+ \o Select Welcome Mode
+ \o Ctrl + 1
+ \row
+ \o Select Edit Mode
+ \o Ctrl + 2
+ \row
+ \o Select Debug Mode
+ \o Ctrl + 3
+ \row
+ \o Select Build & Run Mode
+ \o Ctrl + 4
+ \row
+ \o Select Help Mode
+ \o Ctrl + 5
+ \row
+ \o Select Output Mode
+ \o Ctrl + 6
+ \endtable
+*/
+
+/*!
+ \contentspage index.html
+ \previouspage creator-keyboard-shortcuts.html
+ \page creator-known-issues.html
+
+ \title Known Issues of Version 0.9 (Technical Preview)
+
+ There are some known issues with the Technical Preview.
+ The development team is aware of those, there is no need to report them as bug.
+
+ \list
+ \o The central editor sometimes loses it "changed" status marker.
+
+ \o There is a kernel bug essentially making debugging unreliable
+ on 2.6.24 kernels for i386 (which is, unfortunately, the default
+ on Ubuntu 8.04).
+ See \l{https://bugs.launchpad.net/ubuntu/+source/gdb/+bug/230315/}
+ for details.
+ The only solution for this problem is to boot another kernel.
+
+ \o gdb sometimes takes very long to load debugging symbol,
+ especially from big libraries like libQtWebKit. Starting debugging
+ can take up to several minutes without visible progress.
+
+ \o Paths or file names containing spaces or special characters like colons,
+ dollar signs, hash marks etc. may create difficulties.
+ Some of the tools Qt Creator uses in the background to do the "real
+ work" have restrictions on the characters that are allowed in file
+ and directory names. To be on the safe side, it is strongly
+ recommended to create projects and project items only with names
+ consisting of plain characters, numbers, underscores, and hyphens.
+
+ \o \c .pro files are reformatted if files are added/removed.
+ Whitespace is not preserved.
+
+ \o No IDE support for adding files to include (\c .pri) files.
+
+ \o No IDE support for adding/removing sub-projects.
+ Project hierarchies (SUBDIRS template) have to be created by hand.
+
+ \o The file system sidebar does not update automatically.
+ As a workaround you can switch to another directory and then back.
+
+ \o The resource system of the embedded version of Qt Designer
+ does not interact with the project management.
+
+ \o Loading KDE4 designer plugins breaks the style, due to a bug in KDE.
+ \endlist
+*/
+
diff --git a/doc/qtcreator.qdocconf b/doc/qtcreator.qdocconf
new file mode 100644
index 0000000000..4cc07d2dc7
--- /dev/null
+++ b/doc/qtcreator.qdocconf
@@ -0,0 +1,205 @@
+# Run qdoc from the directory that contains this file.
+
+project = qtcreator
+description = "Qt Creator Manual"
+
+headerdirs =
+sourcedirs =
+sourcedirs = $SRCDIR
+imagedirs = $SRCDIR
+outputdir = $OUTDIR
+
+extraimages.HTML = qt-logo \
+ trolltech-logo
+
+sources.fileextensions = "qtcreator.qdoc"
+
+
+qhp.projects = QtCreator
+qhp.QtCreator.file = qtcreator.qhp
+qhp.QtCreator.namespace = com.nokia.qtcreator.09
+qhp.QtCreator.virtualFolder = doc
+qhp.QtCreator.indexTitle = Qt Creator
+qhp.QtCreator.indexRoot =
+qhp.QtCreator.extraFiles = classic.css \
+ images/qt-logo.png
+qhp.QtCreator.filterAttributes = qtcreator 0.9
+qhp.QtCreator.customFilters.QtCreator.name = Qt Creator 0.9
+qhp.QtCreator.customFilters.QtCreator.filterAttributes = qtcreator 0.9
+
+# macros.qdocconf
+
+macro.aring.HTML = "&aring;"
+macro.Auml.HTML = "&Auml;"
+macro.author = "\\bold{Author:}"
+macro.br.HTML = "<br />"
+macro.BR.HTML = "<br />"
+macro.aacute.HTML = "&aacute;"
+macro.eacute.HTML = "&eacute;"
+macro.iacute.HTML = "&iacute;"
+macro.gui = "\\bold"
+macro.hr.HTML = "<hr />"
+macro.key = "\\bold"
+macro.menu = "\\bold"
+macro.note = "\\bold{Note:}"
+macro.oslash.HTML = "&oslash;"
+macro.ouml.HTML = "&ouml;"
+macro.QA = "\\e{Qt Assistant}"
+macro.QD = "\\e{Qt Designer}"
+macro.QL = "\\e{Qt Linguist}"
+macro.param = "\\e"
+macro.raisedaster.HTML = "<sup>*</sup>"
+macro.reg.HTML = "<sup>&reg;</sup>"
+macro.return = "Returns"
+macro.starslash = "\\c{*/}"
+macro.uuml.HTML = "&uuml;"
+macro.mdash.HTML = "&mdash;"
+
+# compat.qdocconf
+
+alias.i = e
+alias.include = input
+
+macro.0 = "\\\\0"
+macro.b = "\\\\b"
+macro.n = "\\\\n"
+macro.r = "\\\\r"
+macro.i = "\\o"
+macro.i11 = "\\o{1,1}"
+macro.i12 = "\\o{1,2}"
+macro.i13 = "\\o{1,3}"
+macro.i14 = "\\o{1,4}"
+macro.i15 = "\\o{1,5}"
+macro.i16 = "\\o{1,6}"
+macro.i17 = "\\o{1,7}"
+macro.i18 = "\\o{1,8}"
+macro.i19 = "\\o{1,9}"
+macro.i21 = "\\o{2,1}"
+macro.i31 = "\\o{3,1}"
+macro.i41 = "\\o{4,1}"
+macro.i51 = "\\o{5,1}"
+macro.i61 = "\\o{6,1}"
+macro.i71 = "\\o{7,1}"
+macro.i81 = "\\o{8,1}"
+macro.i91 = "\\o{9,1}"
+macro.img = "\\image"
+macro.endquote = "\\endquotation"
+
+spurious = "Missing comma in .*" \
+ "Missing pattern .*"
+
+# Doxygen compatibility commands
+
+macro.see = "\\sa"
+macro.function = "\\fn"
+
+# qt-cpp-ignore.qdocconf
+
+Cpp.ignoretokens = QAXFACTORY_EXPORT \
+ QDESIGNER_COMPONENTS_LIBRARY \
+ QDESIGNER_EXTENSION_LIBRARY \
+ QDESIGNER_SDK_LIBRARY \
+ QDESIGNER_SHARED_LIBRARY \
+ QDESIGNER_UILIB_LIBRARY \
+ QM_EXPORT_CANVAS \
+ QM_EXPORT_DNS \
+ QM_EXPORT_DOM \
+ QM_EXPORT_FTP \
+ QM_EXPORT_HTTP \
+ QM_EXPORT_ICONVIEW \
+ QM_EXPORT_NETWORK \
+ QM_EXPORT_OPENGL \
+ QM_EXPORT_SQL \
+ QM_EXPORT_TABLE \
+ QM_EXPORT_WORKSPACE \
+ QM_EXPORT_XML \
+ QT_ASCII_CAST_WARN \
+ QT_ASCII_CAST_WARN_CONSTRUCTOR \
+ QT_BEGIN_HEADER \
+ QT_DESIGNER_STATIC \
+ QT_END_HEADER \
+ QT_FASTCALL \
+ QT_WIDGET_PLUGIN_EXPORT \
+ Q_COMPAT_EXPORT \
+ Q_CORE_EXPORT \
+ Q_EXPLICIT \
+ Q_EXPORT \
+ Q_EXPORT_CODECS_CN \
+ Q_EXPORT_CODECS_JP \
+ Q_EXPORT_CODECS_KR \
+ Q_EXPORT_PLUGIN \
+ Q_GFX_INLINE \
+ Q_GUI_EXPORT \
+ Q_GUI_EXPORT_INLINE \
+ Q_GUI_EXPORT_STYLE_CDE \
+ Q_GUI_EXPORT_STYLE_COMPACT \
+ Q_GUI_EXPORT_STYLE_MAC \
+ Q_GUI_EXPORT_STYLE_MOTIF \
+ Q_GUI_EXPORT_STYLE_MOTIFPLUS \
+ Q_GUI_EXPORT_STYLE_PLATINUM \
+ Q_GUI_EXPORT_STYLE_POCKETPC \
+ Q_GUI_EXPORT_STYLE_SGI \
+ Q_GUI_EXPORT_STYLE_WINDOWS \
+ Q_GUI_EXPORT_STYLE_WINDOWSXP \
+ QHELP_EXPORT \
+ Q_INLINE_TEMPLATE \
+ Q_INTERNAL_WIN_NO_THROW \
+ Q_NETWORK_EXPORT \
+ Q_OPENGL_EXPORT \
+ Q_OUTOFLINE_TEMPLATE \
+ Q_SQL_EXPORT \
+ Q_SVG_EXPORT \
+ Q_SCRIPT_EXPORT \
+ Q_TESTLIB_EXPORT \
+ Q_TYPENAME \
+ Q_XML_EXPORT \
+ Q_XMLSTREAM_EXPORT \
+ Q_XMLPATTERNS_EXPORT \
+ QDBUS_EXPORT \
+ QT_BEGIN_NAMESPACE \
+ QT_BEGIN_INCLUDE_NAMESPACE \
+ QT_END_NAMESPACE \
+ QT_END_INCLUDE_NAMESPACE \
+ PHONON_EXPORT \
+ EXTENSIONSYSTEM_EXPORT
+Cpp.ignoredirectives = Q_DECLARE_HANDLE \
+ Q_DECLARE_INTERFACE \
+ Q_DECLARE_METATYPE \
+ Q_DECLARE_OPERATORS_FOR_FLAGS \
+ Q_DECLARE_PRIVATE \
+ Q_DECLARE_PUBLIC \
+ Q_DECLARE_SHARED \
+ Q_DECLARE_TR_FUNCTIONS \
+ Q_DECLARE_TYPEINFO \
+ Q_DISABLE_COPY \
+ QT_FORWARD_DECLARE_CLASS \
+ Q_DUMMY_COMPARISON_OPERATOR \
+ Q_ENUMS \
+ Q_FLAGS \
+ Q_INTERFACES \
+ __attribute__ \
+ K_DECLARE_PRIVATE \
+ PHONON_OBJECT \
+ PHONON_HEIR
+
+
+
+HTML.stylesheets = classic.css
+HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \
+ "<tr>\n" \
+ "<td align=\"left\" valign=\"top\" width=\"32\">" \
+ "<img src=\"images/qt-logo.png\" align=\"left\" width=\"32\" height=\"32\" border=\"0\" />" \
+ "</td>\n" \
+ "<td width=\"1\">&nbsp;&nbsp;</td>" \
+ "<td class=\"postheader\" valign=\"center\">" \
+ "<a href=\"qtcreator-manual.html\">" \
+ "<font color=\"#004faf\">Home</font></a>" \
+ "</td>\n" \
+ "<td align=\"right\" valign=\"top\" width=\"230\"></td></tr></table><br>"
+
+HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \
+ "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \
+ "<td width=\"30%\" align=\"left\">Copyright &copy; 2008 Nokia</td>\n" \
+ "<td width=\"40%\" align=\"center\">&nbsp;</td>\n" \
+ "<td width=\"30%\" align=\"right\"><div align=\"right\">Qt Creator 0.9</div></td>\n" \
+ "</tr></table></div></address>"
diff --git a/doc/runframework.dia b/doc/runframework.dia
new file mode 100644
index 0000000000..5ecb76d917
--- /dev/null
+++ b/doc/runframework.dia
Binary files differ
diff --git a/doc/trolltech-logo.png b/doc/trolltech-logo.png
new file mode 100644
index 0000000000..19e3789d50
--- /dev/null
+++ b/doc/trolltech-logo.png
Binary files differ
diff --git a/doc/workbench.qdoc b/doc/workbench.qdoc
new file mode 100644
index 0000000000..033b1ae7d4
--- /dev/null
+++ b/doc/workbench.qdoc
@@ -0,0 +1,98 @@
+/*!
+ \page index.html
+ \title Workbench
+
+ Workbench is Trolltech's crossplatform IDE. The core of Workbench is
+ basically only a \l{Plugin Loader Framework}{plugin loader} comparable to
+ Eclipse. All major functionality is then added via plugins. The plugins
+ necessary for a full IDE will be provided by Trolltech, possible addons or
+ replacements of existing plugins can be provided by anyone. This means that
+ there will be a place where plugins can be shared.
+
+ The main features of Workbench are:
+
+ \list
+ \o Fast since it's written in C++
+ \o Easy and fast to use (the entire IDE can be controlled via short cuts)
+ \o Highly extensible
+ \o Integrated C++ language support, i.e. code completion, class browser, ...
+ \o Integrated debugger framework and outstanding support for gdb
+ \o Integrated Qt Designer
+ \o Qtopia Integration
+ \endlist
+
+ \section1 Plugins
+
+ As already mentioned, Workbench is basically only a plugin loader framework
+ which gets its IDE functionality through plugins. The most important plugin
+ is the QWorkbench plugin which provides all the basic functionality needed
+ later to integrate e.g. editors or tool windows.
+
+ \table
+ \header
+ \o Plugin Name
+ \o Description
+
+ \row
+ \o \l{QWorkbench Plugin} {QWorkbench}
+ \o The core plugin. Provides the main window and managers for editors,
+ actions, tool windows and files, just to mention the most important ones.
+
+ \endtable
+
+*/
+
+/*!
+ \page classes.html
+ \title Workbench Classes and Namespaces
+
+ \section1 Classes
+
+ \generatelist classes
+
+ \section1 Namespaces
+
+ \generatelist{namespaces}
+*/
+
+/*!
+ \page interfaces.html
+ \title Interfaces
+ \generatelist mainclasses
+
+*/
+
+/*!
+ \page functions.html
+ \title Member Function Index
+ \generatelist functionindex
+*/
+
+/*!
+ \group pluginloader
+
+ \title Plugin Loader Framework
+*/
+
+/*!
+ \group qwb
+
+ \title QWorkbench Plugin
+*/
+
+/*!
+ \namespace Trolltech
+*/
+
+/*!
+ \namespace Trolltech::QWorkbench
+*/
+
+/*!
+ \namespace Trolltech::QWorkbench::Internal
+ \brief Classes that manage and control internal features of the workbench environment.
+*/
+
+/*!
+ \namespace ExtensionSystem
+*/
diff --git a/doc/workbench.qtdocconf b/doc/workbench.qtdocconf
new file mode 100644
index 0000000000..7a82c2aac6
--- /dev/null
+++ b/doc/workbench.qtdocconf
@@ -0,0 +1,147 @@
+project = Workbench
+description = Workbench SDK Documentation
+
+language = Cpp
+
+headerdirs = . \
+ ../src/libs/extensionsystem \
+ ../src/plugins/core \
+ ../src/plugins/core/actionmanager
+
+sourcedirs = . \
+ ../src/libs/extensionsystem \
+ ../src/plugins/core \
+ ../src/plugins/core/actionmanager
+
+headers.fileextesnions = "*.h"
+sources.fileextensions = "*.cpp *.qdoc"
+
+imagedirs = .
+
+indexes = $QTDIR/doc/html/qt.index
+
+outputdir = ./html
+base = file:./html
+versionsym = 1.0.0
+defines = Q_QDOC \
+ QT_.*_SUPPORT \
+ QT_.*_LIB \
+ QT_COMPAT \
+ QT_KEYPAD_NAVIGATION \
+ QT3_SUPPORT \
+ Q_WS_.* \
+ Q_OS_.* \
+ Q_BYTE_ORDER \
+ __cplusplus
+
+codeindent = 1
+extraimages.HTML = qt-logo \
+ trolltech-logo
+
+macro.br.HTML = "<br />"
+macro.QD = "\\e{Qt Designer}"
+macro.QA = "\\e{Qt Assistant}"
+macro.eacute.HTML = "&eacute;"
+macro.aring.HTML = "&aring;"
+macro.oslash.HTML = "&oslash;"
+macro.ouml.HTML = "&ouml;"
+macro.Auml.HTML = "&Auml;"
+macro.uuml.HTML = "&uuml;"
+macro.starslash = "\\c{*/}"
+
+Cpp.ignoretokens = QAXFACTORY_EXPORT \
+ QDESIGNER_COMPONENTS_LIBRARY \
+ QDESIGNER_EXTENSION_LIBRARY \
+ QDESIGNER_SDK_LIBRARY \
+ QDESIGNER_SHARED_LIBRARY \
+ QDESIGNER_UILIB_LIBRARY \
+ QM_EXPORT_CANVAS \
+ QM_EXPORT_DNS \
+ QM_EXPORT_DOM \
+ QM_EXPORT_FTP \
+ QM_EXPORT_HTTP \
+ QM_EXPORT_ICONVIEW \
+ QM_EXPORT_NETWORK \
+ QM_EXPORT_OPENGL \
+ QM_EXPORT_SQL \
+ QM_EXPORT_TABLE \
+ QM_EXPORT_WORKSPACE \
+ QM_EXPORT_XML \
+ QT_ASCII_CAST_WARN \
+ QT_BEGIN_HEADER \
+ QT_DESIGNER_STATIC \
+ QT_END_HEADER \
+ QT_WIDGET_PLUGIN_EXPORT \
+ Q_COMPAT_EXPORT \
+ Q_CORE_EXPORT \
+ Q_EXPLICIT \
+ Q_EXPORT \
+ Q_EXPORT_CODECS_CN \
+ Q_EXPORT_CODECS_JP \
+ Q_EXPORT_CODECS_KR \
+ Q_EXPORT_PLUGIN \
+ Q_GFX_INLINE \
+ Q_GUI_EXPORT \
+ Q_GUI_EXPORT_INLINE \
+ Q_GUI_EXPORT_STYLE_CDE \
+ Q_GUI_EXPORT_STYLE_COMPACT \
+ Q_GUI_EXPORT_STYLE_MAC \
+ Q_GUI_EXPORT_STYLE_MOTIF \
+ Q_GUI_EXPORT_STYLE_MOTIFPLUS \
+ Q_GUI_EXPORT_STYLE_PLATINUM \
+ Q_GUI_EXPORT_STYLE_POCKETPC \
+ Q_GUI_EXPORT_STYLE_SGI \
+ Q_GUI_EXPORT_STYLE_WINDOWS \
+ Q_GUI_EXPORT_STYLE_WINDOWSXP \
+ Q_INLINE_TEMPLATE \
+ Q_NETWORK_EXPORT \
+ Q_OPENGL_EXPORT \
+ Q_OUTOFLINE_TEMPLATE \
+ Q_SQL_EXPORT \
+ Q_SVG_EXPORT \
+ Q_SCRIPT_EXPORT \
+ Q_TESTLIB_EXPORT \
+ Q_TYPENAME \
+ Q_XML_EXPORT \
+ QDBUS_EXPORT
+Cpp.ignoredirectives = Q_DECLARE_HANDLE \
+ Q_DECLARE_INTERFACE \
+ Q_DECLARE_METATYPE \
+ Q_DECLARE_OPERATORS_FOR_FLAGS \
+ Q_DECLARE_PRIVATE \
+ Q_DECLARE_PUBLIC \
+ Q_DECLARE_SHARED \
+ Q_DECLARE_TR_FUNCTIONS \
+ Q_DECLARE_TYPEINFO \
+ Q_DISABLE_COPY \
+ Q_DUMMY_COMPARISON_OPERATOR \
+ Q_ENUMS \
+ Q_FLAGS \
+ Q_INTERFACES \
+ __attribute__
+
+HTML.stylesheets = classic.css
+HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \
+ "<tr>\n" \
+ "<td align=\"left\" valign=\"top\" width=\"32\">" \
+ "<a href=\"http://www.trolltech.com/products/qt\"><img src=\"images/qt-logo.png\" align=\"left\" width=\"32\" height=\"32\" border=\"0\" /></a>" \
+ "</td>\n" \
+ "<td width=\"1\">&nbsp;&nbsp;</td>" \
+ "<td class=\"postheader\" valign=\"center\">" \
+ "<a href=\"index.html\">" \
+ "<font color=\"#004faf\">Home</font></a>&nbsp;&middot;" \
+ " <a href=\"classes.html\">" \
+ "<font color=\"#004faf\">All&nbsp;Classes</font></a>&nbsp;&middot;" \
+ " <a href=\"interfaces.html\">" \
+ "<font color=\"#004faf\">All&nbsp;Interfaces</font></a>&nbsp;&middot;" \
+ " <a href=\"functions.html\">" \
+ "<font color=\"#004faf\">Functions</font></a>" \
+ "</td>\n" \
+ "<td align=\"right\" valign=\"top\" width=\"230\"><a href=\"http://www.trolltech.com\"><img src=\"images/trolltech-logo.png\" align=\"right\" width=\"203\" height=\"32\" border=\"0\" /></a></td></tr></table>"
+
+HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \
+ "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \
+ "<td width=\"30%\">Copyright &copy; \$THISYEAR\$ <a href=\"trolltech.html\">Trolltech</a></td>\n" \
+ "<td width=\"40%\" align=\"center\"><a href=\"trademarks.html\">Trademarks</a></td>\n" \
+ "<td width=\"30%\" align=\"right\"><div align=\"right\">Qt \\version</div></td>\n" \
+ "</tr></table></div></address>"
diff --git a/examples/scripting/demo.js b/examples/scripting/demo.js
new file mode 100644
index 0000000000..396423b654
--- /dev/null
+++ b/examples/scripting/demo.js
@@ -0,0 +1,346 @@
+// This script file demos the scripting features
+// of Qt Creator.
+// Choose "Run" from the context menu.
+
+function introspect(o, indent)
+{
+ core.messageManager.printToOutputPane(indent + "+++++++++++++ Class " + o);
+ for (i in o) {
+ var member = o[i];
+ var t = typeof member;
+ core.messageManager.printToOutputPane(indent + typeof o[i] + " " + i);
+ if (t == "object")
+ introspect(i, indent + " ");
+ }
+
+}
+
+function introspectToString(o)
+{
+ var rc = "";
+ for (i in o) {
+ rc = rc + " " + typeof o[i] + " " + i;
+ }
+ return rc;
+}
+
+function demoInputDialogs()
+{
+ var t = getText(core.mainWindow, "Input dialogs", "text", "default");
+ if (t == null)
+ return;
+
+ core.messageManager.printToOutputPane("Input :" +t);
+ var i = getInteger(core.mainWindow, "Input dialogs", "integer", 42, 0, 1000);
+ if (i == null)
+ return;
+
+ core.messageManager.printToOutputPane("Input :" +i);
+ var d = getDouble(core.mainWindow, "Input dialogs", "double", 42.0, 0.0, 1000.0);
+ if (d == null)
+ return;
+ core.messageManager.printToOutputPane("Input :" +d);
+}
+
+function demoFileDialogs()
+{
+ var f = getOpenFileName(core.mainWindow, "Choose file", "", "All files (*.*)");
+ if (f == null)
+ return;
+
+ core.messageManager.printToOutputPane("File:" + f);
+
+ f = getOpenFileNames(core.mainWindow, "Choose files", "", "All files (*.*)");
+
+ if (f == null)
+ return;
+
+ core.messageManager.printToOutputPane("Files:" + f);
+
+ f = getSaveFileName(core.mainWindow, "Choose file to write to", "", "All files (*.*)");
+
+ if (f == null)
+ return;
+
+ core.messageManager.printToOutputPane("File:" + f);
+
+ f = getExistingDirectory(core.mainWindow, "Choose directory", "");
+
+ if (f == null)
+ return;
+
+ core.messageManager.printToOutputPane("Directory:" + f);
+}
+
+
+function demoMessageBoxes()
+{
+ critical(core.mainWindow, "Critical", "critical");
+ warning(core.mainWindow, "warning", "warning");
+ information(core.mainWindow, "information", "information");
+ var a = yesNoQuestion(core.mainWindow, "Question", "question");
+ core.messageManager.printToOutputPane("Answer:" +a);
+}
+
+function demoWizard()
+{
+ var filters = new Array("ProjectExplorer.WizardType.Project", "QtCreator::WizardType::File");
+ core.showNewItemDialog(filters);
+}
+
+function demoWidgets()
+{
+ core.mainWindow.windowTitle = "Accessing MainWindow";
+ core.statusBar.showMessage("Accessing StatusBar", 0);
+}
+
+function demoIntrospect()
+{
+ // Not perfect yet
+ introspect(core, "");
+}
+
+function demoFileManager()
+{
+ core.messageManager.printToOutputPane("Recent files:" + core.fileManager.recentFiles);
+ var name = getText(core.mainWindow, "Input file name", "name", "");
+
+ if (core.fileManager.isFileManaged(name) == 0) {
+ core.messageManager.printToOutputPane(name + " is not managed.");
+ return;
+ }
+
+ var mf = core.fileManager.managedFiles(name);
+ var s = mf.length;
+ core.messageManager.printToOutputPane(s + " managed files match " + name);
+ for (var i = 0; i < mf.length; i++) {
+ core.messageManager.printToOutputPane(mf[i].fileName);
+ }
+}
+
+function printEditor(e, indent)
+{
+ var m = indent + "Editor " + e.displayName + ", " + e.kind ;
+ var f = e.file;
+ m = m + " (" + f.fileName + ")";
+ core.messageManager.printToOutputPane(m);
+}
+
+function printEditorList(header, l, indent)
+{
+ core.messageManager.printToOutputPane(header + " (" + l.length + ")");
+ for (var i = 0; i < l.length; i++) {
+ printEditor(l[i]," ");
+ }
+}
+
+function printEditorGroup(g)
+{
+ var m = "Editor Group: " + g.editorCount + " editor(s)";
+ core.messageManager.printToOutputPane(m);
+ printEditorList("Editors of the group", g.editors);
+ var ce = g.currentEditor;
+ if (ce == null) {
+ core.messageManager.printToOutputPane("No current editor in group");
+ } else {
+ printEditor(ce, " ");
+ }
+}
+
+function demoEditorManager()
+{
+ var og = core.editorManager.editorGroups;
+ core.messageManager.printToOutputPane("Editor groups " + og.length);
+ for (var i = 0; i < og.length; i++) {
+ printEditorGroup(og[i]);
+ }
+
+ printEditorList("Opened editors", core.editorManager.openedEditors);
+
+ var ce = core.editorManager.currentEditor;
+ if (ce == null) {
+ core.messageManager.printToOutputPane("No current editor");
+ return;
+ }
+
+ core.messageManager.printToOutputPane("Current editor");
+ printEditor(ce, "");
+
+ var f = getOpenFileName(core.mainWindow, "Choose file to open", "", "All files (*.*)");
+ if (f == null)
+ return;
+
+ printEditor(core.editorManager.openEditor(f, ""), "");
+// printEditor(core.editorManager.newFile("Text", "title", "contents"));
+// var dup = ce.duplicate(core.mainWindow);
+}
+
+function demoDebugger()
+{
+ var state = gdbdebugger.status;
+ core.messageManager.printToOutputPane("State " + state);
+ // TODO: Start debugger on demand?
+ if (state != 0)
+ gdbdebugger.sendCommand("help");
+}
+
+// -- ProjectExplorer
+function printProjectItem(pi, indent, recursively)
+{
+ var m = indent + "ProjectItem " + pi.kind + " " + pi.name;
+ core.messageManager.printToOutputPane(m);
+ if (recursively != 0) {
+ var rIndent = indent + " ";
+ var c = projectExplorer.childrenOf(pi);
+ for (var i = 0; i < c.length; i++) {
+ printProjectItem(c[i], rIndent, 1);
+ }
+ }
+}
+
+function printSession(s, indent)
+{
+ core.messageManager.printToOutputPane(indent + "Session " + s.name + " startup project " + s.startupProject);
+ var p = s.projects;
+ var pIndent = indent + " ";
+ for (var i = 0; i < p.length; i++) {
+ printProjectItem(p[i], pIndent, 1);
+ }
+}
+
+function demoProjectExplorer()
+{
+ core.messageManager.printToOutputPane("ProjectExplorer");
+ projectExplorer.buildManager.showOutputWindow(1);
+ projectExplorer.buildManager.addMessage("Build manager message");
+ projectExplorer.applicationOutputWindow.clear();
+ projectExplorer.applicationOutputWindow.appendOutput("Hi, there! .. This the projectExplorer demo");
+
+ var ci = projectExplorer.currentItem;
+ if (ci != null) {
+ core.messageManager.printToOutputPane("Current Item");
+ printProjectItem(ci, " ", 0);
+ } else {
+ core.messageManager.printToOutputPane("No current Item");
+ }
+ var cp = projectExplorer.currentProject;
+ if (cp != null) {
+ core.messageManager.printToOutputPane("Current Project");
+ printProjectItem(cp, " ", 0);
+ } else {
+ core.messageManager.printToOutputPane("No current Project");
+ }
+
+ var cs = projectExplorer.session;
+ if (cs != null) {
+ core.messageManager.printToOutputPane("Current Session");
+ printSession(cs, " ");
+ // Ask to build
+ var p = projectExplorer.needsBuild(cs.projects[0]);
+ for (var i = 0; i < p.length; i++) {
+ if (yesNoQuestion(core.mainWindow, "Rebuild", "Do you want to rebuild " + p[i].name + "?") != 65536) {
+ if (p[i].supportsProjectCommand(2)) {
+ p[i].executeProjectCommand(2);
+ } else {
+ core.messageManager.printToOutputPane("Build not supported.");
+ }
+ }
+ }
+ } else {
+ core.messageManager.printToOutputPane("No current Session");
+ var a = yesNoQuestion(core.mainWindow, "Open Session", "Do you want to open a session?");
+ if (a != 65536) {
+ var f = getOpenFileNames(core.mainWindow, "Choose a session", "", "All projects (*.qws *.pro)");
+ if (f == null)
+ return;
+ var o = projectExplorer.openProject(f);
+ return;
+ }
+ }
+ if (yesNoQuestion(core.mainWindow, "Build manager", "Do you want run a command using build mananger?") != 65536) {
+ var cmd = new BuildManagerCommand("ls", "-l");
+ var cmds =new Array(cmd);
+ core.messageManager.printToOutputPane("Let build mananger run a command " + cmds + " (see compile window)");
+ projectExplorer.buildManager.start(cmds);
+ }
+}
+
+// --------------- MAIN
+
+var features = new Array("Input dialogs",
+ "File dialogs",
+ "Messages",
+ "Project Explorer",
+ "Message Manager",
+ "Wizard",
+ "Editor manager",
+ "File manager",
+ "Introspect",
+ "Widgets magic",
+ "Debugger");
+
+core.messageManager.printToOutputPane(" +++ demo.js " + Date());
+
+while (1) {
+ var f = getItem(core.mainWindow, "Choose a demo", "Available demos", features, 0);
+ if (f == null)
+ return;
+
+ while (1) {
+ if (f == features[0]) {
+ demoInputDialogs();
+ break;
+ }
+
+ if (f == features[1]) {
+ demoFileDialogs();
+ break;
+ }
+
+ if (f == features[2]) {
+ demoMessageBoxes();
+ break;
+ }
+
+ if (f == features[3]) {
+ demoProjectExplorer();
+ break;
+ }
+
+ if (f == features[4]) {
+ core.messageManager.printToOutputPane("Hi there!",1);
+ break;
+ }
+
+ if (f == features[5]) {
+ demoWizard();
+ break;
+ }
+
+ if (f == features[6]) {
+ demoEditorManager();
+ break;
+ }
+
+ if (f == features[7]) {
+ demoFileManager();
+ break;
+ }
+
+ if (f == features[8]) {
+ demoIntrospect();
+ break;
+ }
+
+ if (f == features[9]) {
+ demoWidgets();
+ break;
+ }
+
+ if (f == features[10]) {
+ demoDebugger();
+ break;
+ }
+ break;
+ }
+}
diff --git a/fix_makefile_header_dependencies.sh b/fix_makefile_header_dependencies.sh
new file mode 100755
index 0000000000..eae6819a19
--- /dev/null
+++ b/fix_makefile_header_dependencies.sh
@@ -0,0 +1,52 @@
+#! /usr/bin/env bash
+
+WORKER=./fill_deps.sh
+DEPFILE=deps
+
+write_deps_file() {
+ INPUT=$1
+ ESCAPED_OUTPUT=`sed 's/\//\\\\\//g' <<<"$1"`
+
+ {
+ echo '#! /usr/bin/env bash'
+ grep '^\(CXXFLAGS\|INCPATH\|DEFINES\)' ${INPUT} \
+ | sed \
+ -e 's/$(\([^)]\+\))/${\1}/g' \
+ -e 's/"/\\"/g' \
+ -e 's/^\([^ ]\+\) *= *\(.\+\)/\1="\2"/'
+ echo
+ echo 'touch deps'
+ grep '^.$(CXX)' ${INPUT} \
+ | grep -v '$@' \
+ | sed \
+ -e 's/^\t\$(CXX)\(.\+\)$/makedepend \1 -w 1000000 -f '${DEPFILE}' -p "" -a -o .o 2>\/dev\/null/' \
+ -e 's/$(\([^)]\+\))/${\1}/g' \
+ -e 's/\\/\//g'
+ } > "${WORKER}"
+ chmod a+x "${WORKER}"
+}
+
+
+
+PWD_BACKUP=$PWD
+
+while read makefile ; do
+ dir=`dirname "${makefile}"`
+ if [ `find "${dir}" -maxdepth 1 -name '*.cpp' | wc -l 2>/dev/null` -ge 1 ]; then
+ echo "Directory: $dir"
+ cd $dir
+ rm -f "${DEPFILE}"
+ write_deps_file Makefile
+ "${WORKER}"
+ TEMPFILE=`mktemp`
+ sed 's/^.\+\/\([^\/]\+.o:\)/\1/' "${DEPFILE}" > "${TEMPFILE}"
+ mv "${TEMPFILE}" "${DEPFILE}"
+ # rm "${WORKER}"
+
+ cd ${PWD_BACKUP}
+ echo "include ${DEPFILE}" >> "${makefile}"
+ fi
+done < <(find src -name 'Makefile')
+
+cd ${PWD_BACKUP}
+
diff --git a/installer/TODO.txt b/installer/TODO.txt
new file mode 100644
index 0000000000..57aed14430
--- /dev/null
+++ b/installer/TODO.txt
@@ -0,0 +1,12 @@
+<all>
+- installdir whitespace check done.
+- installdir exist/non-empty check
+
+<linux>
+- run '/bin/xdg-desktop-install.sh' if '/usr/bin/xdg-mime exists'
+- desktop shortcut
+
+<windows>
+- create dir '${env(APPDATA)}/Trolltech'
+- start menue shortcuts
+
diff --git a/installer/installer.cpp b/installer/installer.cpp
new file mode 100644
index 0000000000..54ade16ce4
--- /dev/null
+++ b/installer/installer.cpp
@@ -0,0 +1,433 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+// This file contains the QtCreator-specific part of the installer.
+// It lists the files and features the installer should handle.
+
+#include "qinstaller.h"
+#include "qinstallergui.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QObject>
+
+#include <QtGui/QApplication>
+#include <QtGui/QBoxLayout>
+#include <QtGui/QGridLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QMessageBox>
+
+
+// QInstallerGui is base of the Gui part of an installer, i.e.
+// the "main installer wizard". In the simplest case it's just
+// a sequence of "standard" wizard pages. A few commonly used
+// ones are provided already in qinstallergui.h.
+
+
+// A custom target directory selection based due to the no-space
+// restriction...
+
+class TargetDirectoryPage : public QInstallerTargetDirectoryPage
+{
+public:
+ TargetDirectoryPage(QInstaller *installer)
+ : QInstallerTargetDirectoryPage(installer)
+ {
+ m_noSpaceLabel = new QLabel(this);
+ m_noSpaceLabel->setText("The directory name should not contain any space.");
+ m_noSpaceLabel->hide();
+ insertWidget(m_noSpaceLabel, "MessageLabel");
+ }
+
+ bool isComplete() const
+ {
+ bool invalid = targetDir().contains(' ');
+ QPalette palette;
+ // We show the warning only if the user types a space.
+ // No need to scare him if the path is ok for us...
+ if (invalid) {
+ m_noSpaceLabel->show();
+ palette.setColor(QPalette::WindowText, Qt::red);
+ }
+ m_noSpaceLabel->setPalette(palette);
+ return !invalid;
+ }
+
+ int nextId() const
+ {
+ QFileInfo fi(targetDir());
+
+ if (isVisible() && fi.isDir()) {
+ QFileInfo fi2(targetDir() + '/' + installer()->uninstallerName());
+ if (fi2.exists()) {
+ QMessageBox::StandardButton bt = QMessageBox::warning(wizard(),
+ tr("Warning"),
+ tr("The directory you selected exists already and contains an installaion.\n"
+ "Do you want to overwrite it?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::No)
+ return wizard()->currentId();
+ } else {
+ QMessageBox::StandardButton bt = QMessageBox::warning(wizard(),
+ tr("Warning"),
+ tr("The directory you selected exists already.\n"
+ "Do you want to remove it and continue?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::No)
+ return wizard()->currentId();
+ }
+ }
+ return QInstallerPage::nextId();
+ }
+
+private:
+ QLabel *m_noSpaceLabel;
+};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QtCreatorInstallerGui
+//
+////////////////////////////////////////////////////////////////////
+
+// QtCreatorInstallerGui is the QtCreator specific incarnation
+// of a QInstallerGui.
+
+class QtCreatorInstallerGui : public QInstallerGui
+{
+public:
+ QtCreatorInstallerGui(QInstaller *installer)
+ {
+ // The Gui has access to the installer backend at construction
+ // time. For later access it needs to store the QInstaller *
+ // pointer provided. Not needed in this case here.
+
+ setWindowTitle(tr("%1 Setup").arg(installer->value("ProductName")));
+ installer->connectGui(this);
+
+ // We are happy with the default set of pages.
+ addPage(new QInstallerIntroductionPage(installer));
+ addPage(new QInstallerLicenseAgreementPage(installer));
+ //addPage(new QInstallerTargetDirectoryPage(installer));
+ addPage(new TargetDirectoryPage(installer));
+ if (installer->componentCount() > 1)
+ addPage(new QInstallerComponentSelectionPage(installer));
+ addPage(new QInstallerReadyForInstallationPage(installer));
+ addPage(new QInstallerPerformInstallationPage(installer));
+ addPage(new QInstallerFinishedPage(installer));
+
+ setStartId(installer->value("GuiStartPage").toInt());
+ }
+};
+
+
+// QInstaller is base of the "backend" part of an installer, i.e.
+// the part handling the installer tasks and keeping track of
+// related data like the directory to install to, the name of
+// the Product, version of the Product etc.
+
+// QtCreatorInstaller is the QtCreator specific incarnation
+// of a QInstaller. It needs to list all tasks that a performed
+// during installation. The tasks themselves specify what to
+// do at uninstall time.
+
+class QtCreatorInstaller : public QInstaller
+{
+public:
+ QtCreatorInstaller()
+ {
+ // basic product information
+ setValue("ProductName", "Qt Creator");
+ setValue("ProductVersion", "alpha");
+
+ // registration information
+ setValue("Comments", "");
+ setValue("Contact", "");
+ setValue("DisplayVersion", "");
+ setValue("HelpLink", "");
+ setValue("Publisher", "");
+ setValue("UrlAboutInfo", "");
+
+ // information needed at installer generation time
+ setValue("OutputFile", "qtcreator-installer");
+ setValue("RunProgram", "@TargetDir@/bin/qtcreator");
+
+ // default component selection, overridable from command line
+ setValue("UseQtCreator", "true");
+#ifdef Q_OS_WIN
+ //setValue("UseQt", "true");
+ //setValue("UseMinGW", "true");
+#endif
+ }
+
+private:
+ // tasks related to QtCreator itself. Binary, libraries etc.
+ void appendQtCreatorComponent()
+ {
+ QString sourceDir = value("SourceDir");
+ if (sourceDir.isEmpty() && QFileInfo("../bin/qtcreator").isReadable())
+ sourceDir = QLatin1String("..");
+ if (sourceDir.isEmpty())
+ throw QInstallerError("Missing 'SourceDir=<dir>' on command line.");
+ QInstallerComponent *component = new QInstallerComponent(this);
+ component->setValue("Name", "QtCreator");
+ component->setValue("DisplayName", "Qt Creator");
+ component->setValue("Description", "The Qt Creator IDE");
+ component->setValue("SuggestedState", "AlwaysInstalled");
+#ifdef Q_OS_MAC
+ component->appendDirectoryTasks(sourceDir + "/bin/QtCreator.app", "@TargetDir@");
+#else
+ component->appendDirectoryTasks(sourceDir + "/bin", "@TargetDir@/bin");
+ component->appendDirectoryTasks(sourceDir + "/lib", "@TargetDir@/lib");
+#endif
+
+ QInstallerPatchFileTask *task = new QInstallerPatchFileTask(this);
+ task->setTargetPath("@TargetDir@/lib/Trolltech/" + libraryName("ProjectExplorer", "1.0.0"));
+ task->setNeedle("Clear Session");
+ task->setReplacement("CLEAR SESSION");
+ component->appendTask(task);
+
+ appendComponent(component);
+ }
+
+ void appendMinGWComponent()
+ {
+ QString mingwSourceDir = value("MinGWSourceDir");
+ if (mingwSourceDir.isEmpty())
+ throw QInstallerError("Missing 'MinGWSourceDir=<dir>' on command line.");
+ QInstallerComponent *component = new QInstallerComponent(this);
+ component->setValue("Name", "MinGW");
+ component->setValue("DisplayName", "MinGW");
+ component->setValue("Description",
+ "The MinGW environment including the g++ compiler "
+ "and the gdb debugger.");
+ component->setValue("SuggestedState", "Installed");
+ component->appendDirectoryTasks(mingwSourceDir, "@TargetDir@");
+ appendComponent(component);
+ }
+
+ void appendQtComponent()
+ {
+ QString qtSourceDir = value("QtSourceDir");
+ if (qtSourceDir.isEmpty())
+ throw QInstallerError("Missing 'QtSourceDir=<dir>' on command line.");
+
+ QInstallerComponent *component = new QInstallerComponent(this);
+ component->setValue("Name", "Qt Development Libraries");
+ component->setValue("DisplayName", "Qt");
+ component->setValue("Description",
+ "The Qt library files for development including "
+ "documentation");
+ component->setValue("SuggestedState", "Installed");
+ component->appendDirectoryTasks(qtSourceDir, "@TargetDir@");
+
+#ifdef Q_OS_WIN
+ static const struct
+ {
+ const char *fileName;
+ const char *sourceLocation;
+ } libs[] = {
+ {"/bin/Qt3Support", "/src/qt3support/"},
+ {"/bin/QtCore", "/src/corelib/"},
+ {"/bin/QtGui", "/src/gui/"},
+ {"/bin/QtHelp", "/tools/assistant/lib/"},
+ {"/bin/QtNetwork", "/src/network/"},
+ {"/bin/QtOpenGL", "/src/opengl/"},
+ {"/bin/QtScript", "/src/script/"},
+ {"/bin/QtSql", "/src/sql/"},
+ {"/bin/QtSvg", "/src/svg/"},
+ {"/bin/QtTest", "/src/testlib/"},
+ {"/bin/QtWebKit", "/src/3rdparty/webkit/WebCore/"},
+ {"/bin/QtXml", "/src/xml/"},
+ {"/bin/QtXmlPatterns", "/src/xmlpatterns/"},
+ {"/plugins/accessible/qtaccessiblecompatwidgets",
+ "/src/plugins/accessible/compat/"},
+ {"/plugins/accessible/qtaccessiblewidgets",
+ "/src/plugins/accessible/widgets/"},
+ {"/plugins/codecs/qcncodecs", "/src/plugins/codecs/cn/"},
+ {"/plugins/codecs/qjpcodecs", "/src/plugins/codecs/jp/"},
+ {"/plugins/codecs/qkrcodecs", "/src/plugins/codecs/kr/"},
+ {"/plugins/codecs/qtwcodecs", "/src/plugins/codecs/tw/"},
+ {"/plugins/iconengines/qsvgicon", "/src/plugins/iconengines/svgiconengine/"},
+ {"/plugins/imageformats/qgif", "/src/plugins/imageformats/gif/"},
+ {"/plugins/imageformats/qjpeg", "/src/plugins/imageformats/jpeg/"},
+ {"/plugins/imageformats/qmng", "/src/plugins/imageformats/mng/"},
+ {"/plugins/imageformats/qsvg", "/src/plugins/imageformats/svg/"},
+ {"/plugins/imageformats/qtiff", "/src/plugins/imageformats/tiff/"},
+ {"/plugins/sqldrivers/qsqlite", "/src/plugins/sqldrivers/sqlite/"},
+ // {"/plugins/sqldrivers/qsqlodbc", "/src/plugins/sqldrivers/odbc/"}
+ };
+
+ QString debug = QLatin1String("d4.dll");
+
+ for (int i = 0; i != sizeof(libs) / sizeof(libs[0]); ++i) {
+ QInstallerPatchFileTask *task = new QInstallerPatchFileTask(this);
+ task->setTargetPath(QString("@TargetDir@/") + libs[i].fileName + debug);
+ task->setNeedle("f:/depot/qt");
+ task->setReplacement(QByteArray("@TargetDir@/") + libs[i].sourceLocation);
+ component->appendTask(task);
+ }
+#endif
+
+ appendComponent(component);
+ }
+
+ void createTasks()
+ {
+ // set UseXXX=false on command line to prevent inclusion of the
+ // respective component
+ if (value("UseQtCreator") == "true")
+ appendQtCreatorComponent();
+ if (value("UseMinGW") == "true")
+ appendMinGWComponent();
+ if (value("UseQt") == "true")
+ appendQtComponent();
+ }
+};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QtCreatorUninstallerGui
+//
+////////////////////////////////////////////////////////////////////
+
+class QtCreatorUninstallerGui : public QObject
+{
+public:
+ QtCreatorUninstallerGui(QInstaller *installer)
+ : m_installer(installer)
+ {}
+
+ int exec()
+ {
+ QMessageBox::StandardButton bt = QMessageBox::question(0,
+ tr("Question"),
+ tr("Do you want to deinstall %1 and all of its modules?")
+ .arg(m_installer->value("ProductName")),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+ if (bt == QMessageBox::No)
+ return 0;
+ QWizard wizard;
+ wizard.addPage(new QInstallerPerformUninstallationPage(m_installer));
+ wizard.show();
+ return qApp->exec();
+ }
+
+private:
+ QInstaller *m_installer;
+};
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// The Main Driver Program
+//
+////////////////////////////////////////////////////////////////////
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QStringList args = app.arguments();
+ qDebug() << "ARGS: " << args;
+
+ QtCreatorInstaller installer;
+
+ bool helpRequested = false;
+ bool guiRequested = true;
+
+ for (int i = 1; i < args.size(); ++i) {
+ if (args.at(i).contains('=')) {
+ const QString arg = args.at(i);
+ const QString name = arg.section('=', 0, 0);
+ const QString value = arg.section('=', 1, 1);
+ installer.setValue(name, value);
+ } else if (args.at(i) == "--help" || args.at(i) == "-h") {
+ helpRequested = true;
+ } else if (args.at(i) == "--no-gui" || args.at(i) == "NoGui") {
+ qDebug() << "NOGUI";
+ guiRequested = false;
+ } else if (args.at(i) == "--verbose" || args.at(i) == "Verbose") {
+ installer.setVerbose(true);
+ } else {
+ helpRequested = true;
+ }
+ }
+
+ if (installer.isVerbose())
+ installer.dump();
+
+ if (helpRequested) {
+ QString productName = installer.value("ProductName");
+ QString str;
+ if (installer.isCreator())
+ str = QString(" [SourceDir=<dir>]\n"
+ "\n Creates the %1 installer.\n").arg(productName);
+ else if (installer.isInstaller())
+ str = QString(" [--no-gui] [<name>=<value>...]\n"
+ "\n Runs the %1 installer\n"
+ "\n If the '--no-gui' parameter is given, it runs "
+ " installer without GUI\n").arg(productName);
+ else if (installer.isUninstaller())
+ str = QString(" [<name>=<value>...]\n"
+ "\n Runs the %1 uninstaller.\n").arg(productName);
+ str = "\nUsage: " + installer.installerBinaryPath() + str;
+ qDebug() << qPrintable(str);
+ return 0;
+ }
+
+ if (installer.isInstaller() && guiRequested) {
+ QtCreatorInstallerGui gui(&installer);
+ gui.show();
+ return app.exec();
+ }
+
+#ifdef Q_OS_WIN
+ if (installer.isUninstaller()) {
+ QStringList newArgs = args;
+ newArgs.removeFirst();
+ installer.restartTempUninstaller(newArgs);
+ return 0;
+ }
+#endif
+ if ((installer.isUninstaller() || installer.isTempUninstaller())
+ && guiRequested) {
+ QtCreatorUninstallerGui gui(&installer);
+ //gui.show();
+ return gui.exec();
+ }
+
+ return installer.run() ? 0 : 1;
+}
diff --git a/installer/installer.pro b/installer/installer.pro
new file mode 100644
index 0000000000..d9e59651de
--- /dev/null
+++ b/installer/installer.pro
@@ -0,0 +1,29 @@
+TEMPLATE = app
+TARGET = installercreator
+DEPENDPATH += .
+INCLUDEPATH += .
+
+CONFIG -= debug
+CONFIG += release
+
+HEADERS += \
+ qinstaller.h \
+ qinstallergui.h \
+
+SOURCES += \
+ qinstaller.cpp \
+ qinstallergui.cpp \
+ installer.cpp \
+
+RESOURCES += \
+ installer.qrc \
+
+true {
+ OBJECTS_DIR = .tmp/
+ MOC_DIR = .tmp/
+ RCC_DIR = .tmp/
+ UI_DIR = .tmp/
+}
+
+win32:LIBS += ole32.lib
+
diff --git a/installer/installer.qrc b/installer/installer.qrc
new file mode 100644
index 0000000000..5080febcd6
--- /dev/null
+++ b/installer/installer.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/logo.png</file>
+ <file>resources/watermark.png</file>
+ <file>resources/license.txt</file>
+</qresource>
+</RCC>
diff --git a/installer/qinstaller.cpp b/installer/qinstaller.cpp
new file mode 100644
index 0000000000..2144af60f1
--- /dev/null
+++ b/installer/qinstaller.cpp
@@ -0,0 +1,1872 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qinstaller.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
+#include <QtCore/QFile>
+#include <QtCore/QHash>
+#include <QtCore/QProcess>
+#include <QtCore/QSettings>
+
+#ifdef Q_OS_WIN
+#include "qt_windows.h"
+#include <shlobj.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*
+ FIXME: Documentation
+
+NAME = "Name";
+DISPLAY_NAME = "DisplayName";
+DESCRIPTION = "Description";
+TASK_COUNT = "TaskCount";
+SIZE = "ComponentSize";
+OUTPUT_FILE = "OutputFile";
+WANTED_STATE = "WantedState";
+SUGGESTED_STATE = "SuggestedState";
+PRODUCT_NAME = "ProductName";
+GUI_START_PAGE = "GuiStartPage";
+RUN_PROGRAM = "RunProgram";
+COMMENTS = "Comments";
+CONTACT = "Contact";
+DISPLAY_VERSION = "DisplayVersion";
+ESTIMATED_SIZE = "EstimatedSize";
+HELP_LINK = "HelpLink";
+INSTALL_DATE = "InstallDate";
+INSTALL_LOCATION = "InstallLocation";
+NO_MODIFY = "NoModify";
+NO_REPAIR = "NoRepair";
+PUBLISHER = "Publisher";
+UNINSTALL_STRING = "UninstallString";
+URL_INFO_ABOUT = "UrlInfoAbout";
+LOGO_PIXMAP
+WATERMARK_PIXMAP
+*/
+
+
+//static qint64 magicInstallerMarker = (0xdea0d345UL << 32) + 0x12023233UL;
+//static qint64 magicUninstallerMarker = (0xdea0d345UL << 32) + 0x12023234UL;
+static const qint64 magicInstallerMarker = 0x12023233UL;
+static const qint64 magicUninstallerMarker = 0x12023234UL;
+static const qint64 magicTempUninstallerMarker = 0x12023235UL;
+
+// Installer Layout:
+//
+// 0000: <binary: installer code>
+// ...
+// $comptask[0]: <int: $ctc[0]: 1st component task count>
+// $comptask[0][0]: <task: first component task data>
+// ...
+// $comptask[0][$ctc0-1]: <task: first component task data>
+// ...
+// $comptask[$ncomp-1]: <int : $cnn: last component task data>
+// $comptask[$ncomp-1][0]: <task: last component task data>
+// ...
+// $comtaskp[$ncomp-1][$ctc-1]: <task: last component task data>
+// $compvars[0]: <dict: $cn0: first component variables>
+// ...
+// $compvars[$ncomp-1]: <dict: $cnn: last component var data>
+// $comptaskoffsets: <int: $comptask[0]: offset>
+// <int: $comptask[1]: offset>
+// ...
+// $compvarsoffsets: <int: $compvars[0]: offset>
+// <int: $compvars[1]: offset>
+// ...
+// $installervars: <dict: installer variable data>
+// ...
+// end - 7: <int: $comptask[0]: start of comp.tasks>
+// end - 6: <int: $compvars[0]: start of .vars>
+// end - 5: <int: $ncomp: number of components>
+// end - 4: <int: $comptaskoffsets>
+// end - 3: <int: $compvarsoffsets>
+// end - 2: <int: $installervars: offset installer vars>
+// end - 1: <int: magic marker>
+//
+// The stuff after the binary is not present in the "Creator" incarnation
+
+////////////////////////////////////////////////////////////////////
+//
+// Misc helpers
+//
+////////////////////////////////////////////////////////////////////
+
+namespace {
+
+#define ifVerbose(s) if (!installer()->isVerbose()) {} else { qDebug() << s; }
+
+
+QDebug &operator<<(QDebug &os, QInstallerTask *task)
+{
+ task->dump(os);
+ return os;
+}
+
+class Dictionary : public QHash<QString, QString>
+{
+public:
+ typedef QHash<QString, QString> BaseType;
+
+ void setValue(const QString &key, const QString &val)
+ {
+ insert(key, val);
+ }
+
+ void removeTemporaryKeys()
+ {
+ foreach (const QString &key, keys())
+ if (key.startsWith('@'))
+ remove(key);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class Error : public QInstallerError
+{
+public:
+ Error(const QString &m)
+ : QInstallerError(m) {}
+ // convenience
+ Error(const char *m, int n)
+ : QInstallerError(QString(QLatin1String(m)).arg(n)) {}
+ Error(const char *m, const QString & n)
+ : QInstallerError(QString(QLatin1String(m)).arg(n)) {}
+private:
+private:
+ QString m_message;
+};
+
+} // anonymous namespace
+
+static void openForWrite(QFile &file)
+{
+ if (!file.open(QIODevice::WriteOnly))
+ throw Error("Cannot open file %1 for writing", file.fileName());
+}
+
+static void openForRead(QFile &file)
+{
+ if (!file.open(QIODevice::ReadOnly))
+ throw Error("Cannot open file %1 for reading", file.fileName());
+}
+
+static void rawWrite(QIODevice *out, const char *buffer, qint64 size)
+{
+ while (size > 0) {
+ qint64 n = out->write(buffer, size);
+ if (n == -1)
+ throw Error("RAW WRITE FAILED: %1", size);
+ size -= n;
+ }
+}
+
+static void rawRead(QIODevice *in, char *buffer, qint64 size)
+{
+ while (size > 0) {
+ qint64 n = in->read(buffer, size);
+ size -= n;
+ buffer += n;
+ if (size != 0)
+ qDebug() << "COULD ONLY READ " << n << "OF" << size + n << "BYTES";
+ }
+}
+
+static inline QByteArray &theBuffer(int size)
+{
+ static QByteArray b;
+ if (size > b.size())
+ b.reserve(size * 3 / 2);
+ return b;
+}
+
+
+#if 0
+// Faster or not?
+static void appendFileData(QIODevice *out, const QString &fileName)
+{
+ QFile file(fileName);
+ openForRead(file);
+ qint64 size = file.size();
+ QInstaller::appendInt(out, size);
+ if (size == 0)
+ return;
+ uchar *data = file.map(0, size);
+ if (!data)
+ throw Error(QInstaller::tr("Cannot map file %1").arg(file.fileName()));
+ rawWrite(out, (const char *)data, size);
+ if (!file.unmap(data))
+ throw Error(QInstaller::tr("Cannot unmap file %1").arg(file.fileName()));
+}
+#endif
+
+static void appendFileData(QIODevice *out, QIODevice *in)
+{
+ Q_ASSERT(!in->isSequential());
+ qint64 size = in->size();
+ QByteArray &b = theBuffer(size);
+ rawRead(in, b.data(), size);
+ QInstaller::appendInt(out, size);
+ rawWrite(out, b.constData(), size);
+}
+
+static void retrieveFileData(QIODevice *out, QIODevice *in)
+{
+ qint64 size = QInstaller::retrieveInt(in);
+ QByteArray &b = theBuffer(size);
+ rawRead(in, b.data(), size);
+ rawWrite(out, b.constData(), size);
+}
+
+static void appendData(QIODevice *out, QIODevice *in, qint64 size)
+{
+ QByteArray &b = theBuffer(size);
+ rawRead(in, b.data(), size);
+ rawWrite(out, b.constData(), size);
+}
+
+static void appendInt(QIODevice *out, qint64 n)
+{
+ rawWrite(out, (char*)&n, sizeof(n));
+}
+
+static void appendString(QIODevice *out, const QString &str)
+{
+ int n = str.size();
+ appendInt(out, n);
+ rawWrite(out, (char*)str.utf16(), n * sizeof(QChar));
+}
+
+static void appendByteArray(QIODevice *out, const QByteArray &ba)
+{
+ appendInt(out, ba.size());
+ rawWrite(out, ba.constData(), ba.size());
+}
+
+static void appendDictionary(QIODevice *out, const Dictionary &dict)
+{
+ appendInt(out, dict.size());
+ foreach (const QString &key, dict.keys()) {
+ appendString(out, key);
+ appendString(out, dict.value(key));
+ }
+}
+
+static qint64 retrieveInt(QIODevice *in)
+{
+ qint64 n = 0;
+ in->read((char*)&n, sizeof(n));
+ return n;
+}
+
+static QString retrieveString(QIODevice *in)
+{
+ static QByteArray b;
+ qint64 n = retrieveInt(in);
+ if (n * int(sizeof(QChar)) > b.size())
+ b.reserve(n * sizeof(QChar) * 3 / 2);
+ in->read(b.data(), n * sizeof(QChar));
+ QString str((QChar *)b.data(), n);
+ return str;
+}
+
+static QByteArray retrieveByteArray(QIODevice *in)
+{
+ QByteArray ba;
+ qint64 n = retrieveInt(in);
+ ba.resize(n);
+ rawRead(in, ba.data(), n);
+ return ba;
+}
+
+static Dictionary retrieveDictionary(QIODevice *in)
+{
+ Dictionary dict;
+ for (qint64 i = retrieveInt(in); --i >= 0; ) {
+ QString key = retrieveString(in);
+ dict.insert(key, retrieveString(in));
+ }
+ return dict;
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerComponent::Private
+//
+////////////////////////////////////////////////////////////////////
+
+class QInstallerComponent::Private
+{
+public:
+ QInstaller *m_installer;
+ Dictionary m_vars;
+ QList<QInstallerTask *> m_tasks;
+
+ // filled before intaller runs
+ qint64 m_offsetInInstaller;
+};
+
+#if 0
+
+// this is dead slow as QDirIterator::Private::advance needlessly
+// creates tons of QFileInfo objects
+
+static void listDir
+ (const QString &sourcePath0, const QString &targetPath0,
+ QList<QInstallerTask *> *copyTasks,
+ QList<QInstallerTask *> *linkTasks,
+ int sourcePathLength)
+{
+ Q_UNUSED(sourcePathLength);
+ QDirIterator it(sourcePath0, QDir::Files, QDirIterator::Subdirectories);
+ const int pos = sourcePath0.size();
+ while (it.hasNext()) {
+ QString sourcePath = it.next();
+ QFileInfo sourceInfo = it.fileInfo();
+ if (sourceInfo.isSymLink()) {
+ QFileInfo absSourceInfo(sourceInfo.absoluteFilePath());
+ //QString linkTarget = sourceInfo.symLinkTarget();
+ QString absLinkTarget = absSourceInfo.symLinkTarget();
+ //QString relPath = sourceInfo.dir().relativeFilePath(linkTarget);
+ QString absRelPath = absSourceInfo.dir().relativeFilePath(absLinkTarget);
+ if (0) {
+ ifVerbose("\n\nCREATING LINK: "
+ << "\nSOURCE : " << sourceInfo.filePath()
+ << "\nSOURCE ABS: " << absSourceInfo.filePath()
+ //<< "\nLINK : " << linkTarget
+ << "\nLINK ABS: " << absLinkTarget
+ //<< "\nREL : " << relPath
+ << "\nREL ABS: " << absRelPath);
+ }
+ QString targetPath = targetPath0;
+ targetPath += sourcePath.midRef(pos);
+ //qDebug() << "LINK " << absRelPath << targetPath << targetPath0;
+ QInstallerLinkFileTask *task = new QInstallerLinkFileTask(m_installer);
+ task->setLinkTargetPath(absRelPath);
+ task->setTargetPath(targetPath);
+ task->setPermissions(sourceInfo.permissions());
+ linkTasks->append(task);
+ } else {
+ QInstallerCopyFileTask *task = new QInstallerCopyFileTask(m_installer);
+ QString targetPath = targetPath0;
+ targetPath += sourcePath.midRef(pos);
+ //qDebug() << "COPY " << sourcePath << targetPath << targetPath0;
+ task->setSourcePath(sourcePath);
+ task->setTargetPath(targetPath);
+ task->setPermissions(sourceInfo.permissions());
+ copyTasks.append(task);
+ }
+ }
+}
+#else
+
+static void listDir
+ (const QString &sourcePath, const QString &targetPath0,
+ QList<QInstallerTask *> *copyTasks,
+ QList<QInstallerTask *> *linkTasks,
+ QInstaller *installer,
+ int sourcePathLength = -1)
+
+{
+ if (sourcePathLength == -1)
+ sourcePathLength = sourcePath.size();
+ QFileInfo sourceInfo(sourcePath);
+ if (sourceInfo.isDir()) {
+ QDir dir(sourcePath);
+ dir.setSorting(QDir::Unsorted);
+ foreach (const QFileInfo &fi, dir.entryInfoList()) {
+ QString sourceFile = fi.fileName();
+ if (sourceFile == QLatin1String(".")
+ || sourceFile == QLatin1String(".."))
+ continue;
+ listDir(sourcePath + '/' + sourceFile, targetPath0,
+ copyTasks, linkTasks, installer, sourcePathLength);
+ }
+ } else if (sourceInfo.isSymLink()) {
+ QFileInfo absSourceInfo(sourceInfo.absoluteFilePath());
+ QString absLinkTarget = absSourceInfo.symLinkTarget();
+ QString absRelPath = absSourceInfo.dir().relativeFilePath(absLinkTarget);
+ QString targetPath = targetPath0;
+ targetPath += sourcePath.midRef(sourcePathLength);
+ //qDebug() << "LINK " << absRelPath << targetPath << targetPath0;
+ QInstallerLinkFileTask *task = new QInstallerLinkFileTask(installer);
+ task->setLinkTargetPath(absRelPath);
+ task->setTargetPath(targetPath);
+ task->setPermissions(sourceInfo.permissions());
+ linkTasks->append(task);
+ } else {
+ QInstallerCopyFileTask *task = new QInstallerCopyFileTask(installer);
+ QString targetPath = targetPath0;
+ targetPath += sourcePath.midRef(sourcePathLength);
+ //qDebug() << "COPY " << sourcePath << targetPath << targetPath0;
+ task->setSourcePath(sourcePath);
+ task->setTargetPath(targetPath);
+ task->setPermissions(sourceInfo.permissions());
+ copyTasks->append(task);
+ }
+}
+#endif
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerComponent
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerComponent::QInstallerComponent(QInstaller *installer)
+ : d(new QInstallerComponent::Private)
+{
+ d->m_installer = installer;
+}
+
+
+QInstallerComponent::~QInstallerComponent()
+{
+ qDeleteAll(d->m_tasks);
+ d->m_tasks.clear();
+ delete d;
+}
+
+QString QInstallerComponent::value(const QString &key,
+ const QString &defaultValue) const
+{
+ return d->m_vars.value(key, defaultValue);
+}
+
+void QInstallerComponent::setValue(const QString &key, const QString &value)
+{
+ d->m_vars[key] = value;
+}
+
+void QInstallerComponent::appendDirectoryTasks
+ (const QString &sourcePath0, const QString &targetPath)
+{
+ QList<QInstallerTask *> copyTasks;
+ QList<QInstallerTask *> linkTasks;
+ QString sourcePath = d->m_installer->replaceVariables(sourcePath0);
+ listDir(sourcePath, targetPath, &copyTasks, &linkTasks, d->m_installer);
+ d->m_tasks += copyTasks;
+ d->m_tasks += linkTasks;
+}
+
+void QInstallerComponent::appendSettingsTask
+ (const QString &key, const QString &value)
+{
+ QInstallerWriteSettingsTask *task =
+ new QInstallerWriteSettingsTask(d->m_installer);
+ task->setKey(key);
+ task->setValue(value);
+ appendTask(task);
+}
+
+void QInstallerComponent::appendTask(QInstallerTask *task)
+{
+ d->m_tasks.append(task);
+}
+
+int QInstallerComponent::taskCount() const
+{
+ return d->m_tasks.size();
+}
+
+QInstallerTask *QInstallerComponent::task(int i) const
+{
+ return d->m_tasks.at(i);
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstaller::Private
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerTask *createCopyFileTask(QInstaller *installer)
+{
+ return new QInstallerCopyFileTask(installer);
+}
+
+QInstallerTask *createLinkFileTask(QInstaller *installer)
+{
+ return new QInstallerLinkFileTask(installer);
+}
+
+QInstallerTask *createWriteSettingsTask(QInstaller *installer)
+{
+ return new QInstallerWriteSettingsTask(installer);
+}
+
+QInstallerTask *createPatchFileTask(QInstaller *installer)
+{
+ return new QInstallerPatchFileTask(installer);
+}
+
+QInstallerTask *createMenuShortcutTask(QInstaller *installer)
+{
+ return new QInstallerMenuShortcutTask(installer);
+}
+
+
+
+class QInstaller::Private : public QObject
+{
+ Q_OBJECT;
+
+public:
+ explicit Private(QInstaller *);
+ ~Private();
+
+ void initialize();
+
+ QInstallerTask *createTaskFromCode(int code);
+ void undo(const QList<QInstallerTask *> &tasks);
+ void writeUninstaller(const QList<QInstallerTask *> &tasks);
+ bool statusCanceledOrFailed() const;
+
+ void writeInstaller(QIODevice *out);
+ void writeInstaller();
+ void appendCode(QIODevice *out);
+ void runInstaller();
+ void runUninstaller();
+ void deleteUninstaller();
+ QString uninstallerName() const;
+ QString replaceVariables(const QString &str) const;
+ QByteArray replaceVariables(const QByteArray &str) const;
+ QString registerPath() const;
+ void registerInstaller();
+ void unregisterInstaller();
+ QString installerBinaryPath() const;
+ bool isCreator() const;
+ bool isInstaller() const;
+ bool isUninstaller() const;
+ bool isTempUninstaller() const;
+ QInstaller *installer() const { return q; }
+ bool restartTempUninstaller(const QStringList &args);
+ void setInstallationProgress(qint64 progress); // relative to m_totalProgress
+
+signals:
+ void installationStarted();
+ void installationFinished();
+ void uninstallationStarted();
+ void uninstallationFinished();
+
+public:
+ QInstaller *q;
+
+ Dictionary m_vars;
+ QInstaller::InstallerStatus m_status;
+ bool m_verbose;
+
+ qint64 m_codeSize;
+ qint64 m_tasksStart;
+ qint64 m_variablesStart;
+ qint64 m_componentCount;
+ qint64 m_tasksOffsetsStart;
+ qint64 m_variablesOffsetsStart;
+ qint64 m_variableDataStart;
+ qint64 m_magicMarker;
+
+ int m_installationProgress;
+ int m_totalProgress;
+ QString m_installationProgressText;
+
+ // Owned. Indexed by component name
+ QList<QInstallerComponent *> m_components;
+ QList<QInstaller::TaskCreator> m_taskCreators;
+};
+
+QInstaller::Private::Private(QInstaller *q_)
+ : q(q_), m_status(QInstaller::InstallerUnfinished), m_verbose(false)
+{
+ connect(this, SIGNAL(installationStarted()),
+ q, SIGNAL(installationStarted()));
+ connect(this, SIGNAL(installationFinished()),
+ q, SIGNAL(installationFinished()));
+ connect(this, SIGNAL(uninstallationStarted()),
+ q, SIGNAL(uninstallationStarted()));
+ connect(this, SIGNAL(uninstallationFinished()),
+ q, SIGNAL(uninstallationFinished()));
+}
+
+QInstaller::Private::~Private()
+{
+ qDeleteAll(m_components);
+ m_components.clear();
+}
+
+
+void QInstaller::Private::initialize()
+{
+ m_installationProgress = 0;
+ m_totalProgress = 100;
+
+ m_vars["ProductName"] = "Unknown Product";
+ m_vars["LogoPixmap"] = ":/resources/logo.png";
+ m_vars["WatermarkPixmap"] = ":/resources/watermark.png";
+
+ QFile in(installerBinaryPath());
+ openForRead(in);
+ m_codeSize = in.size();
+
+ // this reads bogus values for 'creators', but it does not harm
+ in.seek(in.size() - 7 * sizeof(qint64));
+ m_tasksStart = retrieveInt(&in);
+ m_variablesStart = retrieveInt(&in);
+ m_componentCount = retrieveInt(&in);
+ m_tasksOffsetsStart = retrieveInt(&in);
+ m_variablesOffsetsStart = retrieveInt(&in);
+ m_variableDataStart = retrieveInt(&in);
+ m_magicMarker = retrieveInt(&in);
+
+ if (isCreator()) {
+ // valgrind complains otherwise
+ m_tasksStart = 0;
+ m_variablesStart = 0;
+ m_componentCount = 0;
+ m_tasksOffsetsStart = 0;
+ m_variablesOffsetsStart = 0;
+ m_variableDataStart = 0;
+ m_magicMarker = 0;
+ } else {
+ // fix code size
+ m_codeSize = m_tasksStart;
+
+ // merge stored variables
+ in.seek(m_variablesStart);
+
+ for (int i = 0; i != m_componentCount; ++i) {
+ QInstallerComponent *component = new QInstallerComponent(q);
+ component->d->m_vars = retrieveDictionary(&in);
+ qDebug() << "DICT " << i << component->d->m_vars;
+ m_components.append(component);
+ }
+
+ // read installer variables
+ Dictionary dict = retrieveDictionary(&in);
+ if (m_verbose)
+ qDebug() << "READ VARIABLES FROM INSTALLER:" << dict;
+ foreach (const QString &key, dict.keys()) {
+ if (!m_vars.contains(key))
+ m_vars.insert(key, dict.value(key));
+ }
+ if (m_verbose)
+ qDebug() << "MERGED VARIABLES:" << m_vars;
+ }
+}
+
+void QInstaller::Private::setInstallationProgress(qint64 progress)
+{
+ // from 0 to m_totalProgress
+ int percent = progress * 100 / m_totalProgress;
+ if (percent == m_installationProgress)
+ return;
+ //qDebug() << "setting progress to " << progress
+ // << " of " << m_totalProgress << " " << percent << "%";
+ m_installationProgress = percent;
+ qApp->processEvents();
+}
+
+QString QInstaller::Private::installerBinaryPath() const
+{
+ return qApp->arguments().at(0);
+}
+
+bool QInstaller::Private::isCreator() const
+{
+ return !isInstaller() && !isUninstaller() && !isTempUninstaller();
+}
+
+bool QInstaller::Private::isInstaller() const
+{
+ return m_magicMarker == magicInstallerMarker;
+}
+
+bool QInstaller::Private::isUninstaller() const
+{
+ return m_magicMarker == magicUninstallerMarker;
+}
+
+bool QInstaller::Private::isTempUninstaller() const
+{
+ return m_magicMarker == magicTempUninstallerMarker;
+}
+
+void QInstaller::Private::writeInstaller()
+{
+ QString fileName = m_vars["OutputFile"];
+#ifdef Q_OS_WIN
+ if (!fileName.endsWith(QLatin1String(".exe")))
+ fileName += QLatin1String(".exe");
+#endif
+ QFile out;
+ out.setFileName(fileName);
+ openForWrite(out);
+ writeInstaller(&out);
+ out.setPermissions(out.permissions() | QFile::WriteUser
+ | QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser);
+}
+
+void QInstaller::Private::writeInstaller(QIODevice *out)
+{
+ appendCode(out);
+
+ QList<qint64> tasksOffsets;
+ QList<qint64> variablesOffsets;
+
+ // write component task data
+ foreach (QInstallerComponent *component, m_components) {
+ qint64 componentStart = out->size();
+ tasksOffsets.append(out->size()); // record start of tasks
+ // pack the component as a whole
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ foreach (QInstallerTask *task, component->d->m_tasks) {
+ appendInt(&buffer, q->indexOfTaskType(task->creator()));
+ task->writeToInstaller(&buffer);
+ }
+ buffer.close();
+ QByteArray compressed = qCompress(buffer.buffer());
+ int uncompressedSize = buffer.buffer().size();
+ int compressedSize = compressed.size();
+ appendByteArray(out, compressed);
+ qDebug() << "COMPRESS: " << uncompressedSize << compressedSize;
+ component->setValue("TaskCount", QString::number(component->d->m_tasks.size()));
+ component->setValue("ComponentStart", QString::number(componentStart));
+ component->setValue("CompressedSize", QString::number(compressedSize));
+ component->setValue("UncompressedSize", QString::number(uncompressedSize));
+ }
+
+ // write component variables
+ foreach (QInstallerComponent *component, m_components) {
+ variablesOffsets.append(out->size()); // record start of variables
+ appendDictionary(out, component->d->m_vars);
+ }
+
+ // append variables except temporary ones
+ qint64 variableDataStart = out->size();
+ Dictionary dict = m_vars;
+ dict.removeTemporaryKeys();
+ appendDictionary(out, dict);
+
+ // append recorded list of component task offsets
+ qint64 taskOffsetsStart = out->size();
+ foreach (qint64 offset, tasksOffsets)
+ appendInt(out, offset);
+
+ // append recorded list of component varaibles offsets
+ qint64 variablesOffsetsStart = out->size();
+ foreach (qint64 offset, variablesOffsets)
+ appendInt(out, offset);
+
+ // append trailer
+ appendInt(out, tasksOffsets[0]);
+ appendInt(out, variablesOffsets[0]);
+ appendInt(out, m_components.size());
+ appendInt(out, taskOffsetsStart);
+ appendInt(out, variablesOffsetsStart);
+ appendInt(out, variableDataStart);
+ appendInt(out, magicInstallerMarker);
+}
+
+bool QInstaller::Private::statusCanceledOrFailed() const
+{
+ return m_status == QInstaller::InstallerCanceledByUser
+ || m_status == QInstaller::InstallerFailed;
+}
+
+QInstallerTask *QInstaller::Private::createTaskFromCode(int code)
+{
+ if (code >= 0 && code < m_taskCreators.size())
+ return m_taskCreators[code](q);
+ throw Error("NO TASK WITH CODE %1 REGISTERED");
+}
+
+void QInstaller::Private::undo(const QList<QInstallerTask *> &tasks)
+{
+ //qDebug() << "REMOVING" << files.size();
+ // tasks.size() corresponds to m_installationProgress;
+ m_totalProgress = tasks.size() * m_installationProgress / 100 + 1;
+ for (int i = tasks.size(); --i >= 0; ) {
+ QInstallerTask *task = tasks.at(i);
+ setInstallationProgress(i);
+ task->undo();
+ }
+ setInstallationProgress(0);
+}
+
+void QInstaller::Private::appendCode(QIODevice *out)
+{
+ QFile in(installerBinaryPath());
+ openForRead(in);
+ if (m_verbose)
+ qDebug() << "CODE SIZE: " << m_codeSize;
+ appendData(out, &in, m_codeSize);
+ in.close();
+}
+
+QString QInstaller::Private::replaceVariables(const QString &str) const
+{
+ QString res;
+ int pos = 0;
+ while (true) {
+ int pos1 = str.indexOf('@', pos);
+ if (pos1 == -1)
+ break;
+ int pos2 = str.indexOf('@', pos1 + 1);
+ if (pos2 == -1)
+ break;
+ res += str.mid(pos, pos1 - pos);
+ QString name = str.mid(pos1 + 1, pos2 - pos1 - 1);
+ res += m_vars.value(name);
+ pos = pos2 + 1;
+ }
+ res += str.mid(pos);
+ return res;
+}
+
+QByteArray QInstaller::Private::replaceVariables(const QByteArray &ba) const
+{
+ QByteArray res;
+ int pos = 0;
+ while (true) {
+ int pos1 = ba.indexOf('@', pos);
+ if (pos1 == -1)
+ break;
+ int pos2 = ba.indexOf('@', pos1 + 1);
+ if (pos2 == -1)
+ break;
+ res += ba.mid(pos, pos1 - pos);
+ QString name = QString::fromLocal8Bit(ba.mid(pos1 + 1, pos2 - pos1 - 1));
+ res += m_vars.value(name).toLocal8Bit();
+ pos = pos2 + 1;
+ }
+ res += ba.mid(pos);
+ return res;
+}
+
+QString QInstaller::Private::uninstallerName() const
+{
+ QString name = m_vars["TargetDir"];
+ name += "/uninstall";
+#ifdef Q_OS_WIN
+ name += QLatin1String(".exe");
+#endif
+ return name;
+}
+
+void QInstaller::Private::writeUninstaller(const QList<QInstallerTask *> &tasks)
+{
+ QFile out(uninstallerName());
+ try {
+ ifVerbose("CREATING UNINSTALLER " << tasks.size());
+ // Create uninstaller. this is basically a clone of ourselves
+ // with a few changed variables
+ openForWrite(out);
+ appendCode(&out);
+ qint64 tasksStart = out.size();
+ appendInt(&out, tasks.size());
+
+ for (int i = tasks.size(); --i >= 0; ) {
+ QInstallerTask *task = tasks.at(i);
+ appendInt(&out, m_taskCreators.indexOf(task->creator()));
+ task->writeToUninstaller(&out); // might throw
+ }
+
+ // append variables except temporary ones
+ qint64 variableDataStart = out.size();
+ Dictionary dict = m_vars;
+ dict.removeTemporaryKeys();
+ dict.setValue(QLatin1String("UninstallerPath"), uninstallerName());
+ appendDictionary(&out, dict);
+
+ // append trailer
+ appendInt(&out, tasksStart);
+ appendInt(&out, variableDataStart); // variablesStart
+ appendInt(&out, 0); // componentCount
+ appendInt(&out, 0); // tasksOffsetsStart
+ appendInt(&out, 0); // variablesOffsetsStart
+ appendInt(&out, variableDataStart);
+ appendInt(&out, magicUninstallerMarker);
+
+ out.setPermissions(out.permissions() | QFile::WriteUser
+ | QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser);
+ }
+ catch (const QInstallerError &err) {
+ m_status = QInstaller::InstallerFailed;
+ // local roll back
+ qDebug() << "WRITING TO UNINSTALLER FAILED: " << err.message();
+ out.close();
+ out.remove();
+ throw;
+ }
+}
+
+QString QInstaller::Private::registerPath() const
+{
+ QString productName = m_vars["ProductName"];
+ if (productName.isEmpty())
+ throw QInstallerError("ProductName should be set");
+ QString path;
+ if (m_vars["AllUsers"] == "true")
+ path += "HKEY_LOCAL_MACHINE";
+ else
+ path += "HKEY_CURRENT_USER";
+ path += "\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
+ path += productName;
+ return path;
+}
+
+void QInstaller::Private::registerInstaller()
+{
+#ifdef Q_OS_WIN
+ QSettings settings(registerPath(), QSettings::NativeFormat);
+ settings.beginGroup("CurrentVersion");
+ settings.beginGroup("Uninstall");
+ settings.beginGroup(m_vars["ProductName"]);
+ settings.setValue("Comments", m_vars["Comments"]);
+ settings.setValue("Contact", m_vars["Contact"]);
+ settings.setValue("DisplayName", m_vars["ProductName"]);
+ settings.setValue("DisplayVersion", m_vars["DisplayVersion"]);
+ settings.setValue("EstimatedSize", "X4957efb0");
+ settings.setValue("HelpLink", m_vars["HelpLink"]);
+ settings.setValue("InstallDate", QDateTime::currentDateTime().toString());
+ settings.setValue("InstallLocation", m_vars["TargetDir"]);
+ settings.setValue("NoModify", "1");
+ settings.setValue("NoRepair", "1");
+ settings.setValue("Publisher", m_vars["Publisher"]);
+ settings.setValue("UninstallString", uninstallerName());
+ settings.setValue("UrlInfoAbout", m_vars["UrlInfoAbout"]);
+#endif
+}
+
+void QInstaller::Private::unregisterInstaller()
+{
+#ifdef Q_OS_WIN
+ QSettings settings(registerPath(), QSettings::NativeFormat);
+ settings.remove(QString());
+#endif
+}
+
+void QInstaller::Private::runInstaller()
+{
+ QList<QInstallerTask *> tasks;
+
+ try {
+ emit installationStarted();
+ if (!m_vars.contains("TargetDir"))
+ throw QInstallerError(QLatin1String("Variable 'TargetDir' not set."));
+
+ QFile in(installerBinaryPath());
+ openForRead(in);
+
+ m_totalProgress = 0;
+ QList<QInstallerComponent *> componentsToInstall;
+
+ for (int i = 0; i != m_componentCount; ++i) {
+ QInstallerComponent *comp = m_components.at(i);
+ QString wantedState = comp->value("WantedState");
+ ifVerbose("HANDLING COMPONENT" << i << "WANTED: " << wantedState);
+ if (wantedState == "Uninstalled") {
+ qDebug() << "SKIPPING COMPONENT" << comp->value("DisplayName");
+ continue;
+ }
+ componentsToInstall.append(comp);
+ m_totalProgress += comp->value("UncompressedSize").toInt();
+ }
+
+ qDebug() << "Install size: " << m_totalProgress
+ << "in " << componentsToInstall.size() << "components";
+
+ qint64 lastProgressBase = 0;
+ foreach (QInstallerComponent *comp, componentsToInstall) {
+ int taskCount = comp->value("TaskCount").toInt();
+ quint64 componentStart = comp->value("ComponentStart").toInt();
+ in.seek(componentStart);
+ if (statusCanceledOrFailed())
+ throw Error("Installation canceled by user");
+ m_installationProgressText =
+ tr("Decompressing component %1").arg(comp->value("DisplayName"));
+ qApp->processEvents();
+ QByteArray compressed = retrieveByteArray(&in);
+ QByteArray uncompressed = qUncompress(compressed);
+ if (uncompressed.isEmpty()) {
+ qDebug() << "SIZE: " << compressed.size() << " TASK COUNT: " << taskCount
+ << uncompressed.size();
+ throw Error("DECOMPRESSION FAILED");
+ }
+ QBuffer buffer(&uncompressed);
+ buffer.open(QIODevice::ReadOnly);
+ for (int j = 0; j != taskCount; ++j) {
+ int code = retrieveInt(&buffer);
+ QInstallerTask *task = createTaskFromCode(code); // might throw
+ task->readAndExecuteFromInstaller(&buffer); // might throw
+ tasks.append(task);
+ if (statusCanceledOrFailed())
+ throw Error("Installation canceled by user");
+ setInstallationProgress(lastProgressBase + buffer.pos());
+ }
+ comp->setValue("CurrentState", "Installed");
+ lastProgressBase += uncompressed.size();
+ }
+ in.close();
+
+ registerInstaller();
+ writeUninstaller(tasks);
+
+ m_status = InstallerSucceeded;
+ m_installationProgressText = tr("Installation finished!");
+ qApp->processEvents();
+ emit installationFinished();
+ }
+ catch (const QInstallerError &err) {
+ installer()->showWarning(err.message());
+ qDebug() << "INSTALLER FAILED: " << err.message() << "\nROLLING BACK";
+ undo(tasks);
+ m_installationProgressText = tr("Installation aborted");
+ qApp->processEvents();
+ emit installationFinished();
+ throw;
+ }
+}
+
+bool QInstaller::Private::restartTempUninstaller(const QStringList &args)
+{
+#ifdef Q_OS_WIN
+ ifVerbose("Running uninstaller on Windows.");
+ if (isUninstaller()) {
+ QString uninstallerFile = installerBinaryPath();
+ QDir tmpDir = QDir::temp();
+ QString tmpDirName = QLatin1String("qtcreator_uninst");
+ QString tmpAppName = QLatin1String("uninst.exe");
+ if (!tmpDir.exists(tmpDirName)) {
+ tmpDir.mkdir(tmpDirName);
+ if (!tmpDir.exists(tmpDirName)) {
+ ifVerbose("Could not create temporary folder!");
+ return false;
+ }
+ tmpDir.cd(tmpDirName);
+ }
+
+ if (tmpDir.exists(tmpAppName) && !tmpDir.remove(tmpAppName)) {
+ ifVerbose("Could not remove old temporary uninstaller!");
+ return false;
+ }
+
+ QString tmpUninstaller = tmpDir.absoluteFilePath(tmpAppName);
+
+ QFile in(uninstallerFile);
+ if (!in.open(QIODevice::ReadOnly)) {
+ ifVerbose("Cannot open uninstall.exe!");
+ return false;
+ }
+
+ QFile out(tmpUninstaller);
+ if (!out.open(QIODevice::WriteOnly)) {
+ ifVerbose("Cannot open temporary uninstall.exe!");
+ return false;
+ }
+
+ QByteArray ba = in.readAll();
+ QBuffer buf(&ba);
+ buf.open(QIODevice::ReadWrite);
+ buf.seek(buf.size() - sizeof(qint64));
+ appendInt(&buf, magicTempUninstallerMarker);
+ if (in.size() != out.write(buf.data())) {
+ ifVerbose("Could not copy uninstaller!");
+ return false;
+ }
+
+ in.close();
+ out.close();
+
+ MoveFileExW((TCHAR*)tmpUninstaller.utf16(),
+ 0, MOVEFILE_DELAY_UNTIL_REBOOT|MOVEFILE_REPLACE_EXISTING);
+
+ STARTUPINFOW sInfo;
+ PROCESS_INFORMATION pInfo;
+ memset(&sInfo, 0, sizeof(sInfo));
+ memset(&pInfo, 0, sizeof(pInfo));
+ sInfo.cb = sizeof(sInfo);
+
+ QString cmd = QString("\"%1\"").arg(tmpUninstaller);
+ foreach (const QString &s, args)
+ cmd.append(QLatin1String(" \"") + s + QLatin1String("\""));
+ if (CreateProcessW(0, (TCHAR*)cmd.utf16(), 0, 0, false, 0, 0, 0, &sInfo, &pInfo)) {
+ CloseHandle(pInfo.hThread);
+ CloseHandle(pInfo.hProcess);
+ ifVerbose("Started temp uninstaller.");
+ } else {
+ ifVerbose("Cannot launch uninstaller!");
+ return false;
+ }
+ }
+#else
+ Q_UNUSED(args);
+#endif
+ return true;
+}
+
+void QInstaller::Private::runUninstaller()
+{
+ QFile uninstaller(installerBinaryPath());
+ openForRead(uninstaller);
+ QByteArray ba = uninstaller.readAll();
+ uninstaller.close();
+
+ emit uninstallationStarted();
+#ifndef Q_OS_WIN
+ // remove uninstaller binary itself. Also necessary for successful
+ // removal of the application directory.
+ uninstaller.remove();
+#else
+ if (m_vars.contains(QLatin1String("UninstallerPath"))) {
+ QFile orgUninstaller(m_vars.value(QLatin1String("UninstallerPath")));
+ orgUninstaller.remove();
+ }
+#endif
+
+ // read file
+ QBuffer in(&ba);
+ in.open(QIODevice::ReadOnly);
+ in.seek(m_tasksStart);
+ qint64 taskCount = retrieveInt(&in);
+ ifVerbose("FOUND " << taskCount << "UNINSTALLER TASKS");
+
+ m_totalProgress = m_variablesStart;
+ for (int i = 0; i != taskCount; ++i) {
+ int code = retrieveInt(&in);
+ QInstallerTask *task = createTaskFromCode(code);
+ task->readAndExecuteFromUninstaller(&in);
+ setInstallationProgress(in.pos());
+ }
+ in.close();
+
+ unregisterInstaller();
+
+ m_installationProgressText = tr("Deinstallation finished");
+ qApp->processEvents();
+ emit uninstallationFinished();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstaller
+//
+////////////////////////////////////////////////////////////////////
+
+QInstaller::QInstaller()
+{
+ d = new Private(this);
+ d->initialize();
+ registerTaskType(createCopyFileTask);
+ registerTaskType(createLinkFileTask);
+ registerTaskType(createPatchFileTask);
+ registerTaskType(createWriteSettingsTask);
+ registerTaskType(createMenuShortcutTask);
+}
+
+QInstaller::~QInstaller()
+{
+ delete d;
+}
+
+void QInstaller::appendComponent(QInstallerComponent *component)
+{
+ d->m_components.append(component);
+}
+
+int QInstaller::componentCount() const
+{
+ return d->m_components.size();
+}
+
+QInstallerComponent *QInstaller::component(int i) const
+{
+ return d->m_components.at(i);
+}
+
+void QInstaller::registerTaskType(TaskCreator tc)
+{
+ d->m_taskCreators.append(tc);
+}
+
+int QInstaller::indexOfTaskType(TaskCreator tc) const
+{
+ return d->m_taskCreators.indexOf(tc);
+}
+
+QString QInstaller::value(const QString &key, const QString &defaultValue) const
+{
+ return d->m_vars.value(key, defaultValue);
+}
+
+void QInstaller::setValue(const QString &key, const QString &value)
+{
+ d->m_vars[key] = value;
+}
+
+bool QInstaller::containsValue(const QString &key) const
+{
+ return d->m_vars.contains(key);
+}
+
+bool QInstaller::isVerbose() const
+{
+ return d->m_verbose;
+}
+
+void QInstaller::setVerbose(bool on)
+{
+ d->m_verbose = on;
+}
+
+QInstaller::InstallerStatus QInstaller::status() const
+{
+ return d->m_status;
+}
+
+void QInstaller::interrupt()
+{
+ qDebug() << "INTERRUPT INSTALLER";
+ d->m_status = InstallerCanceledByUser;
+}
+
+QString QInstaller::replaceVariables(const QString &str) const
+{
+ return d->replaceVariables(str);
+}
+
+QByteArray QInstaller::replaceVariables(const QByteArray &ba) const
+{
+ return d->replaceVariables(ba);
+}
+
+int QInstaller::installationProgress() const
+{
+ return d->m_installationProgress;
+}
+
+void QInstaller::setInstallationProgressText(const QString &value)
+{
+ d->m_installationProgressText = value;
+}
+
+QString QInstaller::installationProgressText() const
+{
+ return d->m_installationProgressText;
+}
+
+QString QInstaller::installerBinaryPath() const
+{
+ return d->installerBinaryPath();
+}
+
+bool QInstaller::isCreator() const
+{
+ return d->isCreator();
+}
+
+bool QInstaller::isInstaller() const
+{
+ return d->isInstaller();
+}
+
+bool QInstaller::isUninstaller() const
+{
+ return d->isUninstaller();
+}
+
+bool QInstaller::isTempUninstaller() const
+{
+ return d->isTempUninstaller();
+}
+
+bool QInstaller::runInstaller()
+{
+ try { d->runInstaller(); return true; } catch (...) { return false; }
+}
+
+bool QInstaller::runUninstaller()
+{
+ try { d->runUninstaller(); return true; } catch (...) { return false; }
+}
+
+void QInstaller::showWarning(const QString &str)
+{
+ emit warning(str);
+}
+
+void QInstaller::dump() const
+{
+ qDebug() << "COMMAND LINE VARIABLES:" << d->m_vars;
+}
+
+void QInstaller::appendInt(QIODevice *out, qint64 n)
+{
+ QT_PREPEND_NAMESPACE(appendInt)(out, n);
+}
+
+void QInstaller::appendString(QIODevice *out, const QString &str)
+{
+ QT_PREPEND_NAMESPACE(appendString)(out, str);
+}
+
+void QInstaller::appendByteArray(QIODevice *out, const QByteArray &str)
+{
+ QT_PREPEND_NAMESPACE(appendByteArray)(out, str);
+}
+
+qint64 QInstaller::retrieveInt(QIODevice *in)
+{
+ return QT_PREPEND_NAMESPACE(retrieveInt)(in);
+}
+
+QString QInstaller::retrieveString(QIODevice *in)
+{
+ return QT_PREPEND_NAMESPACE(retrieveString)(in);
+}
+
+QByteArray QInstaller::retrieveByteArray(QIODevice *in)
+{
+ return QT_PREPEND_NAMESPACE(retrieveByteArray)(in);
+}
+
+bool QInstaller::run()
+{
+ try {
+ if (isCreator()) {
+ createTasks(); // implemented in derived classes
+ d->writeInstaller();
+ } else if (isInstaller()) {
+ d->runInstaller();
+ } else if (isUninstaller() || isTempUninstaller()) {
+ runUninstaller();
+ }
+ return true;
+ } catch (const QInstallerError &err) {
+ qDebug() << "Caught Installer Error: " << err.message();
+ return false;
+ }
+}
+
+QString QInstaller::uninstallerName() const
+{
+ return d->uninstallerName();
+}
+
+QString QInstaller::libraryName(const QString &baseName, const QString &version)
+{
+#ifdef Q_OS_WIN
+ return baseName + QLatin1String(".dll");
+#elif Q_OS_MAC
+ return QString("lib%1.dylib").arg(baseName);
+#else
+ return QString("lib%1.so.%2").arg(baseName).arg(version);
+#endif
+}
+
+bool QInstaller::restartTempUninstaller(const QStringList &args)
+{
+ return d->restartTempUninstaller(args);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerTask
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerTask::QInstallerTask(QInstaller *parent)
+ : m_installer(parent)
+{}
+
+QInstaller *QInstallerTask::installer() const
+{
+ return m_installer;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerCopyFileTask
+//
+////////////////////////////////////////////////////////////////////
+
+QInstaller::TaskCreator QInstallerCopyFileTask::creator() const
+{
+ return &createCopyFileTask;
+}
+
+void QInstallerCopyFileTask::writeToInstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+ appendInt(out, m_permissions);
+ QFile file(m_sourcePath);
+ openForRead(file);
+ appendFileData(out, &file);
+}
+
+static int createParentDirs(const QString &absFileName)
+{
+ QFileInfo fi(absFileName);
+ if (fi.isDir())
+ return 0;
+ QString dirName = fi.path();
+ int n = createParentDirs(dirName);
+ QDir dir(dirName);
+ dir.mkdir(fi.fileName());
+ return n + 1;
+}
+
+void QInstallerCopyFileTask::readAndExecuteFromInstaller(QIODevice *in)
+{
+ m_targetPath = installer()->replaceVariables(retrieveString(in));
+ m_permissions = retrieveInt(in);
+ ifVerbose("EXECUTE COPY FILE, TARGET " << m_targetPath);
+
+ QString path = QDir::cleanPath(QFileInfo(m_targetPath).absolutePath());
+ m_parentDirCount = createParentDirs(path);
+ QString msg = QInstaller::tr("Copying file %1").arg(m_targetPath);
+ installer()->setInstallationProgressText(msg);
+
+ QFile file(m_targetPath);
+ bool res = file.open(QIODevice::WriteOnly);
+ if (!res) {
+ // try to make it writeable, and try again
+ bool res1 = file.setPermissions(file.permissions()|QFile::WriteOwner);
+ ifVerbose("MAKE WRITABLE: " << res1);
+ res = file.open(QIODevice::WriteOnly);
+ }
+ if (!res) {
+ // try to remove it, and try again
+ bool res1 = file.remove();
+ ifVerbose("REMOVING FILE: " << res1);
+ res = file.open(QIODevice::WriteOnly);
+ }
+
+ if (!res) {
+ QString msg = QInstaller::tr("The file %1 is not writeable.")
+ .arg(m_targetPath);
+ installer()->showWarning(msg);
+ throw Error(msg);
+ }
+ retrieveFileData(&file, in);
+ QFile::Permissions perms(m_permissions | QFile::WriteOwner);
+ file.close();
+ file.setPermissions(perms);
+}
+
+void QInstallerCopyFileTask::writeToUninstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+ appendInt(out, m_parentDirCount);
+}
+
+void QInstallerCopyFileTask::readAndExecuteFromUninstaller(QIODevice *in)
+{
+ m_targetPath = retrieveString(in);
+ m_parentDirCount = retrieveInt(in);
+ undo();
+}
+
+void QInstallerCopyFileTask::undo()
+{
+ ifVerbose("UNLINKING FILE" << m_targetPath << m_parentDirCount);
+ QString msg = QInstaller::tr("Removing %1").arg(m_targetPath);
+ installer()->setInstallationProgressText(msg);
+
+ QFileInfo fi(m_targetPath);
+ QDir dir(fi.path());
+
+ QFile file(m_targetPath);
+ bool res = file.remove();
+ if (!res) {
+ // try to make it writeable, and try again
+ bool res1 = file.setPermissions(file.permissions()|QFile::WriteOwner);
+ ifVerbose("MAKE WRITABLE: " << res1);
+ res = file.remove();
+ }
+
+ while (res && --m_parentDirCount >= 0) {
+ QString dirName = dir.dirName();
+ dir.cdUp();
+ res = dir.rmdir(dirName);
+ msg = QInstaller::tr("Removing file %1").arg(m_targetPath);
+ installer()->setInstallationProgressText(msg);
+ ifVerbose("REMOVING DIR " << dir.path() << dirName << res);
+ }
+}
+
+void QInstallerCopyFileTask::dump(QDebug & os) const
+{
+ os << "c|" + sourcePath() + '|' + targetPath();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerLinkFileTask
+//
+////////////////////////////////////////////////////////////////////
+
+QInstaller::TaskCreator QInstallerLinkFileTask::creator() const
+{
+ return &createLinkFileTask;
+}
+
+void QInstallerLinkFileTask::writeToInstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+ appendString(out, m_linkTargetPath);
+ appendInt(out, m_permissions);
+}
+
+void QInstallerLinkFileTask::readAndExecuteFromInstaller(QIODevice *in)
+{
+ m_targetPath = installer()->replaceVariables(retrieveString(in));
+ m_linkTargetPath = installer()->replaceVariables(retrieveString(in));
+ m_permissions = retrieveInt(in);
+
+ ifVerbose("LINK " << m_targetPath << " TARGET " << m_linkTargetPath);
+
+ QFile file(m_linkTargetPath);
+ if (file.link(m_targetPath))
+ return;
+
+ // ok. linking failed. try to remove targetPath and link again
+ bool res1 = QFile::remove(m_targetPath);
+ ifVerbose("TARGET EXITS, REMOVE: " << m_targetPath << res1);
+ if (file.link(m_targetPath))
+ return;
+
+ // nothing helped.
+ throw Error(QInstaller::tr("Cannot link file %1 to %2:\n")
+ .arg(m_linkTargetPath).arg(m_targetPath));
+}
+
+void QInstallerLinkFileTask::writeToUninstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+}
+
+void QInstallerLinkFileTask::readAndExecuteFromUninstaller(QIODevice *in)
+{
+ m_targetPath = retrieveString(in);
+ ifVerbose("UNLINKING LINK" << m_targetPath);
+ undo();
+}
+
+void QInstallerLinkFileTask::undo()
+{
+ QFile file(m_targetPath);
+ file.remove();
+}
+
+void QInstallerLinkFileTask::dump(QDebug & os) const
+{
+ os << "l|" + targetPath() + '|' + linkTargetPath();
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerWriteSettingsTask
+//
+////////////////////////////////////////////////////////////////////
+
+QInstaller::TaskCreator QInstallerWriteSettingsTask::creator() const
+{
+ return &createWriteSettingsTask;
+}
+
+void QInstallerWriteSettingsTask::writeToInstaller(QIODevice *out) const
+{
+ appendString(out, m_key);
+ appendString(out, m_value);
+}
+
+void QInstallerWriteSettingsTask::readAndExecuteFromInstaller(QIODevice *in)
+{
+ m_key = installer()->replaceVariables(retrieveString(in));
+ m_value = installer()->replaceVariables(retrieveString(in));
+ QSettings settings;
+ settings.setValue(m_key, m_value);
+}
+
+void QInstallerWriteSettingsTask::writeToUninstaller(QIODevice *out) const
+{
+ appendString(out, m_key);
+ appendString(out, m_value);
+}
+
+void QInstallerWriteSettingsTask::readAndExecuteFromUninstaller(QIODevice *in)
+{
+ m_key = installer()->replaceVariables(retrieveString(in));
+ m_value = installer()->replaceVariables(retrieveString(in));
+ undo();
+}
+
+void QInstallerWriteSettingsTask::undo()
+{
+ QSettings settings;
+ settings.setValue(m_key, QString());
+}
+
+void QInstallerWriteSettingsTask::dump(QDebug & os) const
+{
+ os << "s|" + key() + '|' + value();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerPatchFileTask
+//
+////////////////////////////////////////////////////////////////////
+
+QInstaller::TaskCreator QInstallerPatchFileTask::creator() const
+{
+ return &createPatchFileTask;
+}
+
+void QInstallerPatchFileTask::writeToInstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+ appendByteArray(out, m_needle);
+ appendByteArray(out, m_replacement);
+}
+
+void QInstallerPatchFileTask::readAndExecuteFromInstaller(QIODevice *in)
+{
+ m_targetPath = installer()->replaceVariables(retrieveString(in));
+ m_needle = retrieveByteArray(in);
+ m_replacement = installer()->replaceVariables(retrieveByteArray(in));
+ ifVerbose("PATCHING" << m_replacement << m_needle << m_targetPath);
+
+ QFile file;
+ file.setFileName(m_targetPath);
+ if (!file.open(QIODevice::ReadWrite))
+ throw Error(QInstaller::tr("Cannot open file %1 for reading").arg(file.fileName()));
+
+ uchar *data = file.map(0, file.size());
+ if (!data)
+ throw Error(QInstaller::tr("Cannot map file %1").arg(file.fileName()));
+ QByteArray ba = QByteArray::fromRawData((const char *)data, file.size());
+ int pos = ba.indexOf(m_needle);
+ if (pos != -1) {
+ for (int i = m_replacement.size(); --i >= 0; )
+ data[pos + i] = m_replacement.at(i);
+ }
+ if (!file.unmap(data))
+ throw Error(QInstaller::tr("Cannot unmap file %1").arg(file.fileName()));
+ file.close();
+}
+
+void QInstallerPatchFileTask::dump(QDebug & os) const
+{
+ os << "p|" + targetPath() + '|' + needle() + '|' + replacement();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerMenuShortcutTask
+//
+//
+// Usage:
+//
+// static const struct
+// {
+// const char *target;
+// const char *linkTarget;
+// } menuShortcuts[] = {
+// {"Qt Creator by Nokia\\Run Qt Creator", "bin\\qtcreator.exe"},
+// {"Qt Creator by Nokia\\Readme", "readme.txt"},
+// {"Qt Creator by Nokia\\Uninstall", "uninstall.exe"}
+// };
+//
+// for (int i = 0; i != sizeof(menuShortcuts) / sizeof(menuShortcuts[0]); ++i) {
+// QInstallerMenuShortcutTask *task = new QInstallerMenuShortcutTask(this);
+// task->setTargetPath(menuShortcuts[i].target);
+// task->setLinkTargetPath(QLatin1String("@TargetDir@\\") + menuShortcuts[i].linkTarget);
+// }
+//
+////////////////////////////////////////////////////////////////////
+
+QInstaller::TaskCreator QInstallerMenuShortcutTask::creator() const
+{
+ return &createMenuShortcutTask;
+}
+
+void QInstallerMenuShortcutTask::writeToInstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+ appendString(out, m_linkTargetPath);
+}
+
+void QInstallerMenuShortcutTask::readAndExecuteFromInstaller(QIODevice *in)
+{
+ m_targetPath = installer()->replaceVariables(retrieveString(in));
+ m_linkTargetPath = installer()->replaceVariables(retrieveString(in));
+
+#ifdef Q_OS_WIN
+ QString workingDir = installer()->value(QLatin1String("TargetDir"));
+ bool res = false;
+ HRESULT hres;
+ IShellLink *psl;
+ bool neededCoInit = false;
+
+ ifVerbose("CREATE MENU SHORTCUT: " << m_targetPath << " TARGET " << m_linkTargetPath);
+
+ if (installer()->value(QLatin1String("AllUsers")) == "true") {
+ QSettings registry(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows"
+ "\\CurrentVersion\\Explorer\\Shell Folders"), QSettings::NativeFormat);
+ m_startMenuPath = registry.value(QLatin1String("Common Programs"), QString()).toString();
+ } else {
+ QSettings registry(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows"
+ "\\CurrentVersion\\Explorer\\Shell Folders"), QSettings::NativeFormat);
+ m_startMenuPath = registry.value(QLatin1String("Programs"), QString()).toString();
+ }
+ if (m_startMenuPath.isEmpty()) {
+ ifVerbose("CREATE MENU SHORTCUT: Cannot find start menu folder!");
+ return;
+ }
+
+ if (!m_targetPath.isEmpty()) {
+ if (!m_targetPath.endsWith(QLatin1String(".lnk")))
+ m_targetPath.append(QLatin1String(".lnk"));
+ m_targetPath = m_targetPath.replace('/', '\\');
+ int i = m_targetPath.lastIndexOf('\\');
+ if (i > -1) {
+ QDir dir(m_startMenuPath);
+ if (!dir.exists(m_targetPath.left(i)))
+ dir.mkpath(m_targetPath.left(i));
+ }
+
+ if (m_linkTargetPath.isEmpty())
+ return;
+
+ QString trgt = m_linkTargetPath;
+ if (trgt.startsWith('\"')) {
+ trgt = trgt.left(trgt.indexOf('\"', 1) + 1);
+ } else {
+ trgt = trgt.left(trgt.indexOf(' '));
+ }
+ if (trgt.isEmpty())
+ trgt = m_linkTargetPath;
+
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
+ if (hres == CO_E_NOTINITIALIZED) {
+ neededCoInit = true;
+ CoInitialize(NULL);
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
+ (void **)&psl);
+ }
+ if (SUCCEEDED(hres)) {
+ hres = psl->SetPath((wchar_t *)trgt.utf16());
+ if (SUCCEEDED(hres)) {
+ hres = psl->SetArguments((wchar_t *)m_linkTargetPath.mid(trgt.length()).utf16());
+ if (SUCCEEDED(hres)) {
+ hres = psl->SetWorkingDirectory((wchar_t *)workingDir.utf16());
+ if (SUCCEEDED(hres)) {
+ IPersistFile *ppf;
+ hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
+ if (SUCCEEDED(hres)) {
+ hres = ppf->Save((TCHAR*)QString(m_startMenuPath
+ + QDir::separator() + m_targetPath).utf16(), TRUE);
+ if (SUCCEEDED(hres))
+ res = true;
+ ppf->Release();
+ }
+ }
+ }
+ }
+ psl->Release();
+ }
+ if (neededCoInit)
+ CoUninitialize();
+ }
+ if (!res) {
+ QString msg = QInstaller::tr("Cannot create menu shortcut %1 to %2:\n")
+ .arg(m_linkTargetPath).arg(m_targetPath);
+ installer()->showWarning(msg);
+ return;
+ }
+#endif
+}
+
+void QInstallerMenuShortcutTask::writeToUninstaller(QIODevice *out) const
+{
+ appendString(out, m_targetPath);
+ appendString(out, m_startMenuPath);
+}
+
+void QInstallerMenuShortcutTask::readAndExecuteFromUninstaller(QIODevice *in)
+{
+ m_targetPath = retrieveString(in);
+ m_startMenuPath = retrieveString(in);
+ ifVerbose("REMOVE MENU SHORTCUT: " << m_targetPath);
+ undo();
+}
+
+void QInstallerMenuShortcutTask::undo()
+{
+#ifdef Q_OS_WIN
+ QFileInfo fi(m_startMenuPath + QDir::separator() + m_targetPath);
+ QString path = fi.absoluteFilePath();
+ if (fi.isFile()) {
+ path = fi.absolutePath();
+ QFile file(fi.absoluteFilePath());
+ file.remove();
+ }
+ QDir dir(m_startMenuPath);
+ dir.rmpath(path);
+#endif
+}
+
+void QInstallerMenuShortcutTask::dump(QDebug & os) const
+{
+ os << "msc|" + targetPath() + '|' + linkTargetPath();
+}
+
+QT_END_NAMESPACE
+
+#include "qinstaller.moc"
diff --git a/installer/qinstaller.h b/installer/qinstaller.h
new file mode 100644
index 0000000000..9930cb8664
--- /dev/null
+++ b/installer/qinstaller.h
@@ -0,0 +1,357 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef QINSTALLER_H
+#define QINSTALLER_H
+
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+class QInstallerTask;
+class QInstallerComponent;
+
+class QInstaller : public QObject
+{
+ Q_OBJECT
+
+public:
+ QInstaller();
+ ~QInstaller();
+
+ bool run();
+
+ // parameter handling
+ void setValue(const QString &key, const QString &value);
+ QString value(const QString &key,
+ const QString &defaultValue = QString()) const;
+ bool containsValue(const QString &key) const;
+ QString replaceVariables(const QString &str) const;
+ QByteArray replaceVariables(const QByteArray &str) const;
+ QString installerBinaryPath() const;
+ QString uninstallerName() const;
+
+ // installer-specific task creation
+ virtual void createTasks() {}
+
+ // component handling
+ void appendComponent(QInstallerComponent *components);
+ int componentCount() const;
+ QInstallerComponent *component(int i) const;
+ typedef QInstallerTask *(*TaskCreator)(QInstaller *);
+ void registerTaskType(TaskCreator);
+ int indexOfTaskType(TaskCreator) const;
+
+ // progress handling
+ //void setInstallationProgress(int);
+ int installationProgress() const;
+ void setInstallationProgressText(const QString &);
+ QString installationProgressText() const;
+
+ // convenience
+ bool isCreator() const;
+ bool isInstaller() const;
+ bool isUninstaller() const;
+ bool isTempUninstaller() const;
+
+ bool isVerbose() const;
+ void setVerbose(bool on);
+ void connectGui(QObject *gui);
+
+ QString libraryName(const QString &baseName, const QString &version);
+
+ bool restartTempUninstaller(const QStringList &args);
+
+ // status
+ enum InstallerStatus {
+ InstallerUnfinished,
+ InstallerCanceledByUser,
+ InstallerFailed,
+ InstallerSucceeded,
+ };
+ InstallerStatus status() const;
+
+ // I/O helper for authors of classes deriving from QInstallerStep
+ static void appendInt(QIODevice *out, qint64 n);
+ static void appendString(QIODevice *out, const QString &str);
+ static void appendByteArray(QIODevice *out, const QByteArray &str);
+ static qint64 retrieveInt(QIODevice *in);
+ static QString retrieveString(QIODevice *in);
+ static QByteArray retrieveByteArray(QIODevice *in);
+
+ void dump() const;
+ class Private;
+
+public slots:
+ bool runInstaller();
+ bool runUninstaller();
+ void interrupt();
+ void showWarning(const QString &);
+
+signals:
+ void installationStarted();
+ void installationFinished();
+ void uninstallationStarted();
+ void uninstallationFinished();
+ void warning(QString);
+
+private:
+ Private *d;
+};
+
+
+class QInstallerComponent
+{
+public:
+ explicit QInstallerComponent(QInstaller *installer);
+ ~QInstallerComponent();
+
+ void setValue(const QString &key, const QString &value);
+ QString value(const QString &key,
+ const QString &defaultValue = QString()) const;
+
+ void appendTask(QInstallerTask *step);
+ void appendDirectoryTasks(const QString &sourcePath,
+ const QString &targetPath);
+ void appendSettingsTask(const QString &key, const QString &value);
+ void appendUninstallerRegistrationTask();
+ int taskCount() const;
+ QInstallerTask *task(int) const;
+
+ friend class QInstaller;
+ friend class QInstaller::Private;
+private:
+ Q_DISABLE_COPY(QInstallerComponent);
+ class Private;
+ Private *d;
+};
+
+
+class QInstallerTask
+{
+public:
+ QInstallerTask(QInstaller *parent);
+ virtual ~QInstallerTask() {}
+
+ QInstaller *installer() const;
+
+ virtual void writeToInstaller(QIODevice *out) const = 0;
+ virtual void readAndExecuteFromInstaller(QIODevice *in) = 0;
+
+ virtual void writeToUninstaller(QIODevice *out) const = 0;
+ virtual void readAndExecuteFromUninstaller(QIODevice *in) = 0;
+
+ virtual void undo() = 0;
+ virtual void dump(QDebug &) const {}
+
+ virtual QInstaller::TaskCreator creator() const = 0;
+
+private:
+ QInstaller *m_installer;
+};
+
+
+class QInstallerError
+{
+public:
+ QInstallerError(const QString &m) : m_message(m) {}
+ virtual ~QInstallerError() {}
+ virtual QString message() const { return m_message; }
+private:
+ QString m_message;
+};
+
+/////////////////////////////////////////////////////////////////////
+//
+// Some useful examples
+//
+/////////////////////////////////////////////////////////////////////
+
+
+class QInstallerCopyFileTask : public QInstallerTask
+{
+public:
+ QInstallerCopyFileTask(QInstaller *parent) : QInstallerTask(parent) {}
+ QInstaller::TaskCreator creator() const;
+
+ void setSourcePath(const QString &sourcePath) { m_sourcePath = sourcePath; }
+ QString sourcePath() const { return m_sourcePath; }
+
+ void setTargetPath(const QString &targetPath) { m_targetPath = targetPath; }
+ QString targetPath() const { return m_targetPath; }
+
+ void setPermissions(qint64 permissions) { m_permissions = permissions; }
+ qint64 permissions() const { return m_permissions; }
+
+ void writeToInstaller(QIODevice *out) const;
+ void readAndExecuteFromInstaller(QIODevice *in);
+
+ void writeToUninstaller(QIODevice *out) const;
+ void readAndExecuteFromUninstaller(QIODevice *in);
+
+ void undo();
+ void dump(QDebug &) const;
+
+private:
+ QString m_sourcePath;
+ QString m_targetPath;
+ qint64 m_permissions;
+ int m_parentDirCount;
+};
+
+
+class QInstallerLinkFileTask : public QInstallerTask
+{
+public:
+ QInstallerLinkFileTask(QInstaller *parent) : QInstallerTask(parent) {}
+ QInstaller::TaskCreator creator() const;
+
+ void setTargetPath(const QString &path) { m_targetPath = path; }
+ QString targetPath() const { return m_targetPath; }
+
+ void setLinkTargetPath(const QString &path) { m_linkTargetPath = path; }
+ QString linkTargetPath() const { return m_linkTargetPath; }
+
+ void setPermissions(qint64 permissions) { m_permissions = permissions; }
+ qint64 permissions() const { return m_permissions; }
+
+ void writeToInstaller(QIODevice *out) const;
+ void readAndExecuteFromInstaller(QIODevice *in);
+
+ void writeToUninstaller(QIODevice *out) const;
+ void readAndExecuteFromUninstaller(QIODevice *in);
+
+ void undo();
+ void dump(QDebug &) const;
+
+public:
+ QString m_targetPath; // location of the link in the target system
+ QString m_linkTargetPath; // linkee
+ qint64 m_permissions;
+};
+
+
+class QInstallerWriteSettingsTask : public QInstallerTask
+{
+public:
+ QInstallerWriteSettingsTask(QInstaller *parent)
+ : QInstallerTask(parent) {}
+ QInstaller::TaskCreator creator() const;
+
+ void setKey(const QString &key) { m_key = key; }
+ QString key() const { return m_key; }
+
+ void setValue(const QString &value) { m_value = value; }
+ QString value() const { return m_value; }
+
+ void writeToInstaller(QIODevice *out) const;
+ void readAndExecuteFromInstaller(QIODevice *in);
+
+ void writeToUninstaller(QIODevice *out) const;
+ void readAndExecuteFromUninstaller(QIODevice *in);
+
+ void undo();
+ void dump(QDebug &) const;
+
+public:
+ QString m_key;
+ QString m_value;
+};
+
+
+class QInstallerPatchFileTask : public QInstallerTask
+{
+public:
+ QInstallerPatchFileTask(QInstaller *parent) : QInstallerTask(parent) {}
+ QInstaller::TaskCreator creator() const;
+
+ void setTargetPath(const QString &path) { m_targetPath = path; }
+ QString targetPath() const { return m_targetPath; }
+
+ void setNeedle(const QByteArray &needle) { m_needle = needle; }
+ QByteArray needle() const { return m_needle; }
+
+ void setReplacement(const QByteArray &repl) { m_replacement = repl; }
+ QByteArray replacement() const { return m_replacement; }
+
+ void writeToInstaller(QIODevice *out) const;
+ void readAndExecuteFromInstaller(QIODevice *in);
+
+ void writeToUninstaller(QIODevice *) const {}
+ void readAndExecuteFromUninstaller(QIODevice *) {}
+
+ void undo() {}
+ void dump(QDebug &) const;
+
+private:
+ QByteArray m_needle;
+ QByteArray m_replacement;
+ QString m_targetPath;
+};
+
+
+class QInstallerMenuShortcutTask : public QInstallerTask
+{
+public:
+ QInstallerMenuShortcutTask(QInstaller *parent) : QInstallerTask(parent) {}
+ QInstaller::TaskCreator creator() const;
+
+ void setTargetPath(const QString &path) { m_targetPath = path; }
+ QString targetPath() const { return m_targetPath; }
+
+ void setLinkTargetPath(const QString &path) { m_linkTargetPath = path; }
+ QString linkTargetPath() const { return m_linkTargetPath; }
+
+ void writeToInstaller(QIODevice *out) const;
+ void readAndExecuteFromInstaller(QIODevice *in);
+
+ void writeToUninstaller(QIODevice *out) const;
+ void readAndExecuteFromUninstaller(QIODevice *in);
+
+ void undo();
+ void dump(QDebug &) const;
+
+public:
+ QString m_targetPath;
+ QString m_linkTargetPath;
+ QString m_startMenuPath;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QINSTALLER_H
diff --git a/installer/qinstallergui.cpp b/installer/qinstallergui.cpp
new file mode 100644
index 0000000000..0da9a6d47b
--- /dev/null
+++ b/installer/qinstallergui.cpp
@@ -0,0 +1,742 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qinstallergui.h"
+
+#include "qinstaller.h"
+#include "private/qobject_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QProcess>
+#include <QtCore/QRegExp>
+#include <QtCore/QTimer>
+
+#include <QtGui/QApplication>
+#include <QtGui/QCheckBox>
+#include <QtGui/QFileDialog>
+#include <QtGui/QGridLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QHeaderView>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMessageBox>
+#include <QtGui/QProgressBar>
+#include <QtGui/QPushButton>
+#include <QtGui/QRadioButton>
+#include <QtGui/QTextEdit>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QTreeView>
+#include <QtGui/QVBoxLayout>
+
+
+QT_BEGIN_NAMESPACE
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerGui
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerGui::QInstallerGui(QInstaller *installer, QWidget *parent)
+ : QWizard(parent)
+{
+ #ifndef Q_WS_MAC
+ setWizardStyle(QWizard::ModernStyle);
+ #endif
+ setOption(QWizard::IndependentPages);
+ connect(button(QWizard::CancelButton), SIGNAL(clicked()),
+ this, SLOT(cancelButtonClicked()));
+
+ connect(this, SIGNAL(interrupted()),
+ installer, SLOT(interrupt()));
+ connect(installer, SIGNAL(installationFinished()),
+ this, SLOT(showFinishedPage()));
+ connect(installer, SIGNAL(warning(QString)),
+ this, SLOT(showWarning(QString)));
+}
+
+void QInstallerGui::cancelButtonClicked()
+{
+ QInstallerPage *page = qobject_cast<QInstallerPage *>(currentPage());
+ qDebug() << "CANCEL CLICKED" << currentPage() << page;
+ if (page && page->isInterruptible()) {
+ QMessageBox::StandardButton bt = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("Do you want to abort the installation process?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::Yes)
+ emit interrupted();
+ } else {
+ QMessageBox::StandardButton bt = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("Do you want to abort the installer application?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::Yes)
+ QDialog::reject();
+ }
+}
+
+void QInstallerGui::reject()
+{}
+
+void QInstallerGui::showFinishedPage()
+{
+ qDebug() << "SHOW FINISHED PAGE";
+ next();
+}
+
+void QInstallerGui::showWarning(const QString &msg)
+{
+ QMessageBox::warning(this, tr("Warning"), msg);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerPage::QInstallerPage(QInstaller *installer)
+ : m_installer(installer), m_fresh(true)
+{
+ setSubTitle(QString(" ")); // otherwise the colors will screw up
+
+}
+
+QInstaller *QInstallerPage::installer() const
+{
+ return m_installer;
+}
+
+QPixmap QInstallerPage::watermarkPixmap() const
+{
+ return QPixmap(m_installer->value("WatermarkPixmap"));
+}
+
+QPixmap QInstallerPage::logoPixmap() const
+{
+ return QPixmap(m_installer->value("LogoPixmap"));
+}
+
+QString QInstallerPage::productName() const
+{
+ return m_installer->value("ProductName");
+}
+
+void QInstallerPage::insertWidget(QWidget *widget, const QString &siblingName, int offset)
+{
+ QWidget *sibling = findChild<QWidget *>(siblingName);
+ QWidget *parent = sibling ? sibling->parentWidget() : 0;
+ QLayout *layout = parent ? parent->layout() : 0;
+ QBoxLayout *blayout = qobject_cast<QBoxLayout *>(layout);
+ //qDebug() << "FOUND: " << sibling << parent << layout << blayout;
+ if (blayout) {
+ int index = blayout->indexOf(sibling) + offset;
+ blayout->insertWidget(index, widget);
+ }
+}
+
+QWidget *QInstallerPage::findWidget(const QString &objectName) const
+{
+ return findChild<QWidget *>(objectName);
+}
+
+void QInstallerPage::setVisible(bool visible)
+{
+ QWizardPage::setVisible(visible);
+ qApp->processEvents();
+ //qDebug() << "VISIBLE: " << visible << objectName() << installer();
+ if (m_fresh && !visible) {
+ //qDebug() << "SUPRESSED...";
+ m_fresh = false;
+ return;
+ }
+ if (visible)
+ entering();
+ else
+ leaving();
+}
+
+int QInstallerPage::nextId() const
+{
+ //qDebug() << "NEXTID";
+ return QWizardPage::nextId();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerIntroductionPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerIntroductionPage::QInstallerIntroductionPage(QInstaller *installer)
+ : QInstallerPage(installer)
+{
+ setObjectName("IntroductionPage");
+ setTitle(tr("Setup - %1").arg(productName()));
+ setPixmap(QWizard::WatermarkPixmap, watermarkPixmap());
+ setSubTitle(QString());
+
+ QLabel *msgLabel = new QLabel(this);
+ msgLabel->setObjectName("MessageLabel");
+ msgLabel->setWordWrap(true);
+ msgLabel->setText(QInstaller::tr("Welcome to the %1 Setup Wizard.")
+ .arg(productName()));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(msgLabel);
+ setLayout(layout);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerLicenseAgreementPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerLicenseAgreementPage::QInstallerLicenseAgreementPage(QInstaller *installer)
+ : QInstallerPage(installer)
+{
+ setObjectName("LicenseAgreementPage");
+ setTitle(tr("License Agreement"));
+ QString msg = tr("Please read the following License Agreement. "
+ "You must accept the terms of this agreement "
+ "before continuing with the installation.");
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+
+ QTextEdit *textEdit = new QTextEdit(this);
+ textEdit->setObjectName("LicenseText");
+ QFile file(":/resources/license.txt");
+ file.open(QIODevice::ReadOnly);
+ textEdit->setText(file.readAll());
+
+ m_acceptRadioButton = new QRadioButton(tr("I accept the agreement"), this);
+ m_rejectRadioButton = new QRadioButton(tr("I do not accept the agreement"), this);
+
+ QLabel *msgLabel = new QLabel(msg, this);
+ msgLabel->setObjectName("MessageLabel");
+ msgLabel->setWordWrap(true);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(msgLabel);
+ layout->addWidget(textEdit);
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ hlayout->addWidget(new QLabel(tr("Do you accept this License?")));
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->addWidget(m_acceptRadioButton);
+ vlayout->addWidget(m_rejectRadioButton);
+ hlayout->addLayout(vlayout);
+ layout->addLayout(hlayout);
+ setLayout(layout);
+ connect(m_acceptRadioButton, SIGNAL(toggled(bool)),
+ this, SIGNAL(completeChanged()));
+ connect(m_rejectRadioButton, SIGNAL(toggled(bool)),
+ this, SIGNAL(completeChanged()));
+}
+
+bool QInstallerLicenseAgreementPage::isComplete() const
+{
+ return m_acceptRadioButton->isChecked();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerComponentSelectionPage
+//
+////////////////////////////////////////////////////////////////////
+
+static QString niceSizeText(const QString &str)
+{
+ qint64 size = str.toInt();
+ QString msg = QInstallerComponentSelectionPage::tr(
+ "This component will occupy approximately %1 %2 on your harddisk.");
+ if (size < 10000)
+ return msg.arg(size).arg("Bytes");
+ if (size < 1024 * 10000)
+ return msg.arg(size / 1024).arg("kBytes");
+ return msg.arg(size / 1024 / 1024).arg("MBytes");
+}
+
+class QInstallerComponentSelectionPage::Private : public QObject
+{
+ Q_OBJECT
+
+public:
+ Private(QInstallerComponentSelectionPage *q_, QInstaller *installer)
+ : q(q_), m_installer(installer)
+ {
+ m_treeView = new QTreeWidget(q);
+ m_treeView->setObjectName("TreeView");
+ m_treeView->setMouseTracking(true);
+ m_treeView->header()->hide();
+
+ for (int i = 0; i != installer->componentCount(); ++i) {
+ QInstallerComponent *component = installer->component(i);
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_treeView);
+ item->setText(0, component->value("Name"));
+ item->setToolTip(0, component->value("Description"));
+ item->setToolTip(1, niceSizeText(component->value("UncompressedSize")));
+ //QString current = component->value("CurrentState");
+ QString suggested = component->value("SuggestedState");
+ if (suggested == "Uninstalled") {
+ item->setCheckState(0, Qt::Unchecked);
+ } else if (suggested == "AlwaysInstalled") {
+ item->setCheckState(0, Qt::PartiallyChecked);
+ item->setFlags(item->flags() & ~Qt::ItemIsUserCheckable);
+ } else { //if (suggested == "Installed")
+ item->setCheckState(0, Qt::Checked);
+ }
+ }
+
+ m_descriptionLabel = new QLabel(q);
+ m_descriptionLabel->setWordWrap(true);
+
+ m_sizeLabel = new QLabel(q);
+ m_sizeLabel->setWordWrap(true);
+
+ QVBoxLayout *layout = new QVBoxLayout(q);
+ //layout->addWidget(msgLabel);
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ hlayout->addWidget(m_treeView, 3);
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->addWidget(m_descriptionLabel);
+ vlayout->addWidget(m_sizeLabel);
+ vlayout->addSpacerItem(new QSpacerItem(1, 1,
+ QSizePolicy::MinimumExpanding,
+ QSizePolicy::MinimumExpanding));
+ hlayout->addLayout(vlayout, 2);
+ layout->addLayout(hlayout);
+ q->setLayout(layout);
+
+ connect(m_treeView,
+ SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
+ this, SLOT(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
+ }
+
+public slots:
+ void currentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
+ {
+ m_descriptionLabel->setText(item->toolTip(0));
+ m_sizeLabel->setText(item->toolTip(1));
+ }
+
+public:
+ QInstallerComponentSelectionPage *q;
+ QInstaller *m_installer;
+ QTreeWidget *m_treeView;
+ QLabel *m_descriptionLabel;
+ QLabel *m_sizeLabel;
+};
+
+
+QInstallerComponentSelectionPage::QInstallerComponentSelectionPage
+ (QInstaller *installer)
+ : QInstallerPage(installer), d(new Private(this, installer))
+{
+ setObjectName("ComponentSelectionPage");
+ setTitle(tr("Select Components"));
+ QString msg = tr("Please select the components you want to install.");
+ setSubTitle(msg);
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+}
+
+QInstallerComponentSelectionPage::~QInstallerComponentSelectionPage()
+{
+ delete d;
+}
+
+void QInstallerComponentSelectionPage::leaving()
+{
+ int n = d->m_treeView->topLevelItemCount();
+ for (int i = 0; i != n; ++i) {
+ QTreeWidgetItem *item = d->m_treeView->topLevelItem(i);
+ QInstallerComponent *component = installer()->component(i);
+ if (item->checkState(0) == Qt::Unchecked)
+ component->setValue("WantedState", "Uninstalled");
+ else
+ component->setValue("WantedState", "Installed");
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerTargetDirectoryPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerTargetDirectoryPage::QInstallerTargetDirectoryPage(QInstaller *installer)
+ : QInstallerPage(installer)
+{
+ setObjectName("TargetDirectoryPage");
+ setTitle(tr("Installation Directory"));
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+
+ QLabel *msgLabel = new QLabel(this);
+ msgLabel->setText(QInstaller::tr("Please specify the directory where %1 "
+ "will be installed.").arg(productName()));
+ msgLabel->setWordWrap(true);
+ msgLabel->setObjectName("MessageLabel");
+
+ m_lineEdit = new QLineEdit(this);
+ m_lineEdit->setObjectName("LineEdit");
+
+ QPushButton *browseButton = new QPushButton(this);
+ browseButton->setObjectName("BrowseButton");
+ browseButton->setText("Browse...");
+ browseButton->setIcon(QIcon(logoPixmap()));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(msgLabel);
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ hlayout->addWidget(m_lineEdit);
+ hlayout->addWidget(browseButton);
+ layout->addLayout(hlayout);
+ setLayout(layout);
+
+ QString targetDir = installer->value("TargetDir");
+ //targetDir = QDir::currentPath();
+ if (targetDir.isEmpty())
+ targetDir = QDir::homePath() + QDir::separator() + productName();
+ m_lineEdit->setText(targetDir);
+
+ connect(browseButton, SIGNAL(clicked()),
+ this, SLOT(dirRequested()));
+ connect(m_lineEdit, SIGNAL(textChanged(QString)),
+ this, SIGNAL(completeChanged()));
+}
+
+QString QInstallerTargetDirectoryPage::targetDir() const
+{
+ return m_lineEdit->text();
+}
+
+void QInstallerTargetDirectoryPage::setTargetDir(const QString &dirName)
+{
+ m_lineEdit->setText(dirName);
+}
+
+void QInstallerTargetDirectoryPage::entering()
+{
+ connect(wizard(), SIGNAL(customButtonClicked(int)),
+ this, SLOT(targetDirSelected()));
+}
+
+void QInstallerTargetDirectoryPage::leaving()
+{
+ installer()->setValue("TargetDir", targetDir());
+ disconnect(wizard(), SIGNAL(customButtonClicked(int)),
+ this, SLOT(targetDirSelected()));
+}
+
+void QInstallerTargetDirectoryPage::targetDirSelected()
+{
+ //qDebug() << "TARGET DIRECTORY";
+ QDir dir(targetDir());
+ if (dir.exists() && dir.isReadable()) {
+ QMessageBox::StandardButton bt = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("The directory you slected exists already.\n"
+ "Do you want to continue?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::Yes)
+ wizard()->next();
+ return;
+ }
+ dir.cdUp();
+ if (dir.exists() && dir.isReadable()) {
+ wizard()->next();
+ return;
+ }
+ wizard()->next();
+}
+
+void QInstallerTargetDirectoryPage::dirRequested()
+{
+ //qDebug() << "DIR REQUESTED";
+ QString newDirName = QFileDialog::getExistingDirectory(this,
+ tr("Select Installation Directory"), targetDir()
+ /*, Options options = ShowDirsOnly*/);
+ if (newDirName.isEmpty() || newDirName == targetDir())
+ return;
+ m_lineEdit->setText(newDirName);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerReadyForInstallationPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerReadyForInstallationPage::
+ QInstallerReadyForInstallationPage(QInstaller *installer)
+ : QInstallerPage(installer)
+{
+ setObjectName("ReadyForInstallationPage");
+ setTitle(tr("Ready to Install"));
+ setCommitPage(true);
+ setButtonText(QWizard::CommitButton, tr("Install"));
+
+ QLabel *msgLabel = new QLabel(this);
+ msgLabel->setObjectName("MessageLabel");
+ msgLabel->setText(QInstaller::tr("Setup is now ready to begin installing %1 "
+ "on your computer.").arg(productName()));
+
+ QLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(msgLabel);
+ setLayout(layout);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerPerformInstallationPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerPerformInstallationPage::QInstallerPerformInstallationPage(QInstaller *gui)
+ : QInstallerPage(gui)
+{
+ setObjectName("InstallationPage");
+ setTitle(tr("Installing %1").arg(installer()->value("ProductName")));
+ setCommitPage(true);
+
+ m_progressBar = new QProgressBar(this);
+ m_progressBar->setObjectName("ProgressBar");
+ m_progressBar->setRange(1, 100);
+
+ m_progressLabel = new QLabel(this);
+ m_progressLabel->setObjectName("ProgressLabel");
+
+ m_updateTimer = new QTimer(this);
+ connect(m_updateTimer, SIGNAL(timeout()),
+ this, SLOT(updateProgress()));
+ m_updateTimer->setInterval(50);
+
+ QLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_progressBar);
+ layout->addWidget(m_progressLabel);
+ setLayout(layout);
+
+ connect(installer(), SIGNAL(installationStarted()),
+ this, SLOT(installationStarted()));
+ connect(installer(), SIGNAL(installationFinished()),
+ this, SLOT(installationFinished()));
+}
+
+void QInstallerPerformInstallationPage::initializePage()
+{
+ QWizardPage::initializePage();
+ QTimer::singleShot(30, installer(), SLOT(runInstaller()));
+}
+
+// FIXME: remove function
+bool QInstallerPerformInstallationPage::isComplete() const
+{
+ return true;
+}
+
+void QInstallerPerformInstallationPage::installationStarted()
+{
+ qDebug() << "INSTALLATION STARTED";
+ m_updateTimer->start();
+ updateProgress();
+}
+
+void QInstallerPerformInstallationPage::installationFinished()
+{
+ qDebug() << "INSTALLATION FINISHED";
+ m_updateTimer->stop();
+ updateProgress();
+}
+
+void QInstallerPerformInstallationPage::updateProgress()
+{
+ int progress = installer()->installationProgress();
+ if (progress != m_progressBar->value())
+ m_progressBar->setValue(progress);
+ QString progressText = installer()->installationProgressText();
+ if (progressText != m_progressLabel->text())
+ m_progressLabel->setText(progressText);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerPerformUninstallationPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerPerformUninstallationPage::QInstallerPerformUninstallationPage
+ (QInstaller *gui)
+ : QInstallerPage(gui)
+{
+ setObjectName("UninstallationPage");
+ setTitle(tr("Uninstalling %1").arg(installer()->value("ProductName")));
+ setCommitPage(true);
+
+ m_progressBar = new QProgressBar(this);
+ m_progressBar->setObjectName("ProgressBar");
+ m_progressBar->setRange(1, 100);
+
+ m_progressLabel = new QLabel(this);
+ m_progressLabel->setObjectName("ProgressLabel");
+
+ m_updateTimer = new QTimer(this);
+ connect(m_updateTimer, SIGNAL(timeout()),
+ this, SLOT(updateProgress()));
+ m_updateTimer->setInterval(50);
+
+ QLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_progressBar);
+ layout->addWidget(m_progressLabel);
+ setLayout(layout);
+
+ connect(installer(), SIGNAL(uninstallationStarted()),
+ this, SLOT(uninstallationStarted()));
+ connect(installer(), SIGNAL(uninstallationFinished()),
+ this, SLOT(uninstallationFinished()));
+}
+
+void QInstallerPerformUninstallationPage::initializePage()
+{
+ QWizardPage::initializePage();
+ QTimer::singleShot(30, installer(), SLOT(runUninstaller()));
+}
+
+// FIXME: remove function
+bool QInstallerPerformUninstallationPage::isComplete() const
+{
+ return true;
+}
+
+void QInstallerPerformUninstallationPage::uninstallationStarted()
+{
+ m_updateTimer->start();
+ updateProgress();
+}
+
+void QInstallerPerformUninstallationPage::uninstallationFinished()
+{
+ m_updateTimer->stop();
+ updateProgress();
+}
+
+void QInstallerPerformUninstallationPage::updateProgress()
+{
+ int progress = installer()->installationProgress();
+ if (progress != m_progressBar->value())
+ m_progressBar->setValue(progress);
+ QString progressText = installer()->installationProgressText();
+ if (progressText != m_progressLabel->text())
+ m_progressLabel->setText(progressText);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// QInstallerFinishedPage
+//
+////////////////////////////////////////////////////////////////////
+
+QInstallerFinishedPage::QInstallerFinishedPage(QInstaller *installer)
+ : QInstallerPage(installer)
+{
+ setObjectName("FinishedPage");
+ setTitle(tr("Completing the %1 Setup Wizard").arg(productName()));
+ setPixmap(QWizard::WatermarkPixmap, watermarkPixmap());
+ setSubTitle(QString());
+
+ QLabel *msgLabel = new QLabel(this);
+ msgLabel->setObjectName("MessageLabel");
+ msgLabel->setWordWrap(true);
+ msgLabel->setText(tr("Click Finish to exit the Setup Wizard"));
+
+ m_runItCheckBox = new QCheckBox(this);
+ m_runItCheckBox->setObjectName("RunItCheckBox");
+ m_runItCheckBox->setChecked(true);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(msgLabel);
+ if (m_runItCheckBox)
+ layout->addWidget(m_runItCheckBox);
+ setLayout(layout);
+}
+
+void QInstallerFinishedPage::entering()
+{
+ qDebug() << "FINISHED ENTERING: ";
+ connect(wizard()->button(QWizard::FinishButton), SIGNAL(clicked()),
+ this, SLOT(handleFinishClicked()));
+ if (installer()->status() == QInstaller::InstallerSucceeded) {
+ m_runItCheckBox->show();
+ m_runItCheckBox->setText(tr("Run %1 now.").arg(productName()));
+ } else {
+ setTitle(tr("The %1 Setup Wizard failed").arg(productName()));
+ m_runItCheckBox->hide();
+ m_runItCheckBox->setChecked(false);
+ }
+}
+
+void QInstallerFinishedPage::leaving()
+{
+ disconnect(wizard(), SIGNAL(customButtonClicked(int)),
+ this, SLOT(handleFinishClicked()));
+}
+
+void QInstallerFinishedPage::handleFinishClicked()
+{
+ if (!m_runItCheckBox->isChecked())
+ return;
+ QString program = installer()->value("RunProgram");
+ if (program.isEmpty())
+ return;
+ program = installer()->replaceVariables(program);
+ qDebug() << "STARTING " << program;
+ QProcess *process = new QProcess;
+ process->start(program);
+ process->waitForFinished();
+}
+
+#include "qinstallergui.moc"
+
+QT_END_NAMESPACE
diff --git a/installer/qinstallergui.h b/installer/qinstallergui.h
new file mode 100644
index 0000000000..93de1a1c55
--- /dev/null
+++ b/installer/qinstallergui.h
@@ -0,0 +1,256 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef QINSTALLERGUI_H
+#define QINSTALLERGUI_H
+
+#include <QtGui/QWizard>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QInstaller;
+
+// FIXME: move to private classes
+class QCheckBox;
+class QLabel;
+class QLineEdit;
+class QProgressBar;
+class QRadioButton;
+class QTreeView;
+class QTreeWidget;
+
+class QInstallerGui : public QWizard
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerGui(QInstaller *installer, QWidget *parent = 0);
+
+signals:
+ void interrupted();
+
+public slots:
+ void cancelButtonClicked();
+ void reject();
+ void showFinishedPage();
+ void showWarning(const QString &msg);
+};
+
+
+class QInstallerPage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ QInstallerPage(QInstaller *installer);
+
+ virtual bool isInterruptible() const { return false; }
+ virtual QPixmap watermarkPixmap() const;
+ virtual QPixmap logoPixmap() const;
+ virtual QString productName() const;
+
+protected:
+ QInstaller *installer() const;
+
+ // Inserts widget into the same layout like a sibling identified
+ // by its name. Default position is just behind the sibling.
+ virtual void insertWidget(QWidget *widget, const QString &siblingName,
+ int offset = 1);
+ virtual QWidget *findWidget(const QString &objectName) const;
+
+ virtual void setVisible(bool visible); // reimp
+ virtual int nextId() const; // reimp
+
+ virtual void entering() {} // called on entering
+ virtual void leaving() {} // called on leaving
+
+ virtual void forward() const {} // called when going forwards
+ //virtual void backward() const {} // called when going back
+ bool isConstructing() const { return m_fresh; }
+
+private:
+ QInstaller *m_installer;
+ bool m_fresh;
+};
+
+
+class QInstallerIntroductionPage : public QInstallerPage
+{
+public:
+ explicit QInstallerIntroductionPage(QInstaller *installer);
+};
+
+
+class QInstallerLicenseAgreementPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerLicenseAgreementPage(QInstaller *installer);
+ bool isComplete() const;
+
+private:
+ QRadioButton *m_acceptRadioButton;
+ QRadioButton *m_rejectRadioButton;
+};
+
+
+class QInstallerComponentSelectionPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerComponentSelectionPage(QInstaller *installer);
+ ~QInstallerComponentSelectionPage();
+
+protected:
+ //void entering();
+ void leaving();
+
+private:
+ class Private;
+ Private *d;
+};
+
+
+class QInstallerTargetDirectoryPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerTargetDirectoryPage(QInstaller *installer);
+ QString targetDir() const;
+ void setTargetDir(const QString &dirName);
+
+protected:
+ void entering();
+ void leaving();
+
+private slots:
+ void targetDirSelected();
+ void dirRequested();
+
+private:
+ QLineEdit *m_lineEdit;
+};
+
+
+class QInstallerReadyForInstallationPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerReadyForInstallationPage(QInstaller *installer);
+};
+
+
+class QInstallerPerformInstallationPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerPerformInstallationPage(QInstaller *installer);
+
+protected:
+ void initializePage();
+ bool isComplete() const;
+ bool isInterruptible() const { return true; }
+
+signals:
+ void installationRequested();
+
+private slots:
+ void installationStarted();
+ void installationFinished();
+ void updateProgress();
+
+private:
+ QProgressBar *m_progressBar;
+ QLabel *m_progressLabel;
+ QTimer *m_updateTimer;
+};
+
+
+class QInstallerPerformUninstallationPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerPerformUninstallationPage(QInstaller *installer);
+
+protected:
+ void initializePage();
+ bool isComplete() const;
+ bool isInterruptible() const { return true; }
+
+signals:
+ void uninstallationRequested();
+
+private slots:
+ void uninstallationStarted();
+ void uninstallationFinished();
+ void updateProgress();
+
+private:
+ QProgressBar *m_progressBar;
+ QLabel *m_progressLabel;
+ QTimer *m_updateTimer;
+};
+
+
+class QInstallerFinishedPage : public QInstallerPage
+{
+ Q_OBJECT
+
+public:
+ explicit QInstallerFinishedPage(QInstaller *installer);
+
+public slots:
+ void handleFinishClicked();
+
+protected:
+ void entering();
+ void leaving();
+
+private:
+ QCheckBox *m_runItCheckBox;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QINSTALLERGUI_H
diff --git a/installer/resources/license.txt b/installer/resources/license.txt
new file mode 100644
index 0000000000..a55990fe3a
--- /dev/null
+++ b/installer/resources/license.txt
@@ -0,0 +1,84 @@
+For individuals and/or legal entities resident in the American Continent (including those resident in Canada, South America, and the United States of America), the applicable licensing terms are specified under the heading "Trolltech Technology Preview License
+Agreement: American Continent".
+
+For individuals and/or legal entities not resident in the American Continent, the applicable licensing terms are specified under the heading "Trolltech Technology Preview License Agreement: Norway".
+
+TROLLTECH TECHNOLOGY PREVIEW LICENSE AGREEMENT: AMERICAN CONTINENT Agreement version 2.0
+IMPORTANT-READ CAREFULLY:
+
+1. This Trolltech Technology Preview License Agreement ("Agreement") is a legal agreement between you (either an individual or a legal entity) and Trolltech, Inc. ("Trolltech"), and pertains to the Trolltech software product(s) accompanying this Agreement, which include(s) computer software and may include "online" or electronic documentation, associated media, and printed materials, including the source code, example programs and the documentation ("Licensed Software").
+
+2. The Licensed Software is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. Trolltech retains all rights not expressly granted. No title, property rights or copyright in the Licensed Software or in any modifications to the Licensed Software shall pass to the Licensee under any circumstances. The Licensed Software is licensed, not sold.
+
+3. By installing, copying, or otherwise using the Licensed Software, Licensee agrees to be bound by the terms of this Agreement. If Licensee does not agree to the terms of this Agreement, Licensee should not install, copy, or otherwise use the Licensed Software.
+
+4. Upon Licensee's acceptance of the terms and conditions of this Agreement, Trolltech grants Licensee the right to use the Licensed Software in the manner provided below.
+
+5. Trolltech grants to Licensee as an individual a personal, non-exclusive, non-transferable license to make and use copies of the Licensed Software for the sole purpose of evaluating and testing the Licensed Software and/or providing feedback to Trolltech. Licensee may install copies of the Licensed Software on an unlimited number of computers provided that Licensee is the only individual using the Licensed Software. If Licensee is an entity, Trolltech grants Licensee the right to designate one, and only one, individual within Licensee's organization who shall have the sole right to use the Licensed Software in the manner provided in this Agreement. Licensee may, at any time, but not more frequently than once every six (6) months, designate another individual to replace the current designated user by notifying Trolltech, so long as there is no more than one (1) designated user at any given time
+
+6. Licensee may not loan, rent, lease, or license the Licensed Software or any copy of it. Licensee may not alter or remove any details of ownership, copyright, trademark or other property right connected with the Licensed Software. Licensee may not modify or distribute the Licensed Software. Licensee may not distribute any software statically or dynamically linked with the Licensed Software.
+
+7. This Licensed Software is time-limited. All rights granted to Licensee in this Agreement will be void three (3) months after Licensee received the Licensed Software.
+
+8. The Licensed Software may provide links to third party libraries or code (collectively "Third Party Libraries") to implement various functions. Third Party Libraries do not comprise part of the Licensed Software. In some cases, access to Third Party Libraries may be included along with the Licensed Software delivery as a convenience for development and testing only. Such source code and libraries as are or may be listed in the ".../src/3rdparty" source tree delivered with the Licensed Software, as may be amended from time to time, do not comprise the Licensed Software. Licensee acknowledges (1) that some Third Party Libraries may require additional licensing of copyright and patents from the owners of such, and (2) that distribution of any of the Licensed Software referencing any portion of a Third Party Library may require appropriate licensing from such third parties.
+
+9. Pre-Release Code, Non-Commercial Use: The Licensed Software contains Pre-release Code that is not at the level of performance and compatibility of a final, generally available, product offering. The Licensed Software may not operate correctly and may be substantially modified prior to the first commercial shipment, if any. Trolltech is not obligated to make this or any later version of the Licensed Software commercially available. The License Software is "Not for Commercial Use" and may only be used for the purposes described in Section 5. You may not use the Licensed Software in a live operating environment where it may be relied upon to perform in the same manner as a commercially released product or with data that has not been sufficiently backed up.
+
+10. WARRANTY DISCLAIMER: THE LICENSED SOFTWARE IS LICENSED TO LICENSEE "AS IS". TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, TROLLTECH ON BEHALF OF ITSELF AND ITS SUPPLIERS, DISCLAIMS ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT WITH REGARD TO THE LICENSED SOFTWARE.
+
+11. LIMITATION OF LIABILITY: IF, TROLLTECH'S WARRANTY DISCLAIMER NOTWITHSTANDING, TROLLTECH IS HELD LIABLE TO LICENSEE, WHETHER IN CONTRACT, TORT OR ANY OTHER LEGAL THEORY, BASED ON THE LICENSED SOFTWARE, TROLLTECH'S ENTIRE LIABILITY TO LICENSEE AND LICENSEE'S EXCLUSIVE REMEDY SHALL BE, AT TROLLTECH'S OPTION, EITHER (A) RETURN OF THE PRICE LICENSEE PAID FOR THE LICENSED SOFTWARE, OR (B) REPAIR OR REPLACEMENT OF THE LICENSED SOFTWARE, PROVIDED LICENSEE RETURNS TO TROLLTECH ALL COPIES OF THE LICENSED SOFTWARE AS ORIGINALLY DELIVERED TO LICENSEE. TROLLTECH SHALL NOT UNDER ANY CIRCUMSTANCES BE LIABLE TO LICENSEE BASED ON FAILURE OF THE LICENSED SOFTWARE IF THE FAILURE RESULTED FROM ACCIDENT, ABUSE OR MISAPPLICATION, NOR SHALL TROLLTECH UNDER ANY CIRCUMSTANCES BE LIABLE FOR SPECIAL DAMAGES, PUNITIVE OR EXEMPLARY DAMAGES, DAMAGES FOR LOSS OF PROFITS OR INTERRUPTION OF BUSINESS OR FOR LOSS OR CORRUPTION OF DATA. ANY AWARD OF DAMAGES FROM TROLLTECH TO LICENSEE SHALL NOT EXCEED THE TOTAL AMOUNT LICENSEE HAS PAID TO TROLLTECH IN CONNECTION WITH THIS AGREEMENT.
+
+12. Termination: Without prejudice to any other rights, Trolltech may terminate this Agreement if Licensee fails to comply with the terms and conditions of this Agreement. In such event, Licensee must destroy all copies of the Licensed Software and all of its components.
+
+13. Export Restrictions: Licensee agrees not to export or re-export the Licensed Software, any part thereof, or any process or service that is the direct product of the Licensed Software. Licensee may not sell, resell, or otherwise transfer for value, the Licensed Software (the foregoing collectively referred to as the "Restricted Components"), to any country, person, entity or end user subject to U.S. export restrictions. Licensee specifically agrees not to export or re-export any of the Restricted Components (i) to any country to which the U.S. has embargoed or restricted the export of goods or services, which currently include, but are not necessarily limited to Cuba, Iran, Iraq, Libya, North Korea, Sudan and Syria, or to any national of any such country, wherever located, who intends to transmit or transport the Restricted Components back to such country; (ii) to any end-user who Licensee knows or has reason to know will utilize the Restricted Components in the design, development or production of nuclear, chemical or biological weapons; or (iii) to any end-user who has been prohibited from participating in U.S. export transactions by any federal agency of the U.S. government. Licensee warrants and represents that neither the U.S. Commerce Department, Bureau of Export Administration nor any other U.S. federal agency has suspended, revoked or denied Licensee's export privileges.
+
+14. Government End Users: A "U.S. Government End User" shall mean any agency or entity of the government of the United States. The following shall apply if Licensee is a U.S. Government End User. The Licensed Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire the Licensed Software with only those rights set forth herein. The Licensed Software (including related documentation) is provided to U.S. Government End Users: (a) only as a commercial end item; and (b) only pursuant to this Agreement.
+
+15. Compliance with local laws: Licensee shall comply with all applicable laws and regulations relating to the Licensed Software in the United States and in other countries in which Licensee uses or modifies the Licensed Software. Without limiting the generality of the foregoing, Licensee shall not export, re-export, disclose or distribute any of the Licensed Software in violation of any applicable laws or regulations, including the export laws and regulations of the United States, and shall comply with all such laws and regulations.
+
+16. Entire Agreement: This Agreement constitutes the complete agreement between the parties and supersedes all prior or contemporaneous discussions, representations, and proposals, written or oral, with respect to the subject matters discussed herein. No modification of this Agreement will be effective unless contained in a writing executed by an authorized representative of each party. No term or condition contained in Licensee's purchase order will apply unless expressly accepted by Trolltech in writing. If any provision of the Agreement is found void or unenforceable, the remainder will remain valid and enforceable according to its terms. If any remedy provided is determined to have failed for its essential purpose, all limitations of liability and exclusions of damages set forth in this Agreement shall remain in effect.
+
+17. Governing law, legal venue: This Agreement shall be construed, interpreted and governed by the laws of the State of California, USA. Any action or proceeding arising from or relating to this Agreement shall be brought in a federal court in the Northern District of California or in the State Court in Santa Clara County, California, and each party irrevocably submits to the personal jurisdiction of any such court in any such action or proceeding. The Agreement gives Licensee specific legal rights; Licensee may have others, which vary from state to state and from country to country. Trolltech reserves all rights not specifically granted in this Agreement.
+
+
+
+
+For legal entities and/or individuals residing in any country other than Canada, the United States of America or South America:
+TROLLTECH TECHNOLOGY PREVIEW LICENSE AGREEMENT: NORWAY
+
+Agreement version 2.0
+IMPORTANT-READ CAREFULLY:
+
+1. This Trolltech Technology Preview License Agreement ("Agreement") is a legal agreement between you (either an individual or a legal entity) and Trolltech ASA ("Trolltech"), and pertains to the Trolltech software product(s) accompanying this Agreement, which include(s) computer software and may include "online" or electronic documentation, associated media, and printed materials, including the source code, example programs and the documentation ("Licensed Software").
+
+2. The Licensed Software is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. Trolltech retains all rights not expressly granted. No title, property rights or copyright in the Licensed Software or in any modifications to the Licensed Software shall pass to the Licensee under any circumstances. The Licensed Software is licensed, not sold.
+
+3. By installing, copying, or otherwise using the Licensed Software, Licensee agrees to be bound by the terms of this Agreement. If Licensee does not agree to the terms of this Agreement, Licensee should not install, copy, or otherwise use the Licensed Software.
+
+4. Upon Licensee's acceptance of the terms and conditions of this Agreement, Trolltech grants Licensee the right to use the Licensed Software in the manner provided below.
+
+5. Trolltech grants to Licensee as an individual a personal, non-exclusive, non-transferable license to make and use copies of the Licensed Software for the sole purpose of evaluating and testing the Licensed Software and/or providing feedback to Trolltech. Licensee may install copies of the Licensed Software on an unlimited number of computers provided that Licensee is the only individual using the Licensed Software. If Licensee is an entity, Trolltech grants Licensee the right to designate one, and only one, individual within Licensee's organization who shall have the sole right to use the Licensed Software in the manner provided in this Agreement. Licensee may, at any time, but not more frequently than once every six (6) months, designate another individual to replace the current designated user by notifying Trolltech, so long as there is no more than one (1) designated user at any given time
+
+6. Licensee may not loan, rent, lease, or license the Licensed Software or any copy of it. Licensee may not alter or remove any details of ownership, copyright, trademark or other property right connected with the Licensed Software. Licensee may not modify or distribute the Licensed Software. Licensee may not distribute any software statically or dynamically linked with the Licensed Software.
+
+7. This Licensed Software is time-limited. All rights granted to Licensee in this Agreement will be void three (3) months after Licensee received the Licensed Software.
+
+8. The Licensed Software may provide links to third party libraries or code (collectively "Third Party Libraries") to implement various functions. Third Party Libraries do not comprise part of the Licensed Software. In some cases, access to Third Party Libraries may be included along with the Licensed Software delivery as a convenience for development and testing only. Such source code and libraries as are or may be listed in the ".../src/3rdparty" source tree delivered with the Licensed Software, as may be amended from time to time, do not comprise the Licensed Software. Licensee acknowledges (1) that some Third Party Libraries may require additional licensing of copyright and patents from the owners of such, and (2) that distribution of any of the Licensed Software referencing any portion of a Third Party Library may require appropriate licensing from such third parties.
+
+9. Pre-Release Code, Non-Commercial Use: The Licensed Software contains Pre-release Code that is not at the level of performance and compatibility of a final, generally available, product offering. The Licensed Software may not operate correctly and may be substantially modified prior to the first commercial shipment, if any. Trolltech is not obligated to make this or any later version of the Licensed Software commercially available. The License Software is "Not for Commercial Use" and may only be used for the purposes described in Section 5. You may not use the Licensed Software in a live operating environment where it may be relied upon to perform in the same manner as a commercially released product or with data that has not been sufficiently backed up.
+
+10. WARRANTY DISCLAIMER: THE LICENSED SOFTWARE IS LICENSED TO LICENSEE "AS IS". TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, TROLLTECH ON BEHALF OF ITSELF AND ITS SUPPLIERS, DISCLAIMS ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT WITH REGARD TO THE LICENSED SOFTWARE.
+
+11. LIMITATION OF LIABILITY: IF, TROLLTECH'S WARRANTY DISCLAIMER NOTWITHSTANDING, TROLLTECH IS HELD LIABLE TO LICENSEE, WHETHER IN CONTRACT, TORT OR ANY OTHER LEGAL THEORY, BASED ON THE LICENSED SOFTWARE, TROLLTECH'S ENTIRE LIABILITY TO LICENSEE AND LICENSEE'S EXCLUSIVE REMEDY SHALL BE, AT TROLLTECH'S OPTION, EITHER (A) RETURN OF THE PRICE LICENSEE PAID FOR THE LICENSED SOFTWARE, OR (B) REPAIR OR REPLACEMENT OF THE LICENSED SOFTWARE, PROVIDED LICENSEE RETURNS TO TROLLTECH ALL COPIES OF THE LICENSED SOFTWARE AS ORIGINALLY DELIVERED TO LICENSEE. TROLLTECH SHALL NOT UNDER ANY CIRCUMSTANCES BE LIABLE TO LICENSEE BASED ON FAILURE OF THE LICENSED SOFTWARE IF THE FAILURE RESULTED FROM ACCIDENT, ABUSE OR MISAPPLICATION, NOR SHALL TROLLTECH UNDER ANY CIRCUMSTANCES BE LIABLE FOR SPECIAL DAMAGES, PUNITIVE OR EXEMPLARY DAMAGES, DAMAGES FOR LOSS OF PROFITS OR INTERRUPTION OF BUSINESS OR FOR LOSS OR CORRUPTION OF DATA. ANY AWARD OF DAMAGES FROM TROLLTECH TO LICENSEE SHALL NOT EXCEED THE TOTAL AMOUNT LICENSEE HAS PAID TO TROLLTECH IN CONNECTION WITH THIS AGREEMENT.
+
+12. Termination: Without prejudice to any other rights, Trolltech may terminate this Agreement if Licensee fails to comply with the terms and conditions of this Agreement. In such event, Licensee must destroy all copies of the Licensed Software and all of its components.
+
+13. Export Restrictions: Licensee agrees not to export or re-export the Licensed Software, any part thereof, or any process or service that is the direct product of the Licensed Software. Licensee may not sell, resell, or otherwise transfer for value, the Licensed Software (the foregoing collectively referred to as the "Restricted Components"), to any country, person, entity or end user subject to U.S. export restrictions. Licensee specifically agrees not to export or re-export any of the Restricted Components (i) to any country to which the U.S. has embargoed or restricted the export of goods or services, which currently include, but are not necessarily limited to Cuba, Iran, Iraq, Libya, North Korea, Sudan and Syria, or to any national of any such country, wherever located, who intends to transmit or transport the Restricted Components back to such country; (ii) to any end-user who Licensee knows or has reason to know will utilize the Restricted Components in the design, development or production of nuclear, chemical or biological weapons; or (iii) to any end-user who has been prohibited from participating in U.S. export transactions by any federal agency of the U.S. government. Licensee warrants and represents that neither the U.S. Commerce Department, Bureau of Export Administration nor any other U.S. federal agency has suspended, revoked or denied Licensee's export privileges.
+
+14. Government End Users: A "U.S. Government End User" shall mean any agency or entity of the government of the United States. The following shall apply if Licensee is a U.S. Government End User. The Licensed Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire the Licensed Software with only those rights set forth herein. The Licensed Software (including related documentation) is provided to U.S. Government End Users: (a) only as a commercial end item; and (b) only pursuant to this Agreement.
+
+15. Compliance with local laws: Licensee shall comply with all applicable laws and regulations relating to the Licensed Software in the United States and in other countries in which Licensee uses or modifies the Licensed Software. Without limiting the generality of the foregoing, Licensee shall not export, re-export, disclose or distribute any of the Licensed Software in violation of any applicable laws or regulations, including the export laws and regulations of the United States, and shall comply with all such laws and regulations.
+
+16. Entire Agreement: This Agreement constitutes the complete agreement between the parties and supersedes all prior or contemporaneous discussions, representations, and proposals, written or oral, with respect to the subject matters discussed herein. No modification of this Agreement will be effective unless contained in a writing executed by an authorized representative of each party. No term or condition contained in Licensee's purchase order will apply unless expressly accepted by Trolltech in writing. If any provision of the Agreement is found void or unenforceable, the remainder will remain valid and enforceable according to its terms. If any remedy provided is determined to have failed for its essential purpose, all limitations of liability and exclusions of damages set forth in this Agreement shall remain in effect.
+
+17. Governing law, legal venue: This Agreement shall be construed, interpreted and governed by the laws of Norway, the legal venue to be Oslo City Court. Trolltech reserves all rights not specifically granted in this Agreement.
diff --git a/installer/resources/logo.png b/installer/resources/logo.png
new file mode 100644
index 0000000000..8a9562614b
--- /dev/null
+++ b/installer/resources/logo.png
Binary files differ
diff --git a/installer/resources/watermark.png b/installer/resources/watermark.png
new file mode 100644
index 0000000000..b07780d9d0
--- /dev/null
+++ b/installer/resources/watermark.png
Binary files differ
diff --git a/qtcreator.pro b/qtcreator.pro
new file mode 100644
index 0000000000..13f0b26fa3
--- /dev/null
+++ b/qtcreator.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = src
diff --git a/replaceVersion.sh b/replaceVersion.sh
new file mode 100755
index 0000000000..0bb38a68a9
--- /dev/null
+++ b/replaceVersion.sh
@@ -0,0 +1,101 @@
+#! /usr/bin/env bash
+
+## Command line parameters
+if [[ $# != 2 ]]; then
+ cat <<USAGE
+usage:
+ $0 <old> <new>
+example:
+ $0 '1.2.3' '1.2.4'
+USAGE
+ exit 1
+fi
+
+
+## Process and show version
+OLD=`sed 's/\./\\\\./g' <<<"$1"`
+NEW=`sed 's/\./\\\\./g' <<<"$2"`
+
+OLD_MAJOR=`sed 's/^\([0-9]\+\)\.[0-9]\+\.[0-9]\+$/\1/' <<<"$1"`
+NEW_MAJOR=`sed 's/^\([0-9]\+\)\.[0-9]\+\.[0-9]\+$/\1/' <<<"$2"`
+
+OLD_MINOR=`sed 's/^[0-9]\+\.\([0-9]\+\)\.[0-9]\+$/\1/' <<<"$1"`
+NEW_MINOR=`sed 's/^[0-9]\+\.\([0-9]\+\)\.[0-9]\+$/\1/' <<<"$2"`
+
+OLD_RELEASE=`sed 's/^[0-9]\+\.[0-9]\+\.\([0-9]\+\)$/\1/' <<<"$1"`
+NEW_RELEASE=`sed 's/^[0-9]\+\.[0-9]\+\.\([0-9]\+\)$/\1/' <<<"$2"`
+
+OLD_DOT_FOUR="${OLD_MAJOR}\\.${OLD_MINOR}\\.${OLD_RELEASE}\\.0"
+NEW_DOT_FOUR="${NEW_MAJOR}\\.${NEW_MINOR}\\.${NEW_RELEASE}\\.0"
+
+OLD_COMMA_FOUR="${OLD_MAJOR},${OLD_MINOR},${OLD_RELEASE},0"
+NEW_COMMA_FOUR="${NEW_MAJOR},${NEW_MINOR},${NEW_RELEASE},0"
+
+echo "#==============================================="
+echo "# Plain '${OLD}' -> '${NEW}'"
+echo "#-----------------------------------------------"
+echo "# Major '${OLD_MAJOR}' -> '${NEW_MAJOR}'"
+echo "# Minor '${OLD_MINOR}' -> '${NEW_MINOR}'"
+echo "# Release '${OLD_RELEASE}' -> '${NEW_RELEASE}'"
+echo "#-----------------------------------------------"
+echo "# Dots '${OLD_DOT_FOUR}' -> '${NEW_DOT_FOUR}'"
+echo "# Comma '${OLD_COMMA_FOUR}' -> '${NEW_COMMA_FOUR}'"
+echo "#==============================================="
+echo
+
+
+## Make script safe to call from anywhere by going home first
+SCRIPT_DIR=`dirname "${PWD}/$0"`
+echo "Entering directory \`${SCRIPT_DIR}'"
+pushd "${SCRIPT_DIR}" &>/dev/null || exit 1
+
+
+## Patch *.pluginspec
+while read i ; do
+ echo "Patching \`$i'"
+ TMPFILE=`mktemp`
+ sed -e 's/version="'"${OLD}"'"/version="'"${NEW}"'"/' \
+ -e 's/compatVersion="'"${OLD}"'"/compatVersion="'"${NEW}"'"/' \
+ "${i}" > "${TMPFILE}"
+ mv -f "${TMPFILE}" "${i}"
+done < <(find . -name '*.pluginspec')
+
+
+## Patch coreconstants.h
+TMPFILE=`mktemp`
+CORE_CONSTANT_H="${SCRIPT_DIR}/src/plugins/coreplugin/coreconstants.h"
+echo "Patching \`${CORE_CONSTANT_H}'"
+sed \
+ -e 's/^\(#define IDE_VERSION_MAJOR \)'"${OLD_MAJOR}"'/\1'"${NEW_MAJOR}"'/' \
+ -e 's/^\(#define IDE_VERSION_MINOR \)'"${OLD_MINOR}"'/\1'"${NEW_MINOR}"'/' \
+ -e 's/^\(#define IDE_VERSION_RELEASE \)'"${OLD_RELEASE}"'/\1'"${NEW_RELEASE}"'/' \
+ "${CORE_CONSTANT_H}" > "${TMPFILE}"
+mv -f "${TMPFILE}" "${CORE_CONSTANT_H}"
+
+
+## Patch installer.rc
+TMPFILE=`mktemp`
+INSTALLER_RC="${SCRIPT_DIR}/../ide/nightly_builds/installer/installer.rc"
+echo "Patching \`${INSTALLER_RC}'"
+sed \
+ -e "s/"${OLD_DOT_FOUR}"/"${NEW_DOT_FOUR}"/" \
+ -e "s/"${OLD_COMMA_FOUR}"/"${NEW_COMMA_FOUR}"/" \
+ "${INSTALLER_RC}" > "${TMPFILE}"
+ p4 edit `sed -e 's/\/\.\//\//g' -e 's/\/[^\/]\+\/\.\.\//\//g' <<<"${INSTALLER_RC}"`
+mv -f "${TMPFILE}" "${INSTALLER_RC}"
+
+
+## Patch installer.rc
+TMPFILE=`mktemp`
+INFO_PLIST="${SCRIPT_DIR}/src/app/Info.plist"
+echo "Patching \`${INFO_PLIST}'"
+sed \
+ -e "s/"${OLD}"/"${NEW}"/" \
+ "${INFO_PLIST}" > "${TMPFILE}"
+mv -f "${TMPFILE}" "${INFO_PLIST}"
+
+
+## Go back to original $PWD
+echo "Leaving directory \`${SCRIPT_DIR}'"
+popd &>/dev/null || exit 1
+exit 0
diff --git a/shared/cpaster/cgi.cpp b/shared/cpaster/cgi.cpp
new file mode 100644
index 0000000000..222d0c9d08
--- /dev/null
+++ b/shared/cpaster/cgi.cpp
@@ -0,0 +1,428 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cgi.h"
+
+#include <QByteArray>
+
+// -------------------------------------------------------------------------------------------------
+
+const char *cgi_chars = "0123456789abcdef"; // RFC 1738 suggests lower-case to be optimal
+QString CGI::encodeURL(const QString &rawText)
+{
+ QByteArray utf = rawText.toUtf8();
+ QString enc;
+ enc.reserve(utf.length()); // Make sure we at least have space for a normal US-ASCII URL
+
+ QByteArray::const_iterator it = utf.constBegin();
+ while(it != utf.constEnd()) {
+ char ch = *it;
+ if (('A' <= ch && ch <= 'Z')
+ || ('a' <= ch && ch <= 'z')
+ || ('0' <= ch && ch <= '9'))
+ enc.append(*it);
+ else if (ch == ' ')
+ enc.append('+');
+ else {
+ switch(ch) {
+ case '-': case '_':
+ case '(': case ')':
+ case '.': case '!':
+ case '~': case '*':
+ case '\'':
+ enc.append(ch);
+ break;
+ default:
+ ushort c1 = (*it & 0xF0) >> 4;
+ ushort c2 = (*it & 0x0F);
+ enc.append('%');
+ enc.append(QChar(*(cgi_chars + c1)));
+ enc.append(QChar(*(cgi_chars + c2)));
+ break;
+ }
+ }
+ ++it;
+ }
+ return enc;
+}
+
+QString CGI::decodeURL(const QString &urlText)
+{
+ QByteArray dec;
+ QString::const_iterator it = urlText.constBegin();
+ while(it != urlText.constEnd()) {
+ ushort ch = (*it).unicode();
+ switch(ch) {
+ case '%':
+ {
+ char c1 = char(0x00ff & (*(++it)).unicode());
+ char c2 = char(0x00ff & (*(++it)).unicode());
+ ushort v = 0;
+ if('A' <= c1 && c1 <= 'Z')
+ v = c1 - 'A' + 10;
+ else if ('a' <= c1 && c1 <= 'z')
+ v = c1 - 'a' + 10;
+ else if ('0' <= c1 && c1 <= '9')
+ v = c1 - '0';
+ else
+ continue; // Malformed URL!
+ v <<= 4; // c1 was MSB half
+ if('A' <= c2 && c2 <= 'Z')
+ v |= c2 - 'A' + 10;
+ else if ('a' <= c2 && c2 <= 'z')
+ v |= c2 - 'a' + 10;
+ else if ('0' <= c2 && c2 <= '9')
+ v |= c2 - '0';
+ else
+ continue; // Malformed URL!
+ dec.append((char)v);
+ }
+ break;
+ case '+':
+ dec.append(' ');
+ break;
+ default:
+ dec.append(*it);
+ break;
+ }
+ ++it;
+ }
+ return QString::fromUtf8(dec.constData(), dec.length());
+}
+
+// -------------------------------------------------------------------------------------------------
+inline const char *unicodeToHTML(ushort unicode_char)
+{
+ switch(unicode_char) {
+ // Latin -------------------------------
+ case 0x0022: return "quot"; // (34 ) quotation mark = APL quote
+ case 0x0026: return "amp"; // (38 ) ampersand
+ case 0x003C: return "lt"; // (60 ) less-than sign
+ case 0x003E: return "gt"; // (62 ) greater-than sign
+ case 0x00A0: return "nbsp"; // (160 ) no-break space = non-breaking space
+ case 0x00A1: return "iexcl"; // (161 ) inverted exclamation mark
+ case 0x00A2: return "cent"; // (162 ) cent sign
+ case 0x00A3: return "pound"; // (163 ) pound sign
+ case 0x00A4: return "curren"; // (164 ) currency sign
+ case 0x00A5: return "yen"; // (165 ) yen sign = yuan sign
+ case 0x00A6: return "brvbar"; // (166 ) broken bar = broken vertical bar
+ case 0x00A7: return "sect"; // (167 ) section sign
+ case 0x00A8: return "uml"; // (168 ) diaeresis = spacing diaeresis
+ case 0x00A9: return "copy"; // (169 ) copyright sign
+ case 0x00AA: return "ordf"; // (170 ) feminine ordinal indicator
+ case 0x00AB: return "laquo"; // (171 ) left-pointing double angle quotation mark = left pointing guillemet
+ case 0x00AC: return "not"; // (172 ) not sign
+ case 0x00AD: return "shy"; // (173 ) soft hyphen = discretionary hyphen
+ case 0x00AE: return "reg"; // (174 ) registered sign = registered trade mark sign
+ case 0x00AF: return "macr"; // (175 ) macron = spacing macron = overline = APL overbar
+ case 0x00B0: return "deg"; // (176 ) degree sign
+ case 0x00B1: return "plusmn"; // (177 ) plus-minus sign = plus-or-minus sign
+ case 0x00B2: return "sup2"; // (178 ) superscript two = superscript digit two = squared
+ case 0x00B3: return "sup3"; // (179 ) superscript three = superscript digit three = cubed
+ case 0x00B4: return "acute"; // (180 ) acute accent = spacing acute
+ case 0x00B5: return "micro"; // (181 ) micro sign
+ case 0x00B6: return "para"; // (182 ) pilcrow sign = paragraph sign
+ case 0x00B7: return "middot"; // (183 ) middle dot = Georgian comma = Greek middle dot
+ case 0x00B8: return "cedil"; // (184 ) cedilla = spacing cedilla
+ case 0x00B9: return "sup1"; // (185 ) superscript one = superscript digit one
+ case 0x00BA: return "ordm"; // (186 ) masculine ordinal indicator
+ case 0x00BB: return "raquo"; // (187 ) right-pointing double angle quotation mark = right pointing guillemet
+ case 0x00BC: return "frac14"; // (188 ) vulgar fraction one quarter = fraction one quarter
+ case 0x00BD: return "frac12"; // (189 ) vulgar fraction one half = fraction one half
+ case 0x00BE: return "frac34"; // (190 ) vulgar fraction three quarters = fraction three quarters
+ case 0x00BF: return "iquest"; // (191 ) inverted question mark = turned question mark
+ case 0x00C0: return "Agrave"; // (192 ) capital letter A with grave = capital letter À
+ case 0x00C1: return "Aacute"; // (193 ) capital letter A with acute
+ case 0x00C2: return "Acirc"; // (194 ) capital letter A with circumflex
+ case 0x00C3: return "Atilde"; // (195 ) capital letter A with tilde
+ case 0x00C4: return "Auml"; // (196 ) capital letter A with diaeresis
+ case 0x00C5: return "Aring"; // (197 ) capital letter A with ring above = capital letter Å
+ case 0x00C6: return "AElig"; // (198 ) capital letter AE = capital ligature Æ
+ case 0x00C7: return "Ccedil"; // (199 ) capital letter C with cedilla
+ case 0x00C8: return "Egrave"; // (200 ) capital letter E with grave
+ case 0x00C9: return "Eacute"; // (201 ) capital letter E with acute
+ case 0x00CA: return "Ecirc"; // (202 ) capital letter E with circumflex
+ case 0x00CB: return "Euml"; // (203 ) capital letter E with diaeresis
+ case 0x00CC: return "Igrave"; // (204 ) capital letter I with grave
+ case 0x00CD: return "Iacute"; // (205 ) capital letter I with acute
+ case 0x00CE: return "Icirc"; // (206 ) capital letter I with circumflex
+ case 0x00CF: return "Iuml"; // (207 ) capital letter I with diaeresis
+ case 0x00D0: return "ETH"; // (208 ) capital letter ETH
+ case 0x00D1: return "Ntilde"; // (209 ) capital letter N with tilde
+ case 0x00D2: return "Ograve"; // (210 ) capital letter O with grave
+ case 0x00D3: return "Oacute"; // (211 ) capital letter O with acute
+ case 0x00D4: return "Ocirc"; // (212 ) capital letter O with circumflex
+ case 0x00D5: return "Otilde"; // (213 ) capital letter O with tilde
+ case 0x00D6: return "Ouml"; // (214 ) capital letter O with diaeresis
+ case 0x00D7: return "times"; // (215 ) multiplication sign
+ case 0x00D8: return "Oslash"; // (216 ) capital letter O with stroke = capital letter Ø
+ case 0x00D9: return "Ugrave"; // (217 ) capital letter U with grave
+ case 0x00DA: return "Uacute"; // (218 ) capital letter U with acute
+ case 0x00DB: return "Ucirc"; // (219 ) capital letter U with circumflex
+ case 0x00DC: return "Uuml"; // (220 ) capital letter U with diaeresis
+ case 0x00DD: return "Yacute"; // (221 ) capital letter Y with acute
+ case 0x00DE: return "THORN"; // (222 ) capital letter THORN
+ case 0x00DF: return "szlig"; // (223 ) small letter sharp s = ess-zed
+ case 0x00E0: return "agrave"; // (224 ) small letter a with grave = small letter à
+ case 0x00E1: return "aacute"; // (225 ) small letter a with acute
+ case 0x00E2: return "acirc"; // (226 ) small letter a with circumflex
+ case 0x00E3: return "atilde"; // (227 ) small letter a with tilde
+ case 0x00E4: return "auml"; // (228 ) small letter a with diaeresis
+ case 0x00E5: return "aring"; // (229 ) small letter a with ring above = small letter å
+ case 0x00E6: return "aelig"; // (230 ) small letter ae = small letter æ
+ case 0x00E7: return "ccedil"; // (231 ) small letter c with cedilla
+ case 0x00E8: return "egrave"; // (232 ) small letter e with grave
+ case 0x00E9: return "eacute"; // (233 ) small letter e with acute
+ case 0x00EA: return "ecirc"; // (234 ) small letter e with circumflex
+ case 0x00EB: return "euml"; // (235 ) small letter e with diaeresis
+ case 0x00EC: return "igrave"; // (236 ) small letter i with grave
+ case 0x00ED: return "iacute"; // (237 ) small letter i with acute
+ case 0x00EE: return "icirc"; // (238 ) small letter i with circumflex
+ case 0x00EF: return "iuml"; // (239 ) small letter i with diaeresis
+ case 0x00F0: return "eth"; // (240 ) small letter eth
+ case 0x00F1: return "ntilde"; // (241 ) small letter n with tilde
+ case 0x00F2: return "ograve"; // (242 ) small letter o with grave
+ case 0x00F3: return "oacute"; // (243 ) small letter o with acute
+ case 0x00F4: return "ocirc"; // (244 ) small letter o with circumflex
+ case 0x00F5: return "otilde"; // (245 ) small letter o with tilde
+ case 0x00F6: return "ouml"; // (246 ) small letter o with diaeresis
+ case 0x00F7: return "divide"; // (247 ) division sign
+ case 0x00F8: return "oslash"; // (248 ) small letter o with stroke = small letter ø
+ case 0x00F9: return "ugrave"; // (249 ) small letter u with grave
+ case 0x00FA: return "uacute"; // (250 ) small letter u with acute
+ case 0x00FB: return "ucirc"; // (251 ) small letter u with circumflex
+ case 0x00FC: return "uuml"; // (252 ) small letter u with diaeresis
+ case 0x00FD: return "yacute"; // (253 ) small letter y with acute
+ case 0x00FE: return "thorn"; // (254 ) small letter thorn
+ case 0x00FF: return "yuml"; // (255 ) small letter y with diaeresis
+ case 0x0152: return "OElig"; // (338 ) capital ligature OE
+ case 0x0153: return "oelig"; // (339 ) small ligature oe
+ case 0x0160: return "Scaron"; // (352 ) capital letter S with caron
+ case 0x0161: return "scaron"; // (353 ) small letter s with caron
+ case 0x0178: return "Yuml"; // (376 ) capital letter Y with diaeresis
+ case 0x0192: return "fnof"; // (402 ) small f with hook = function = florin
+ case 0x02C6: return "circ"; // (710 ) modifier letter circumflex accent
+ case 0x02DC: return "tilde"; // (732 ) small tilde
+ // Greek -------------------------------
+ case 0x0391: return "Alpha"; // (913 ) capital letter alpha
+ case 0x0392: return "Beta"; // (914 ) capital letter beta
+ case 0x0393: return "Gamma"; // (915 ) capital letter gamma
+ case 0x0394: return "Delta"; // (916 ) capital letter delta
+ case 0x0395: return "Epsilon"; // (917 ) capital letter epsilon
+ case 0x0396: return "Zeta"; // (918 ) capital letter zeta
+ case 0x0397: return "Eta"; // (919 ) capital letter eta
+ case 0x0398: return "Theta"; // (920 ) capital letter theta
+ case 0x0399: return "Iota"; // (921 ) capital letter iota
+ case 0x039A: return "Kappa"; // (922 ) capital letter kappa
+ case 0x039B: return "Lambda"; // (923 ) capital letter lambda
+ case 0x039C: return "Mu"; // (924 ) capital letter mu
+ case 0x039D: return "Nu"; // (925 ) capital letter nu
+ case 0x039E: return "Xi"; // (926 ) capital letter xi
+ case 0x039F: return "Omicron"; // (927 ) capital letter omicron
+ case 0x03A0: return "Pi"; // (928 ) capital letter pi
+ case 0x03A1: return "Rho"; // (929 ) capital letter rho
+ case 0x03A3: return "Sigma"; // (931 ) capital letter sigma
+ case 0x03A4: return "Tau"; // (932 ) capital letter tau
+ case 0x03A5: return "Upsilon"; // (933 ) capital letter upsilon
+ case 0x03A6: return "Phi"; // (934 ) capital letter phi
+ case 0x03A7: return "Chi"; // (935 ) capital letter chi
+ case 0x03A8: return "Psi"; // (936 ) capital letter psi
+ case 0x03A9: return "Omega"; // (937 ) capital letter omega
+ case 0x03B1: return "alpha"; // (945 ) small letter alpha
+ case 0x03B2: return "beta"; // (946 ) small letter beta
+ case 0x03B3: return "gamma"; // (947 ) small letter gamma
+ case 0x03B4: return "delta"; // (948 ) small letter delta
+ case 0x03B5: return "epsilon"; // (949 ) small letter epsilon
+ case 0x03B6: return "zeta"; // (950 ) small letter zeta
+ case 0x03B7: return "eta"; // (951 ) small letter eta
+ case 0x03B8: return "theta"; // (952 ) small letter theta
+ case 0x03B9: return "iota"; // (953 ) small letter iota
+ case 0x03BA: return "kappa"; // (954 ) small letter kappa
+ case 0x03BB: return "lambda"; // (955 ) small letter lambda
+ case 0x03BC: return "mu"; // (956 ) small letter mu
+ case 0x03BD: return "nu"; // (957 ) small letter nu
+ case 0x03BE: return "xi"; // (958 ) small letter xi
+ case 0x03BF: return "omicron"; // (959 ) small letter omicron
+ case 0x03C0: return "pi"; // (960 ) small letter pi
+ case 0x03C1: return "rho"; // (961 ) small letter rho
+ case 0x03C2: return "sigmaf"; // (962 ) small letter final sigma
+ case 0x03C3: return "sigma"; // (963 ) small letter sigma
+ case 0x03C4: return "tau"; // (964 ) small letter tau
+ case 0x03C5: return "upsilon"; // (965 ) small letter upsilon
+ case 0x03C6: return "phi"; // (966 ) small letter phi
+ case 0x03C7: return "chi"; // (967 ) small letter chi
+ case 0x03C8: return "psi"; // (968 ) small letter psi
+ case 0x03C9: return "omega"; // (969 ) small letter omega
+ case 0x03D1: return "thetasym";// (977 ) small letter theta symbol
+ case 0x03D2: return "upsih"; // (978 ) upsilon with hook symbol
+ case 0x03D6: return "piv"; // (982 ) pi symbol
+ // General Punctuation -----------------
+ case 0x2002: return "ensp"; // (8194) en space
+ case 0x2003: return "emsp"; // (8195) em space
+ case 0x2009: return "thinsp"; // (8201) thin space
+ case 0x200C: return "zwnj"; // (8204) zero width non-joiner
+ case 0x200D: return "zwj"; // (8205) zero width joiner
+ case 0x200E: return "lrm"; // (8206) left-to-right mark
+ case 0x200F: return "rlm"; // (8207) right-to-left mark
+ case 0x2013: return "ndash"; // (8211) en dash
+ case 0x2014: return "mdash"; // (8212) em dash
+ case 0x2018: return "lsquo"; // (8216) left single quotation mark
+ case 0x2019: return "rsquo"; // (8217) right single quotation mark
+ case 0x201A: return "sbquo"; // (8218) single low-9 quotation mark
+ case 0x201C: return "ldquo"; // (8220) left double quotation mark
+ case 0x201D: return "rdquo"; // (8221) right double quotation mark
+ case 0x201E: return "bdquo"; // (8222) double low-9 quotation mark
+ case 0x2020: return "dagger"; // (8224) dagger
+ case 0x2021: return "Dagger"; // (8225) double dagger
+ case 0x2022: return "bull"; // (8226) bullet = black small circle
+ case 0x2026: return "hellip"; // (8230) horizontal ellipsis = three dot leader
+ case 0x2030: return "permil"; // (8240) per mille sign
+ case 0x2032: return "prime"; // (8242) prime = minutes = feet
+ case 0x2033: return "Prime"; // (8243) double prime = seconds = inches
+ case 0x2039: return "lsaquo"; // (8249) single left-pointing angle quotation mark
+ case 0x203A: return "rsaquo"; // (8250) single right-pointing angle quotation mark
+ case 0x203E: return "oline"; // (8254) overline = spacing overscore
+ case 0x2044: return "frasl"; // (8260) fraction slash
+ // Currency Symbols --------------------
+ case 0x20AC: return "euro"; // (8364) euro sign
+ // Letterlike Symbols ------------------
+ case 0x2111: return "image"; // (8465) blackletter capital I = imaginary part
+ case 0x2118: return "weierp"; // (8472) script capital P = power set = Weierstrass p
+ case 0x211C: return "real"; // (8476) blackletter capital R = real part symbol
+ case 0x2122: return "trade"; // (8482) trade mark sign
+ case 0x2135: return "alefsym"; // (8501) alef symbol = first transfinite cardinal
+ // Arrows ------------------------------
+ case 0x2190: return "larr"; // (8592) leftwards arrow
+ case 0x2191: return "uarr"; // (8593) upwards arrow
+ case 0x2192: return "rarr"; // (8594) rightwards arrow
+ case 0x2193: return "darr"; // (8595) downwards arrow
+ case 0x2194: return "harr"; // (8596) left right arrow
+ case 0x21B5: return "crarr"; // (8629) downwards arrow with corner leftwards = carriage return
+ case 0x21D0: return "lArr"; // (8656) leftwards double arrow
+ case 0x21D1: return "uArr"; // (8657) upwards double arrow
+ case 0x21D2: return "rArr"; // (8658) rightwards double arrow
+ case 0x21D3: return "dArr"; // (8659) downwards double arrow
+ case 0x21D4: return "hArr"; // (8660) left right double arrow
+ // Mathematical Operators --------------
+ case 0x2200: return "forall"; // (8704) for all
+ case 0x2202: return "part"; // (8706) partial differential
+ case 0x2203: return "exist"; // (8707) there exists
+ case 0x2205: return "empty"; // (8709) empty set = null set = diameter
+ case 0x2207: return "nabla"; // (8711) nabla = backward difference
+ case 0x2208: return "isin"; // (8712) element of
+ case 0x2209: return "notin"; // (8713) not an element of
+ case 0x220B: return "ni"; // (8715) contains as member
+ case 0x220F: return "prod"; // (8719) n-ary product = product sign
+ case 0x2211: return "sum"; // (8721) n-ary sumation
+ case 0x2212: return "minus"; // (8722) minus sign
+ case 0x2217: return "lowast"; // (8727) asterisk operator
+ case 0x221A: return "radic"; // (8730) square root = radical sign
+ case 0x221D: return "prop"; // (8733) proportional to
+ case 0x221E: return "infin"; // (8734) infinity
+ case 0x2220: return "ang"; // (8736) angle
+ case 0x2227: return "and"; // (8743) logical and = wedge
+ case 0x2228: return "or"; // (8744) logical or = vee
+ case 0x2229: return "cap"; // (8745) intersection = cap
+ case 0x222A: return "cup"; // (8746) union = cup
+ case 0x222B: return "int"; // (8747) integral
+ case 0x2234: return "there4"; // (8756) therefore
+ case 0x223C: return "sim"; // (8764) tilde operator = varies with = similar to
+ case 0x2245: return "cong"; // (8773) approximately equal to
+ case 0x2248: return "asymp"; // (8776) almost equal to = asymptotic to
+ case 0x2260: return "ne"; // (8800) not equal to
+ case 0x2261: return "equiv"; // (8801) identical to
+ case 0x2264: return "le"; // (8804) less-than or equal to
+ case 0x2265: return "ge"; // (8805) greater-than or equal to
+ case 0x2282: return "sub"; // (8834) subset of
+ case 0x2283: return "sup"; // (8835) superset of
+ case 0x2284: return "nsub"; // (8836) not a subset of
+ case 0x2286: return "sube"; // (8838) subset of or equal to
+ case 0x2287: return "supe"; // (8839) superset of or equal to
+ case 0x2295: return "oplus"; // (8853) circled plus = direct sum
+ case 0x2297: return "otimes"; // (8855) circled times = vector product
+ case 0x22A5: return "perp"; // (8869) up tack = orthogonal to = perpendicular
+ case 0x22C5: return "sdot"; // (8901) dot operator
+ // Miscellaneous Technical -------------
+ case 0x2308: return "lceil"; // (8968) left ceiling = apl upstile
+ case 0x2309: return "rceil"; // (8969) right ceiling
+ case 0x230A: return "lfloor"; // (8970) left floor = apl downstile
+ case 0x230B: return "rfloor"; // (8971) right floor
+ case 0x2329: return "lang"; // (9001) left-pointing angle bracket = bra
+ case 0x232A: return "rang"; // (9002) right-pointing angle bracket = ket
+ // Geometric Shapes --------------------
+ case 0x25CA: return "loz"; // (9674) lozenge
+ // Miscellaneous Symbols ---------------
+ case 0x2660: return "spades"; // (9824) black spade suit
+ case 0x2663: return "clubs"; // (9827) black club suit = shamrock
+ case 0x2665: return "hearts"; // (9829) black heart suit = valentine
+ case 0x2666: return "diams"; // (9830) black diamond suit
+ default: break;
+ }
+ return 0;
+}
+
+QString CGI::encodeHTML(const QString &rawText, int conversionFlags)
+{
+ QString enc;
+ enc.reserve(rawText.length()); // at least
+
+ QString::const_iterator it = rawText.constBegin();
+ while (it != rawText.constEnd()) {
+ const char *html = unicodeToHTML((*it).unicode());
+ if (html) {
+ enc.append('&');
+ enc.append(html);
+ enc.append(';');
+ } else if ((conversionFlags & CGI::LineBreaks)
+ && ((*it).toLatin1() == '\n')) {
+ enc.append("<BR>\n");
+ } else if ((conversionFlags & CGI::Spaces)
+ && ((*it).toLatin1() == ' ')) {
+ enc.append("&nbsp;");
+ } else if ((conversionFlags & CGI::Tabs)
+ && ((*it).toLatin1() == '\t')) {
+ enc.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
+ } else if ((*it).unicode() > 0x00FF) {
+ enc.append("&#");
+ enc.append(QString::number((*it).unicode()));
+ enc.append(';');
+ } else {
+ enc.append(*it);
+ }
+ ++it;
+ }
+
+ return enc;
+}
+
+// -------------------------------------------------------------------------------------------------
+
diff --git a/shared/cpaster/cgi.h b/shared/cpaster/cgi.h
new file mode 100644
index 0000000000..37b3eb0998
--- /dev/null
+++ b/shared/cpaster/cgi.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef _CGI_H_
+#define _CGI_H_
+#include <QString>
+
+class CGI
+{
+public:
+ static QString encodeURL(const QString &rawText);
+ static QString decodeURL(const QString &urlText);
+
+ enum HTMLconvertFlags {
+ Normal,
+ LineBreaks = 0x0001,
+ Spaces = 0x0002,
+ Tabs = 0x0004
+ };
+
+ static QString encodeHTML(const QString &rawText, int conversionFlags = 0);
+
+private:
+ inline short charToHex(const QChar &ch);
+ inline QChar hexToChar(const QString &hx);
+};
+
+#endif // _CGI_H_
+
diff --git a/shared/cpaster/cpaster.pri b/shared/cpaster/cpaster.pri
new file mode 100644
index 0000000000..146b9d393b
--- /dev/null
+++ b/shared/cpaster/cpaster.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/cgi.h \
+ $$PWD/fetcher.h \
+ $$PWD/poster.h \
+ $$PWD/splitter.h \
+ $$PWD/view.h
+SOURCES += $$PWD/cgi.cpp \
+ $$PWD/fetcher.cpp \
+ $$PWD/poster.cpp \
+ $$PWD/splitter.cpp \
+ $$PWD/view.cpp
+
+FORMS += $$PWD/view.ui
diff --git a/shared/cpaster/fetcher.cpp b/shared/cpaster/fetcher.cpp
new file mode 100644
index 0000000000..19e9690b8b
--- /dev/null
+++ b/shared/cpaster/fetcher.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fetcher.h"
+#include "cgi.h"
+
+#include <QCoreApplication>
+#include <QByteArray>
+#include <QDebug>
+
+Fetcher::Fetcher(const QString &host)
+ : QHttp(host)
+{
+ m_host = host;
+ m_status = 0;
+ m_hadError = false;
+ connect(this, SIGNAL(requestFinished(int,bool)), SLOT(gotRequestFinished(int,bool)));
+ connect(this, SIGNAL(readyRead(const QHttpResponseHeader &)), SLOT(gotReadyRead(const QHttpResponseHeader &)));
+}
+
+int Fetcher::fetch(const QString &url)
+{
+// qDebug("Fetcher::fetch(%s)", qPrintable(url));
+ return QHttp::get(url);
+}
+
+int Fetcher::fetch(int pasteID)
+{
+ return fetch("http://" + m_host + "/?format=raw&id=" + QString::number(pasteID));
+}
+
+void Fetcher::gotRequestFinished(int, bool error)
+{
+ m_hadError = error;
+ QCoreApplication::exit(error ? -1 : 0); // ends event-loop
+}
+
+void Fetcher::gotReadyRead(const QHttpResponseHeader & /* resp */)
+{
+ m_body += QHttp::readAll();
+
+ // Hackish check for No Such Paste, as codepaster doesn't send a HTTP code indicating such, or
+ // sends a redirect to an url indicating failure...
+ if (m_body.contains("<B>No such paste!</B>")) {
+ m_body.clear();
+ m_status = -1;
+ m_hadError = true;
+ }
+}
diff --git a/shared/cpaster/fetcher.h b/shared/cpaster/fetcher.h
new file mode 100644
index 0000000000..989965c271
--- /dev/null
+++ b/shared/cpaster/fetcher.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FETCHER_H
+#define FETCHER_H
+
+#include <QHttp>
+#include <QHttpResponseHeader>
+
+#include <QString>
+
+class Fetcher : public QHttp
+{
+ Q_OBJECT
+public:
+ Fetcher(const QString &host);
+
+ int fetch(const QString &url);
+ int fetch(int pasteID);
+
+ QByteArray &body() { return m_body; }
+
+ int status() { return m_status; }
+ bool hadError() { return m_hadError; }
+
+private slots:
+ void gotRequestFinished(int id, bool error);
+ void gotReadyRead(const QHttpResponseHeader &resp);
+
+private:
+ QString m_host;
+ int m_status;
+ bool m_hadError;
+ QByteArray m_body;
+};
+
+#endif // FETCHER_H
diff --git a/shared/cpaster/poster.cpp b/shared/cpaster/poster.cpp
new file mode 100644
index 0000000000..1b7f152ad2
--- /dev/null
+++ b/shared/cpaster/poster.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "poster.h"
+#include "cgi.h"
+
+#include <QCoreApplication>
+#include <QByteArray>
+#include <QDebug>
+
+Poster::Poster(const QString &host)
+ : QHttp(host)
+{
+ m_status = 0;
+ m_hadError = false;
+ connect(this, SIGNAL(requestFinished(int,bool)), SLOT(gotRequestFinished(int,bool)));
+ connect(this, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), SLOT(gotResponseHeaderReceived(const QHttpResponseHeader &)));
+}
+
+void Poster::post(const QString &description, const QString &comment,
+ const QString &text, const QString &user)
+{
+
+ QByteArray data = "command=processcreate&submit=submit&highlight_type=0&description=";
+ data += CGI::encodeURL(description).toLatin1();
+ data += "&comment=";
+ data += CGI::encodeURL(comment).toLatin1();
+ data += "&code=";
+ data += CGI::encodeURL(text).toLatin1();
+ data += "&poster=";
+ data += CGI::encodeURL(user).toLatin1();
+// qDebug("POST [%s]", data.constData());
+
+ QHttp::post("/", data);
+}
+
+void Poster::gotRequestFinished(int, bool error)
+{
+ m_hadError = error;
+ QCoreApplication::exit(error ? -1 : 0); // ends event-loop
+}
+
+void Poster::gotResponseHeaderReceived(const QHttpResponseHeader &resp)
+{
+ m_url = resp.value("location");
+}
diff --git a/shared/cpaster/poster.h b/shared/cpaster/poster.h
new file mode 100644
index 0000000000..2f405d4207
--- /dev/null
+++ b/shared/cpaster/poster.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef POSTER_H
+#define POSTER_H
+
+#include <QHttp>
+#include <QHttpResponseHeader>
+
+#include <QString>
+
+class Poster : public QHttp
+{
+ Q_OBJECT
+public:
+ Poster(const QString &host);
+
+ void post(const QString &description, const QString &comment,
+ const QString &text, const QString &user);
+
+ QString pastedUrl() { return m_url; }
+ int status() { return m_status; }
+ bool hadError() { return m_hadError; }
+
+private slots:
+ void gotRequestFinished(int id, bool error);
+ void gotResponseHeaderReceived(const QHttpResponseHeader &resp);
+
+private:
+ QString m_url;
+ int m_status;
+ bool m_hadError;
+};
+
+#endif // POSTER_H
diff --git a/shared/cpaster/splitter.cpp b/shared/cpaster/splitter.cpp
new file mode 100644
index 0000000000..15a74b02f1
--- /dev/null
+++ b/shared/cpaster/splitter.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "splitter.h"
+#include <QRegExp>
+
+FileDataList splitDiffToFiles(const QByteArray &data)
+{
+ FileDataList ret;
+ QString strData = data;
+ QString splitExpression;
+
+ if (data.contains("==== ") && data.contains(" ====\n")) {
+ // Perforce diff
+ splitExpression = "==== ([^\\n\\r]+) - ([^\\n\\r]+) ====";
+
+ } else if (data.contains("--- ") && data.contains("\n+++ ")) {
+ // Unified contextual diff
+ splitExpression = "\\-\\-\\- ([^\\n\\r]*)"
+ "\\n\\+\\+\\+ ([^\\n\\r]*)";
+
+ } else if (data.contains("*** ") && data.contains("\n--- ")) {
+ // Copied contextual diff
+ splitExpression = "\\*\\*\\* ([^\\n\\r]*) [0-9\\-]* [0-9:\\.]*[^\\n\\r]*"
+ "\\n\\-\\-\\- ([^\\n\\r]*) [0-9\\-]* [0-9:\\.]*[^\\n\\r]*";
+
+ } else {
+ ret.append(FileData("<not a diff>", data));
+ return ret;
+ }
+
+ int splitIndex = 0, previousSplit = -1;
+ QRegExp splitExpr(splitExpression);
+ QString filename, content;
+ // The algorithm works like this:
+ // On the first match we only get the filename of the first patch part
+ // On the second match (if any) we get the diff content, and the name of the next file patch
+ //
+
+
+ while(-1 != (splitIndex = splitExpr.indexIn(strData,splitIndex))) {
+ if (!filename.isEmpty()) {
+ QString content = strData.mid(previousSplit, splitIndex - previousSplit);
+ ret.append(FileData(filename, content.toLatin1()));
+ }
+
+ // If the first index in not at the beginning of the file, then we know there's content
+ // we're about to skip, which is common in commit diffs, so we get that content and give it
+ // a 'fake' filename.
+ if (previousSplit == -1 && splitIndex > 0 && filename.isEmpty()) {
+ QString content = strData.left(splitIndex);
+ ret.append(FileData("<Header information>", content.toLatin1()));
+ }
+
+ filename = splitExpr.cap(1);
+ previousSplit = splitIndex;
+ ++splitIndex;
+ }
+ // Append the last patch content
+ if (!filename.isEmpty()) {
+ QString content = strData.mid(previousSplit);
+ ret.append(FileData(filename, content.toLatin1()));
+ }
+
+ return ret;
+}
diff --git a/shared/cpaster/splitter.h b/shared/cpaster/splitter.h
new file mode 100644
index 0000000000..0daaf378bf
--- /dev/null
+++ b/shared/cpaster/splitter.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SPLITTER_H
+#define SPLITTER_H
+
+#include <QString>
+#include <QByteArray>
+#include <QList>
+
+struct FileData
+{
+ FileData(const QString &f, const QByteArray &c)
+ { filename = f; content = c; }
+
+ QString filename;
+ QByteArray content;
+};
+
+typedef QList<FileData> FileDataList;
+
+FileDataList splitDiffToFiles(const QByteArray &data);
+
+#endif // SPLITTER_H
diff --git a/shared/cpaster/view.cpp b/shared/cpaster/view.cpp
new file mode 100644
index 0000000000..1db8039ab5
--- /dev/null
+++ b/shared/cpaster/view.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "view.h"
+
+#include <QFontMetrics>
+#include <QPainter>
+#include <QScrollBar>
+#include <QPushButton>
+#include <QSettings>
+
+// -------------------------------------------------------------------------------------------------
+class ColumnIndicatorTextEdit : public QTextEdit
+{
+public:
+ ColumnIndicatorTextEdit(QWidget *parent) : QTextEdit(parent), m_columnIndicator(0)
+ {
+ QFont font;
+ font.setFamily(QString::fromUtf8("Courier New"));
+ //font.setPointSizeF(8.0);
+ setFont(font);
+ setReadOnly(true);
+ QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ sizePolicy.setVerticalStretch(3);
+ setSizePolicy(sizePolicy);
+ int cmx = 0, cmy = 0, cmw = 0, cmh = 0;
+ getContentsMargins(&cmx, &cmy, &cmw, &cmh);
+ m_columnIndicator = QFontMetrics(font).width('W') * 100 + cmx + 1;
+ m_columnIndicatorFont.setFamily(QString::fromUtf8("Times"));
+ m_columnIndicatorFont.setPointSizeF(7.0);
+ }
+
+ int m_columnIndicator;
+ QFont m_columnIndicatorFont;
+
+protected:
+ virtual void paintEvent(QPaintEvent *event);
+};
+
+void ColumnIndicatorTextEdit::paintEvent(QPaintEvent *event)
+{
+ QTextEdit::paintEvent(event);
+
+ QPainter p(viewport());
+ p.setFont(m_columnIndicatorFont);
+ p.setPen(QPen(QColor(0xa0, 0xa0, 0xa0, 0xa0)));
+ p.drawLine(m_columnIndicator, 0, m_columnIndicator, viewport()->height());
+ int yOffset = verticalScrollBar()->value();
+ p.drawText(m_columnIndicator + 1, m_columnIndicatorFont.pointSize() - yOffset, "100");
+}
+
+// -------------------------------------------------------------------------------------------------
+
+
+View::View(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+
+ // Swap out the Patch View widget with a ColumnIndicatorTextEdit, which will indicate column 100
+ delete m_ui.uiPatchView;
+ m_ui.uiPatchView = new ColumnIndicatorTextEdit(m_ui.groupBox);
+ m_ui.vboxLayout1->addWidget(m_ui.uiPatchView);
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setText("Paste");
+ connect(m_ui.uiPatchList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(contentChanged()));
+}
+
+View::~View()
+{
+}
+
+QString View::getUser()
+{
+ const QString username = m_ui.uiUsername->text();
+ if (username.isEmpty() || username == "<Username>")
+ return "Anonymous";
+ return username;
+}
+
+QString View::getDescription()
+{
+ const QString description = m_ui.uiDescription->text();
+ if (description == "<Description>")
+ return QString();
+ return description;
+}
+
+QString View::getComment()
+{
+ const QString comment = m_ui.uiComment->toPlainText();
+ if (comment == "<Comment>")
+ return QString();
+ return comment;
+}
+
+QByteArray View::getContent()
+{
+ QByteArray newContent;
+ for(int i = 0; i < m_ui.uiPatchList->count(); ++i) {
+ QListWidgetItem *item = m_ui.uiPatchList->item(i);
+ if (item->checkState() != Qt::Unchecked)
+ newContent += m_parts.at(i).content;
+ }
+ return newContent;
+}
+
+void View::contentChanged()
+{
+ m_ui.uiPatchView->setPlainText(getContent());
+}
+
+int View::show(const QString &user, const QString &description, const QString &comment,
+ const FileDataList &parts)
+{
+ if (user.isEmpty())
+ m_ui.uiUsername->setText("<Username>");
+ else
+ m_ui.uiUsername->setText(user);
+
+ if (description.isEmpty())
+ m_ui.uiDescription->setText("<Description>");
+ else
+ m_ui.uiDescription->setText(description);
+
+ if (comment.isEmpty())
+ m_ui.uiComment->setPlainText("<Comment>");
+ else
+ m_ui.uiComment->setPlainText(comment);
+
+ QByteArray content;
+ m_parts = parts;
+ m_ui.uiPatchList->clear();
+ foreach(const FileData part, parts) {
+ QListWidgetItem *itm = new QListWidgetItem(part.filename, m_ui.uiPatchList);
+ itm->setCheckState(Qt::Checked);
+ itm->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ content += part.content;
+ }
+ m_ui.uiPatchView->setPlainText(content);
+
+ m_ui.uiDescription->setFocus();
+ m_ui.uiDescription->selectAll();
+
+ // (Re)store dialog size
+ QSettings settings("Trolltech", "cpaster");
+ int h = settings.value("/gui/height", height()).toInt();
+ int w = settings.value("/gui/width",
+ ((ColumnIndicatorTextEdit*)m_ui.uiPatchView)->m_columnIndicator + 50)
+ .toInt();
+ resize(w, h);
+ int ret = QDialog::exec();
+ settings.setValue("/gui/height", height());
+ settings.setValue("/gui/width", width());
+
+ return ret;
+}
diff --git a/shared/cpaster/view.h b/shared/cpaster/view.h
new file mode 100644
index 0000000000..5ba72fd938
--- /dev/null
+++ b/shared/cpaster/view.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VIEW_H
+#define VIEW_H
+
+#include <QDialog>
+#include <QByteArray>
+
+#include "splitter.h"
+#include "ui_view.h"
+
+class View : public QDialog
+{
+ Q_OBJECT
+public:
+ View(QWidget *parent);
+ ~View();
+
+ int show(const QString &user, const QString &description, const QString &comment,
+ const FileDataList &parts);
+
+ QString getUser();
+ QString getDescription();
+ QString getComment();
+ QByteArray getContent();
+
+private slots:
+ void contentChanged();
+
+private:
+ Ui::ViewDialog m_ui;
+ FileDataList m_parts;
+};
+
+#endif // VIEW_H
+
diff --git a/shared/cpaster/view.ui b/shared/cpaster/view.ui
new file mode 100644
index 0000000000..b8ede8d1d4
--- /dev/null
+++ b/shared/cpaster/view.ui
@@ -0,0 +1,208 @@
+<ui version="4.0" >
+ <class>ViewDialog</class>
+ <widget class="QDialog" name="ViewDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Send to Codepaster</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>uiUsername</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="uiUsername" >
+ <property name="text" >
+ <string>&lt;Username></string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>uiDescription</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="uiDescription" >
+ <property name="text" >
+ <string>&lt;Description></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="uiComment" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="tabChangesFocus" >
+ <bool>true</bool>
+ </property>
+ <property name="html" >
+ <string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&amp;lt;Comment&amp;gt;&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Parts to send to codepaster</string>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>2</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="uiPatchList" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="uniformItemSizes" >
+ <bool>true</bool>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Patch 1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Patch 2</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="uiPatchView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>3</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font" >
+ <font>
+ <family>Courier New</family>
+ </font>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>uiUsername</tabstop>
+ <tabstop>uiDescription</tabstop>
+ <tabstop>uiComment</tabstop>
+ <tabstop>buttonBox</tabstop>
+ <tabstop>uiPatchList</tabstop>
+ <tabstop>uiPatchView</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ViewDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ViewDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/shared/cplusplus/AST.cpp b/shared/cplusplus/AST.cpp
new file mode 100644
index 0000000000..ca3c1aab65
--- /dev/null
+++ b/shared/cplusplus/AST.cpp
@@ -0,0 +1,2458 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "AST.h"
+#include "ASTVisitor.h"
+#include "MemoryPool.h"
+
+#include <cassert>
+#include <cstddef>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+AST::AST()
+{ }
+
+AST::~AST()
+{ assert(0); }
+
+AccessDeclarationAST *AST::asAccessDeclaration()
+{ return dynamic_cast<AccessDeclarationAST *>(this); }
+
+ArrayAccessAST *AST::asArrayAccess()
+{ return dynamic_cast<ArrayAccessAST *>(this); }
+
+ArrayDeclaratorAST *AST::asArrayDeclarator()
+{ return dynamic_cast<ArrayDeclaratorAST *>(this); }
+
+ArrayInitializerAST *AST::asArrayInitializer()
+{ return dynamic_cast<ArrayInitializerAST *>(this); }
+
+AsmDefinitionAST *AST::asAsmDefinition()
+{ return dynamic_cast<AsmDefinitionAST *>(this); }
+
+AttributeAST *AST::asAttribute()
+{ return dynamic_cast<AttributeAST *>(this); }
+
+AttributeSpecifierAST *AST::asAttributeSpecifier()
+{ return dynamic_cast<AttributeSpecifierAST *>(this); }
+
+BaseSpecifierAST *AST::asBaseSpecifier()
+{ return dynamic_cast<BaseSpecifierAST *>(this); }
+
+QtMethodAST *AST::asQtMethod()
+{ return dynamic_cast<QtMethodAST *>(this); }
+
+BinaryExpressionAST *AST::asBinaryExpression()
+{ return dynamic_cast<BinaryExpressionAST *>(this); }
+
+BoolLiteralAST *AST::asBoolLiteral()
+{ return dynamic_cast<BoolLiteralAST *>(this); }
+
+BreakStatementAST *AST::asBreakStatement()
+{ return dynamic_cast<BreakStatementAST *>(this); }
+
+CallAST *AST::asCall()
+{ return dynamic_cast<CallAST *>(this); }
+
+CaseStatementAST *AST::asCaseStatement()
+{ return dynamic_cast<CaseStatementAST *>(this); }
+
+CastExpressionAST *AST::asCastExpression()
+{ return dynamic_cast<CastExpressionAST *>(this); }
+
+CatchClauseAST *AST::asCatchClause()
+{ return dynamic_cast<CatchClauseAST *>(this); }
+
+ClassSpecifierAST *AST::asClassSpecifier()
+{ return dynamic_cast<ClassSpecifierAST *>(this); }
+
+CompoundStatementAST *AST::asCompoundStatement()
+{ return dynamic_cast<CompoundStatementAST *>(this); }
+
+ConditionAST *AST::asCondition()
+{ return dynamic_cast<ConditionAST *>(this); }
+
+ConditionalExpressionAST *AST::asConditionalExpression()
+{ return dynamic_cast<ConditionalExpressionAST *>(this); }
+
+ContinueStatementAST *AST::asContinueStatement()
+{ return dynamic_cast<ContinueStatementAST *>(this); }
+
+ConversionFunctionIdAST *AST::asConversionFunctionId()
+{ return dynamic_cast<ConversionFunctionIdAST *>(this); }
+
+CoreDeclaratorAST *AST::asCoreDeclarator()
+{ return dynamic_cast<CoreDeclaratorAST *>(this); }
+
+CppCastExpressionAST *AST::asCppCastExpression()
+{ return dynamic_cast<CppCastExpressionAST *>(this); }
+
+CtorInitializerAST *AST::asCtorInitializer()
+{ return dynamic_cast<CtorInitializerAST *>(this); }
+
+DeclarationAST *AST::asDeclaration()
+{ return dynamic_cast<DeclarationAST *>(this); }
+
+DeclarationStatementAST *AST::asDeclarationStatement()
+{ return dynamic_cast<DeclarationStatementAST *>(this); }
+
+DeclaratorAST *AST::asDeclarator()
+{ return dynamic_cast<DeclaratorAST *>(this); }
+
+DeclaratorIdAST *AST::asDeclaratorId()
+{ return dynamic_cast<DeclaratorIdAST *>(this); }
+
+DeclaratorListAST *AST::asDeclaratorList()
+{ return dynamic_cast<DeclaratorListAST *>(this); }
+
+DeleteExpressionAST *AST::asDeleteExpression()
+{ return dynamic_cast<DeleteExpressionAST *>(this); }
+
+DestructorNameAST *AST::asDestructorName()
+{ return dynamic_cast<DestructorNameAST *>(this); }
+
+DoStatementAST *AST::asDoStatement()
+{ return dynamic_cast<DoStatementAST *>(this); }
+
+ElaboratedTypeSpecifierAST *AST::asElaboratedTypeSpecifier()
+{ return dynamic_cast<ElaboratedTypeSpecifierAST *>(this); }
+
+EmptyDeclarationAST *AST::asEmptyDeclaration()
+{ return dynamic_cast<EmptyDeclarationAST *>(this); }
+
+EnumSpecifierAST *AST::asEnumSpecifier()
+{ return dynamic_cast<EnumSpecifierAST *>(this); }
+
+EnumeratorAST *AST::asEnumerator()
+{ return dynamic_cast<EnumeratorAST *>(this); }
+
+ExceptionDeclarationAST *AST::asExceptionDeclaration()
+{ return dynamic_cast<ExceptionDeclarationAST *>(this); }
+
+ExceptionSpecificationAST *AST::asExceptionSpecification()
+{ return dynamic_cast<ExceptionSpecificationAST *>(this); }
+
+ExpressionAST *AST::asExpression()
+{ return dynamic_cast<ExpressionAST *>(this); }
+
+ExpressionListAST *AST::asExpressionList()
+{ return dynamic_cast<ExpressionListAST *>(this); }
+
+ExpressionOrDeclarationStatementAST *AST::asExpressionOrDeclarationStatement()
+{ return dynamic_cast<ExpressionOrDeclarationStatementAST *>(this); }
+
+ExpressionStatementAST *AST::asExpressionStatement()
+{ return dynamic_cast<ExpressionStatementAST *>(this); }
+
+ForStatementAST *AST::asForStatement()
+{ return dynamic_cast<ForStatementAST *>(this); }
+
+FunctionDeclaratorAST *AST::asFunctionDeclarator()
+{ return dynamic_cast<FunctionDeclaratorAST *>(this); }
+
+FunctionDefinitionAST *AST::asFunctionDefinition()
+{ return dynamic_cast<FunctionDefinitionAST *>(this); }
+
+GotoStatementAST *AST::asGotoStatement()
+{ return dynamic_cast<GotoStatementAST *>(this); }
+
+IfStatementAST *AST::asIfStatement()
+{ return dynamic_cast<IfStatementAST *>(this); }
+
+LabeledStatementAST *AST::asLabeledStatement()
+{ return dynamic_cast<LabeledStatementAST *>(this); }
+
+LinkageBodyAST *AST::asLinkageBody()
+{ return dynamic_cast<LinkageBodyAST *>(this); }
+
+LinkageSpecificationAST *AST::asLinkageSpecification()
+{ return dynamic_cast<LinkageSpecificationAST *>(this); }
+
+MemInitializerAST *AST::asMemInitializer()
+{ return dynamic_cast<MemInitializerAST *>(this); }
+
+MemberAccessAST *AST::asMemberAccess()
+{ return dynamic_cast<MemberAccessAST *>(this); }
+
+NameAST *AST::asName()
+{ return dynamic_cast<NameAST *>(this); }
+
+NamedTypeSpecifierAST *AST::asNamedTypeSpecifier()
+{ return dynamic_cast<NamedTypeSpecifierAST *>(this); }
+
+NamespaceAST *AST::asNamespace()
+{ return dynamic_cast<NamespaceAST *>(this); }
+
+NamespaceAliasDefinitionAST *AST::asNamespaceAliasDefinition()
+{ return dynamic_cast<NamespaceAliasDefinitionAST *>(this); }
+
+NestedDeclaratorAST *AST::asNestedDeclarator()
+{ return dynamic_cast<NestedDeclaratorAST *>(this); }
+
+NestedExpressionAST *AST::asNestedExpression()
+{ return dynamic_cast<NestedExpressionAST *>(this); }
+
+NestedNameSpecifierAST *AST::asNestedNameSpecifier()
+{ return dynamic_cast<NestedNameSpecifierAST *>(this); }
+
+NewDeclaratorAST *AST::asNewDeclarator()
+{ return dynamic_cast<NewDeclaratorAST *>(this); }
+
+NewExpressionAST *AST::asNewExpression()
+{ return dynamic_cast<NewExpressionAST *>(this); }
+
+NewInitializerAST *AST::asNewInitializer()
+{ return dynamic_cast<NewInitializerAST *>(this); }
+
+NewTypeIdAST *AST::asNewTypeId()
+{ return dynamic_cast<NewTypeIdAST *>(this); }
+
+NumericLiteralAST *AST::asNumericLiteral()
+{ return dynamic_cast<NumericLiteralAST *>(this); }
+
+OperatorAST *AST::asOperator()
+{ return dynamic_cast<OperatorAST *>(this); }
+
+OperatorFunctionIdAST *AST::asOperatorFunctionId()
+{ return dynamic_cast<OperatorFunctionIdAST *>(this); }
+
+ParameterDeclarationAST *AST::asParameterDeclaration()
+{ return dynamic_cast<ParameterDeclarationAST *>(this); }
+
+ParameterDeclarationClauseAST *AST::asParameterDeclarationClause()
+{ return dynamic_cast<ParameterDeclarationClauseAST *>(this); }
+
+PointerAST *AST::asPointer()
+{ return dynamic_cast<PointerAST *>(this); }
+
+PointerToMemberAST *AST::asPointerToMember()
+{ return dynamic_cast<PointerToMemberAST *>(this); }
+
+PostIncrDecrAST *AST::asPostIncrDecr()
+{ return dynamic_cast<PostIncrDecrAST *>(this); }
+
+PostfixAST *AST::asPostfix()
+{ return dynamic_cast<PostfixAST *>(this); }
+
+PostfixDeclaratorAST *AST::asPostfixDeclarator()
+{ return dynamic_cast<PostfixDeclaratorAST *>(this); }
+
+PostfixExpressionAST *AST::asPostfixExpression()
+{ return dynamic_cast<PostfixExpressionAST *>(this); }
+
+PtrOperatorAST *AST::asPtrOperator()
+{ return dynamic_cast<PtrOperatorAST *>(this); }
+
+QualifiedNameAST *AST::asQualifiedName()
+{ return dynamic_cast<QualifiedNameAST *>(this); }
+
+ReferenceAST *AST::asReference()
+{ return dynamic_cast<ReferenceAST *>(this); }
+
+ReturnStatementAST *AST::asReturnStatement()
+{ return dynamic_cast<ReturnStatementAST *>(this); }
+
+SimpleDeclarationAST *AST::asSimpleDeclaration()
+{ return dynamic_cast<SimpleDeclarationAST *>(this); }
+
+SimpleNameAST *AST::asSimpleName()
+{ return dynamic_cast<SimpleNameAST *>(this); }
+
+SimpleSpecifierAST *AST::asSimpleSpecifier()
+{ return dynamic_cast<SimpleSpecifierAST *>(this); }
+
+SizeofExpressionAST *AST::asSizeofExpression()
+{ return dynamic_cast<SizeofExpressionAST *>(this); }
+
+SpecifierAST *AST::asSpecifier()
+{ return dynamic_cast<SpecifierAST *>(this); }
+
+StatementAST *AST::asStatement()
+{ return dynamic_cast<StatementAST *>(this); }
+
+StringLiteralAST *AST::asStringLiteral()
+{ return dynamic_cast<StringLiteralAST *>(this); }
+
+SwitchStatementAST *AST::asSwitchStatement()
+{ return dynamic_cast<SwitchStatementAST *>(this); }
+
+TemplateArgumentListAST *AST::asTemplateArgumentList()
+{ return dynamic_cast<TemplateArgumentListAST *>(this); }
+
+TemplateDeclarationAST *AST::asTemplateDeclaration()
+{ return dynamic_cast<TemplateDeclarationAST *>(this); }
+
+TemplateIdAST *AST::asTemplateId()
+{ return dynamic_cast<TemplateIdAST *>(this); }
+
+TemplateTypeParameterAST *AST::asTemplateTypeParameter()
+{ return dynamic_cast<TemplateTypeParameterAST *>(this); }
+
+ThisExpressionAST *AST::asThisExpression()
+{ return dynamic_cast<ThisExpressionAST *>(this); }
+
+ThrowExpressionAST *AST::asThrowExpression()
+{ return dynamic_cast<ThrowExpressionAST *>(this); }
+
+TranslationUnitAST *AST::asTranslationUnit()
+{ return dynamic_cast<TranslationUnitAST *>(this); }
+
+TryBlockStatementAST *AST::asTryBlockStatement()
+{ return dynamic_cast<TryBlockStatementAST *>(this); }
+
+TypeConstructorCallAST *AST::asTypeConstructorCall()
+{ return dynamic_cast<TypeConstructorCallAST *>(this); }
+
+TypeIdAST *AST::asTypeId()
+{ return dynamic_cast<TypeIdAST *>(this); }
+
+TypeidExpressionAST *AST::asTypeidExpression()
+{ return dynamic_cast<TypeidExpressionAST *>(this); }
+
+TypenameCallExpressionAST *AST::asTypenameCallExpression()
+{ return dynamic_cast<TypenameCallExpressionAST *>(this); }
+
+TypenameTypeParameterAST *AST::asTypenameTypeParameter()
+{ return dynamic_cast<TypenameTypeParameterAST *>(this); }
+
+TypeofSpecifierAST *AST::asTypeofSpecifier()
+{ return dynamic_cast<TypeofSpecifierAST *>(this); }
+
+UnaryExpressionAST *AST::asUnaryExpression()
+{ return dynamic_cast<UnaryExpressionAST *>(this); }
+
+UsingAST *AST::asUsing()
+{ return dynamic_cast<UsingAST *>(this); }
+
+UsingDirectiveAST *AST::asUsingDirective()
+{ return dynamic_cast<UsingDirectiveAST *>(this); }
+
+WhileStatementAST *AST::asWhileStatement()
+{ return dynamic_cast<WhileStatementAST *>(this); }
+
+void *AST::operator new(size_t size, MemoryPool *pool)
+{ return pool->allocate(size); }
+
+void AST::operator delete(void *)
+{ }
+
+void AST::operator delete(void *, MemoryPool *)
+{ }
+
+void AST::accept(ASTVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ accept0(visitor);
+ visitor->postVisit(this);
+}
+
+unsigned AttributeSpecifierAST::firstToken() const
+{
+ return attribute_token;
+}
+
+unsigned AttributeSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (second_rparen_token)
+ return second_rparen_token + 1;
+ else if (first_rparen_token)
+ return first_rparen_token + 1;
+ else if (attributes)
+ return attributes->lastToken();
+ return second_lparen_token + 1;
+}
+
+void AttributeSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (AttributeAST *attr = attributes; attr; attr = attr->next)
+ accept(attr, visitor);
+ }
+}
+
+unsigned AttributeAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned AttributeAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression_list)
+ return expression_list->lastToken();
+ else if (tag_token)
+ return tag_token + 1;
+ return identifier_token + 1;
+}
+
+void AttributeAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *it = expression_list; it; it = it->next)
+ accept(it->expression, visitor);
+ }
+}
+
+void AccessDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned AccessDeclarationAST::firstToken() const
+{
+ return access_specifier_token;
+}
+
+unsigned AccessDeclarationAST::lastToken() const
+{
+ assert(0 && "review me");
+ return colon_token + 1;
+}
+
+void ArrayAccessAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ArrayAccessAST::firstToken() const
+{
+ return lbracket_token;
+}
+
+unsigned ArrayAccessAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbracket_token + 1;
+}
+
+void ArrayDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(this->expression, visitor);
+ }
+}
+
+unsigned ArrayDeclaratorAST::firstToken() const
+{
+ return lbracket_token;
+}
+
+unsigned ArrayDeclaratorAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbracket_token + 1;
+}
+
+void ArrayInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *expr = expression_list;expr;
+ expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned ArrayInitializerAST::firstToken() const
+{
+ return lbrace_token;
+}
+
+unsigned ArrayInitializerAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbrace_token + 1;
+}
+
+void AsmDefinitionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = cv_qualifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ }
+}
+
+unsigned AsmDefinitionAST::firstToken() const
+{
+ return asm_token;
+}
+
+unsigned AsmDefinitionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void BaseSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned BaseSpecifierAST::firstToken() const
+{
+ if (token_virtual && token_access_specifier)
+ return std::min(token_virtual, token_access_specifier);
+ return name->firstToken();
+}
+
+unsigned BaseSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ return name->lastToken();
+}
+
+unsigned QtMethodAST::firstToken() const
+{ return method_token; }
+
+unsigned QtMethodAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token;
+}
+
+void QtMethodAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarator, visitor);
+ }
+}
+
+void BinaryExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left_expression, visitor);
+ accept(right_expression, visitor);
+ }
+}
+
+unsigned BinaryExpressionAST::firstToken() const
+{
+ return left_expression->firstToken();
+}
+
+unsigned BinaryExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return right_expression->lastToken();
+}
+
+void BoolLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned BoolLiteralAST::firstToken() const
+{
+ return token;
+}
+
+unsigned BoolLiteralAST::lastToken() const
+{
+ assert(0 && "review me");
+ return token + 1;
+}
+
+void BreakStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned BreakStatementAST::firstToken() const
+{
+ return break_token;
+}
+
+unsigned BreakStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void CallAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *expr = expression_list;
+ expr; expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned CallAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned CallAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void CaseStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned CaseStatementAST::firstToken() const
+{
+ return case_token;
+}
+
+unsigned CaseStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (statement)
+ return statement->lastToken();
+ return colon_token + 1;
+}
+
+void CastExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned CastExpressionAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned CastExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return expression->lastToken();
+}
+
+void CatchClauseAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(exception_declaration, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned CatchClauseAST::firstToken() const
+{
+ return catch_token;
+}
+
+unsigned CatchClauseAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (statement)
+ return statement->lastToken();
+ return rparen_token + 1;
+}
+
+void ClassSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = attributes; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(name, visitor);
+ for (BaseSpecifierAST *spec = base_clause; spec; spec = spec->next)
+ accept(spec, visitor);
+ for (DeclarationAST *decl = member_specifiers; decl; decl = decl->next)
+ accept(decl, visitor);
+ }
+}
+
+unsigned ClassSpecifierAST::firstToken() const
+{
+ return classkey_token;
+}
+
+unsigned ClassSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbrace_token + 1;
+}
+
+void CompoundStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (StatementAST *stmt = statements; stmt; stmt = stmt->next)
+ accept(stmt, visitor);
+ }
+}
+
+unsigned CompoundStatementAST::firstToken() const
+{
+ return lbrace_token;
+}
+
+unsigned CompoundStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbrace_token + 1;
+}
+
+void ConditionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ }
+}
+
+unsigned ConditionAST::firstToken() const
+{
+ if (type_specifier)
+ return type_specifier->firstToken();
+ return declarator->firstToken();
+}
+
+unsigned ConditionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return declarator->lastToken();
+}
+
+void ConditionalExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(left_expression, visitor);
+ accept(right_expression, visitor);
+ }
+}
+
+unsigned ConditionalExpressionAST::firstToken() const
+{
+ return condition->firstToken();
+}
+
+unsigned ConditionalExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (right_expression)
+ return right_expression->lastToken();
+ return colon_token + 1;
+}
+
+void ContinueStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ContinueStatementAST::firstToken() const
+{
+ return continue_token;
+}
+
+unsigned ContinueStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void ConversionFunctionIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op;
+ ptr_op = static_cast<PtrOperatorAST *>(ptr_op->next))
+ accept(ptr_op, visitor);
+ }
+}
+
+unsigned ConversionFunctionIdAST::firstToken() const
+{
+ return operator_token;
+}
+
+unsigned ConversionFunctionIdAST::lastToken() const
+{
+ assert(0 && "review me");
+#if 0 // ### implement me
+ for (DeclaratorAST *ptr_op = ptr_operators; ptr_op;
+ ptr_op = ptr_op->next) {
+ if (! ptr_op->next)
+ return ptr_op->lastToken();
+ }
+#endif
+ if (type_specifier)
+ return type_specifier->lastToken();
+ return operator_token + 1;
+}
+
+void CppCastExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(type_id, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned CppCastExpressionAST::firstToken() const
+{
+ return cast_token;
+}
+
+unsigned CppCastExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void CtorInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (MemInitializerAST *mem_init = member_initializers;
+ mem_init; mem_init = mem_init->next)
+ accept(mem_init, visitor);
+ }
+}
+
+unsigned CtorInitializerAST::firstToken() const
+{
+ return colon_token;
+}
+
+unsigned CtorInitializerAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (MemInitializerAST *it = member_initializers; it;
+ it = it->next)
+ if (! it->next)
+ return it->lastToken();
+ return colon_token + 1;
+}
+
+void DeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op; ptr_op = ptr_op->next) {
+ accept(ptr_op, visitor);
+ }
+ accept(core_declarator, visitor);
+ for (PostfixDeclaratorAST *fx = postfix_declarators; fx; fx = fx->next) {
+ accept(fx, visitor);
+ }
+ accept(attributes, visitor);
+ accept(initializer, visitor);
+ }
+}
+
+unsigned DeclaratorAST::firstToken() const
+{
+ if (ptr_operators)
+ return ptr_operators->firstToken();
+ else if (core_declarator)
+ return core_declarator->firstToken();
+ else if (postfix_declarators)
+ return postfix_declarators->firstToken();
+ return 0;
+}
+
+unsigned DeclaratorAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (PostfixDeclaratorAST *fx = postfix_declarators; fx; fx = fx->next) {
+ if (! fx->next)
+ return fx->lastToken();
+ }
+ if (core_declarator)
+ return core_declarator->lastToken();
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op; ptr_op = ptr_op->next) {
+ if (! ptr_op->next)
+ return ptr_op->lastToken();
+ }
+ return 0;
+}
+
+void DeclarationStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+}
+
+unsigned DeclarationStatementAST::firstToken() const
+{
+ return declaration->firstToken();
+}
+
+unsigned DeclarationStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return declaration->lastToken();
+}
+
+void DeclaratorIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned DeclaratorIdAST::firstToken() const
+{
+ return name->firstToken();
+}
+
+unsigned DeclaratorIdAST::lastToken() const
+{
+ assert(0 && "review me");
+ return name->lastToken();
+}
+
+void DeclaratorListAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclaratorListAST *it = this; it; it = it->next)
+ accept(it->declarator, visitor);
+ }
+}
+
+unsigned DeclaratorListAST::firstToken() const
+{
+ return declarator->firstToken();
+}
+
+unsigned DeclaratorListAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (const DeclaratorListAST *it = this; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+void DeleteExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned DeleteExpressionAST::firstToken() const
+{
+ if (scope_token)
+ return scope_token;
+ return delete_token;
+}
+
+unsigned DeleteExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ else if (rbracket_token)
+ return rbracket_token + 1;
+ return delete_token + 1;
+}
+
+void DestructorNameAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned DestructorNameAST::firstToken() const
+{
+ return tilde_token;
+}
+
+unsigned DestructorNameAST::lastToken() const
+{
+ assert(0 && "review me");
+ return identifier_token + 1;
+}
+
+void DoStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned DoStatementAST::firstToken() const
+{
+ return do_token;
+}
+
+unsigned DoStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void ElaboratedTypeSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned ElaboratedTypeSpecifierAST::firstToken() const
+{
+ return classkey_token;
+}
+
+unsigned ElaboratedTypeSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (name)
+ return name->lastToken();
+ return classkey_token + 1;
+}
+
+void EmptyDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned EmptyDeclarationAST::firstToken() const
+{
+ return semicolon_token;
+}
+
+unsigned EmptyDeclarationAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void EnumSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ for (EnumeratorAST *enumerator = enumerators; enumerator;
+ enumerator = enumerator->next)
+ accept(enumerator, visitor);
+ }
+}
+
+unsigned EnumSpecifierAST::firstToken() const
+{
+ return enum_token;
+}
+
+unsigned EnumSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbrace_token + 1;
+}
+
+void EnumeratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned EnumeratorAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned EnumeratorAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ if (equal_token)
+ return equal_token + 1;
+ return identifier_token + 1;
+}
+
+void ExceptionDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ }
+}
+
+unsigned ExceptionDeclarationAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned ExceptionDeclarationAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (dot_dot_dot_token)
+ return dot_dot_dot_token + 1;
+ else if (declarator)
+ return declarator->lastToken();
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return type_specifier->lastToken();
+ }
+ return 0;
+}
+
+void ExceptionSpecificationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *type_id = type_ids; type_id;
+ type_id = type_id->next)
+ accept(type_id->expression, visitor);
+ }
+}
+
+unsigned ExceptionSpecificationAST::firstToken() const
+{
+ return throw_token;
+}
+
+unsigned ExceptionSpecificationAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void ExpressionListAST::accept0(ASTVisitor *)
+{ assert(0); }
+
+unsigned ExpressionListAST::firstToken() const
+{
+ return expression->firstToken();
+}
+
+unsigned ExpressionListAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (const ExpressionListAST *it = this; it; it = it->next) {
+ if (! it->next)
+ return it->expression->lastToken();
+ }
+ return 0;
+}
+
+void ExpressionOrDeclarationStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned ExpressionOrDeclarationStatementAST::firstToken() const
+{
+ return expression->firstToken();
+}
+
+unsigned ExpressionOrDeclarationStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return expression->lastToken();
+}
+
+void ExpressionStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ExpressionStatementAST::firstToken() const
+{
+ if (expression)
+ return expression->firstToken();
+ return semicolon_token;
+}
+
+unsigned ExpressionStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return expression->lastToken();
+}
+
+void ForStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initializer, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned ForStatementAST::firstToken() const
+{
+ return for_token;
+}
+
+unsigned ForStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (statement)
+ return statement->lastToken();
+ return rparen_token + 1;
+}
+
+void FunctionDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned FunctionDeclaratorAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned FunctionDeclaratorAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (exception_specification)
+ return exception_specification->lastToken();
+ else if (cv_qualifier_seq) {
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ }
+ return rparen_token + 1;
+}
+
+void FunctionDefinitionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = decl_specifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ accept(ctor_initializer, visitor);
+ accept(function_body, visitor);
+ }
+}
+
+unsigned FunctionDefinitionAST::firstToken() const
+{
+ if (decl_specifier_seq)
+ return decl_specifier_seq->firstToken();
+ else if (declarator)
+ return declarator->firstToken();
+ else if (ctor_initializer)
+ return ctor_initializer->firstToken();
+ return function_body->firstToken();
+}
+
+unsigned FunctionDefinitionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (function_body)
+ return function_body->lastToken();
+ else if (ctor_initializer)
+ return ctor_initializer->lastToken();
+ return declarator->lastToken();
+}
+
+void GotoStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned GotoStatementAST::firstToken() const
+{
+ return goto_token;
+}
+
+unsigned GotoStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void IfStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(statement, visitor);
+ accept(else_statement, visitor);
+ }
+}
+
+unsigned IfStatementAST::firstToken() const
+{
+ return if_token;
+}
+
+unsigned IfStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (else_statement)
+ return else_statement->lastToken();
+ else if (else_token)
+ return else_token + 1;
+ else if (statement)
+ return statement->lastToken();
+ return rparen_token + 1;
+}
+
+void LabeledStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+}
+
+unsigned LabeledStatementAST::firstToken() const
+{
+ return label_token;
+}
+
+unsigned LabeledStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (statement)
+ return statement->lastToken();
+ return colon_token + 1;
+}
+
+void LinkageBodyAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *decl = declarations; decl;
+ decl = decl->next)
+ accept(decl, visitor);
+ }
+}
+
+unsigned LinkageBodyAST::firstToken() const
+{
+ return lbrace_token;
+}
+
+unsigned LinkageBodyAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rbrace_token + 1;
+}
+
+void LinkageSpecificationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+}
+
+unsigned LinkageSpecificationAST::firstToken() const
+{
+ return extern_token;
+}
+
+unsigned LinkageSpecificationAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (declaration)
+ return declaration->lastToken();
+ else if (extern_type)
+ return extern_type + 1;
+ return extern_token + 1;
+}
+
+void MemInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned MemInitializerAST::firstToken() const
+{
+ return name->firstToken();
+}
+
+unsigned MemInitializerAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void MemberAccessAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(member_name, visitor);
+ }
+}
+
+unsigned MemberAccessAST::firstToken() const
+{
+ return access_token;
+}
+
+unsigned MemberAccessAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (member_name)
+ return member_name->lastToken();
+ return access_token + 1;
+}
+
+void NamedTypeSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned NamedTypeSpecifierAST::firstToken() const
+{
+ return name->firstToken();
+}
+
+unsigned NamedTypeSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ return name->lastToken();
+}
+
+void NamespaceAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *attr = attributes; attr; attr = attr->next) {
+ accept(attr, visitor);
+ }
+ accept(linkage_body, visitor);
+ }
+}
+
+unsigned NamespaceAST::firstToken() const
+{
+ return namespace_token;
+}
+
+unsigned NamespaceAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (linkage_body)
+ return linkage_body->lastToken();
+ if (identifier_token)
+ return identifier_token + 1;
+ return namespace_token + 1;
+}
+
+void NamespaceAliasDefinitionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned NamespaceAliasDefinitionAST::firstToken() const
+{
+ return namespace_token;
+}
+
+unsigned NamespaceAliasDefinitionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void NestedDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarator, visitor);
+ }
+}
+
+unsigned NestedDeclaratorAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned NestedDeclaratorAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void NestedExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned NestedExpressionAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned NestedExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void NestedNameSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(class_or_namespace_name, visitor);
+ accept(next, visitor); // ### I'm not 100% sure about this.
+ }
+}
+
+unsigned NestedNameSpecifierAST::firstToken() const
+{
+ return class_or_namespace_name->firstToken();
+}
+
+unsigned NestedNameSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ return scope_token + 1;
+}
+
+void NewDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op;
+ ptr_op = static_cast<PtrOperatorAST *>(ptr_op->next))
+ accept(ptr_op, visitor);
+ // ### TODO accept the brackets
+ }
+}
+
+unsigned NewDeclaratorAST::firstToken() const
+{
+ return ptr_operators->firstToken();
+}
+
+unsigned NewDeclaratorAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (declarator)
+ return declarator->lastToken();
+ assert(0); // ### implement me
+ return 0;
+}
+
+void NewExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(type_id, visitor);
+ accept(new_type_id, visitor);
+ accept(new_initializer, visitor);
+ }
+}
+
+unsigned NewExpressionAST::firstToken() const
+{
+ if (scope_token)
+ return scope_token;
+ return new_token;
+}
+
+unsigned NewExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (new_initializer)
+ return new_initializer->lastToken();
+ else if (new_type_id)
+ return new_type_id->lastToken();
+ else if (type_id)
+ return type_id->lastToken();
+ else if (expression)
+ return expression->lastToken();
+ return new_token + 1;
+}
+
+void NewInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned NewInitializerAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned NewInitializerAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void NewTypeIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(new_initializer, visitor);
+ accept(new_declarator, visitor);
+ }
+}
+
+unsigned NewTypeIdAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned NewTypeIdAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (new_declarator)
+ return new_declarator->lastToken();
+ else if (new_initializer)
+ return new_initializer->lastToken();
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+void NumericLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned NumericLiteralAST::firstToken() const
+{
+ return token;
+}
+
+unsigned NumericLiteralAST::lastToken() const
+{
+ assert(0 && "review me");
+ return token + 1;
+}
+
+void OperatorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned OperatorAST::firstToken() const
+{
+ return op_token;
+}
+
+unsigned OperatorAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (close_token)
+ return close_token + 1;
+ return op_token + 1;
+}
+
+void OperatorFunctionIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(op, visitor);
+ }
+}
+
+unsigned OperatorFunctionIdAST::firstToken() const
+{
+ return operator_token;
+}
+
+unsigned OperatorFunctionIdAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (op)
+ return op->lastToken();
+ return operator_token + 1;
+}
+
+void ParameterDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned ParameterDeclarationAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned ParameterDeclarationAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (declarator)
+ return declarator->lastToken();
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+void ParameterDeclarationClauseAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *param = parameter_declarations; param;
+ param = param->next)
+ accept(param, visitor);
+ }
+}
+
+unsigned ParameterDeclarationClauseAST::firstToken() const
+{
+ if (parameter_declarations)
+ return parameter_declarations->firstToken();
+ return dot_dot_dot_token;
+}
+
+unsigned ParameterDeclarationClauseAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (dot_dot_dot_token)
+ return dot_dot_dot_token + 1;
+ return parameter_declarations->lastToken();
+}
+
+void PointerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = cv_qualifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ }
+}
+
+unsigned PointerAST::firstToken() const
+{
+ return star_token;
+}
+
+unsigned PointerAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return star_token + 1;
+}
+
+void PointerToMemberAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(nested_name_specifier, visitor);
+ for (SpecifierAST *spec = cv_qualifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ }
+}
+
+unsigned PointerToMemberAST::firstToken() const
+{
+ if (global_scope_token)
+ return global_scope_token;
+ else if (nested_name_specifier)
+ return nested_name_specifier->firstToken();
+ return star_token;
+}
+
+unsigned PointerToMemberAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return star_token + 1;
+}
+
+void PostIncrDecrAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned PostIncrDecrAST::firstToken() const
+{
+ return incr_decr_token;
+}
+
+unsigned PostIncrDecrAST::lastToken() const
+{
+ assert(0 && "review me");
+ return incr_decr_token + 1;
+}
+
+void PostfixExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base_expression, visitor);
+ for (PostfixAST *fx = postfix_expressions; fx; fx = fx->next)
+ accept(fx, visitor);
+ }
+}
+
+unsigned PostfixExpressionAST::firstToken() const
+{
+ return base_expression->firstToken();
+}
+
+unsigned PostfixExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (PostfixAST *it = postfix_expressions; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return base_expression->lastToken();
+}
+
+void QualifiedNameAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(nested_name_specifier, visitor);
+ accept(unqualified_name, visitor);
+ }
+}
+
+unsigned QualifiedNameAST::firstToken() const
+{
+ if (global_scope_token)
+ return global_scope_token;
+ else if (nested_name_specifier)
+ return nested_name_specifier->firstToken();
+ return unqualified_name->firstToken();
+}
+
+unsigned QualifiedNameAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (unqualified_name)
+ return unqualified_name->lastToken();
+ else if (nested_name_specifier)
+ return nested_name_specifier->lastToken();
+ return global_scope_token + 1;
+}
+
+void ReferenceAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ReferenceAST::firstToken() const
+{
+ return amp_token;
+}
+
+unsigned ReferenceAST::lastToken() const
+{
+ assert(0 && "review me");
+ return amp_token + 1;
+}
+
+void ReturnStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ReturnStatementAST::firstToken() const
+{
+ return return_token;
+}
+
+unsigned ReturnStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void SimpleDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = decl_specifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ accept(declarators, visitor);
+ }
+}
+
+unsigned SimpleDeclarationAST::firstToken() const
+{
+ for (SpecifierAST *it = decl_specifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->firstToken();
+ }
+ for (DeclaratorListAST *it = declarators; it; it = it->next) {
+ if (! it->next)
+ return it->firstToken();
+ }
+ return semicolon_token;
+}
+
+unsigned SimpleDeclarationAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (semicolon_token)
+ return semicolon_token + 1;
+ for (DeclaratorListAST *it = declarators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ for (SpecifierAST *it = decl_specifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+void SimpleNameAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned SimpleNameAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned SimpleNameAST::lastToken() const
+{
+ assert(0 && "review me");
+ return identifier_token + 1;
+}
+
+void SimpleSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned SimpleSpecifierAST::firstToken() const
+{
+ return specifier_token;
+}
+
+unsigned SimpleSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ return specifier_token + 1;
+}
+
+void TypeofSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned TypeofSpecifierAST::firstToken() const
+{
+ return typeof_token;
+}
+
+unsigned TypeofSpecifierAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ return typeof_token + 1;
+}
+
+void SizeofExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned SizeofExpressionAST::firstToken() const
+{
+ return sizeof_token;
+}
+
+unsigned SizeofExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ return sizeof_token + 1;
+}
+
+void StringLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(next, visitor);
+ }
+}
+
+unsigned StringLiteralAST::firstToken() const
+{
+ return token;
+}
+
+unsigned StringLiteralAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (next)
+ return next->lastToken();
+ return token + 1;
+}
+
+void SwitchStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned SwitchStatementAST::firstToken() const
+{
+ return switch_token;
+}
+
+unsigned SwitchStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (statement)
+ return statement->lastToken();
+ return rparen_token + 1;
+}
+
+void TemplateArgumentListAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(template_argument, visitor);
+ accept(next, visitor);
+ }
+}
+
+unsigned TemplateArgumentListAST::firstToken() const
+{
+ return template_argument->firstToken();
+}
+
+unsigned TemplateArgumentListAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (const TemplateArgumentListAST *it = this; it; it = it->next) {
+ if (! it->next)
+ return it->template_argument->lastToken();
+ }
+ return 0;
+}
+
+void TemplateDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *param = template_parameters; param;
+ param = param->next)
+ accept(param, visitor);
+ accept(declaration, visitor);
+ }
+}
+
+unsigned TemplateDeclarationAST::firstToken() const
+{
+ if (export_token)
+ return export_token;
+ return template_token;
+}
+
+unsigned TemplateDeclarationAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (declaration)
+ return declaration->lastToken();
+ return greater_token + 1;
+}
+
+void TemplateIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (TemplateArgumentListAST *it = template_arguments; it; it = it->next) {
+ accept(it, visitor);
+ }
+ }
+}
+
+unsigned TemplateIdAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned TemplateIdAST::lastToken() const
+{
+ assert(0 && "review me");
+ return greater_token + 1;
+}
+
+void TemplateTypeParameterAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned TemplateTypeParameterAST::firstToken() const
+{
+ return template_token;
+}
+
+unsigned TemplateTypeParameterAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (type_id)
+ return type_id->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (name)
+ return name->lastToken();
+ else if (class_token)
+ return class_token + 1;
+ return greater_token + 1;
+}
+
+void ThisExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ThisExpressionAST::firstToken() const
+{
+ return this_token;
+}
+
+unsigned ThisExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return this_token + 1;
+}
+
+void ThrowExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ThrowExpressionAST::firstToken() const
+{
+ return throw_token;
+}
+
+unsigned ThrowExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ return throw_token + 1;
+}
+
+void TranslationUnitAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *decl = declarations; decl;
+ decl = decl->next)
+ accept(decl, visitor);
+ }
+}
+
+unsigned TranslationUnitAST::firstToken() const
+{
+ return declarations->firstToken();
+}
+
+unsigned TranslationUnitAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (DeclarationAST *it = declarations; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+void TryBlockStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(catch_clause_seq, visitor);
+ }
+}
+
+unsigned TryBlockStatementAST::firstToken() const
+{
+ return try_token;
+}
+
+unsigned TryBlockStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ for (CatchClauseAST *it = catch_clause_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ if (statement)
+ return statement->lastToken();
+ return try_token + 1;
+}
+
+void TypeConstructorCallAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ for (ExpressionListAST *expr = expression_list;expr;
+ expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned TypeConstructorCallAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned TypeConstructorCallAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void TypeIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ }
+}
+
+unsigned TypeIdAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned TypeIdAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (declarator)
+ return declarator->lastToken();
+ return type_specifier->lastToken();
+}
+
+void TypeidExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned TypeidExpressionAST::firstToken() const
+{
+ return typeid_token;
+}
+
+unsigned TypeidExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void TypenameCallExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ for (ExpressionListAST *expr = expression_list;expr;
+ expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned TypenameCallExpressionAST::firstToken() const
+{
+ return typename_token;
+}
+
+unsigned TypenameCallExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ return rparen_token + 1;
+}
+
+void TypenameTypeParameterAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ accept(type_id, visitor);
+ }
+}
+
+unsigned TypenameTypeParameterAST::firstToken() const
+{
+ return classkey_token;
+}
+
+unsigned TypenameTypeParameterAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (type_id)
+ return type_id->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (name)
+ return name->lastToken();
+ return classkey_token + 1;
+}
+
+void UnaryExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned UnaryExpressionAST::firstToken() const
+{
+ return unary_op_token;
+}
+
+unsigned UnaryExpressionAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (expression)
+ return expression->lastToken();
+ return unary_op_token + 1;
+}
+
+void UsingAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned UsingAST::firstToken() const
+{
+ return using_token;
+}
+
+unsigned UsingAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void UsingDirectiveAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned UsingDirectiveAST::firstToken() const
+{
+ return using_token;
+}
+
+unsigned UsingDirectiveAST::lastToken() const
+{
+ assert(0 && "review me");
+ return semicolon_token + 1;
+}
+
+void WhileStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned WhileStatementAST::firstToken() const
+{
+ return while_token;
+}
+
+unsigned WhileStatementAST::lastToken() const
+{
+ assert(0 && "review me");
+ if (statement)
+ return statement->lastToken();
+ return rparen_token + 1;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/AST.h b/shared/cplusplus/AST.h
new file mode 100644
index 0000000000..e692a60976
--- /dev/null
+++ b/shared/cplusplus/AST.h
@@ -0,0 +1,1722 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_AST_H
+#define CPLUSPLUS_AST_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+#include <new>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT AST
+{
+ AST(const AST &other);
+ void operator =(const AST &other);
+
+public:
+ AST();
+ virtual ~AST();
+
+ void accept(ASTVisitor *visitor);
+
+ static void accept(AST *ast, ASTVisitor *visitor)
+ { if (ast) ast->accept(visitor); }
+
+ void *operator new(size_t size, MemoryPool *pool);
+ void operator delete(void *);
+ void operator delete(void *, MemoryPool *);
+
+ virtual unsigned firstToken() const = 0;
+ virtual unsigned lastToken() const = 0;
+
+ AccessDeclarationAST *asAccessDeclaration();
+ ArrayAccessAST *asArrayAccess();
+ ArrayDeclaratorAST *asArrayDeclarator();
+ ArrayInitializerAST *asArrayInitializer();
+ AsmDefinitionAST *asAsmDefinition();
+ AttributeAST *asAttribute();
+ AttributeSpecifierAST *asAttributeSpecifier();
+ BaseSpecifierAST *asBaseSpecifier();
+ QtMethodAST *asQtMethod();
+ BinaryExpressionAST *asBinaryExpression();
+ BoolLiteralAST *asBoolLiteral();
+ BreakStatementAST *asBreakStatement();
+ CallAST *asCall();
+ CaseStatementAST *asCaseStatement();
+ CastExpressionAST *asCastExpression();
+ CatchClauseAST *asCatchClause();
+ ClassSpecifierAST *asClassSpecifier();
+ CompoundStatementAST *asCompoundStatement();
+ ConditionAST *asCondition();
+ ConditionalExpressionAST *asConditionalExpression();
+ ContinueStatementAST *asContinueStatement();
+ ConversionFunctionIdAST *asConversionFunctionId();
+ CoreDeclaratorAST *asCoreDeclarator();
+ CppCastExpressionAST *asCppCastExpression();
+ CtorInitializerAST *asCtorInitializer();
+ DeclarationAST *asDeclaration();
+ DeclarationStatementAST *asDeclarationStatement();
+ DeclaratorAST *asDeclarator();
+ DeclaratorIdAST *asDeclaratorId();
+ DeclaratorListAST *asDeclaratorList();
+ DeleteExpressionAST *asDeleteExpression();
+ DestructorNameAST *asDestructorName();
+ DoStatementAST *asDoStatement();
+ ElaboratedTypeSpecifierAST *asElaboratedTypeSpecifier();
+ EmptyDeclarationAST *asEmptyDeclaration();
+ EnumSpecifierAST *asEnumSpecifier();
+ EnumeratorAST *asEnumerator();
+ ExceptionDeclarationAST *asExceptionDeclaration();
+ ExceptionSpecificationAST *asExceptionSpecification();
+ ExpressionAST *asExpression();
+ ExpressionListAST *asExpressionList();
+ ExpressionOrDeclarationStatementAST *asExpressionOrDeclarationStatement();
+ ExpressionStatementAST *asExpressionStatement();
+ ForStatementAST *asForStatement();
+ FunctionDeclaratorAST *asFunctionDeclarator();
+ FunctionDefinitionAST *asFunctionDefinition();
+ GotoStatementAST *asGotoStatement();
+ IfStatementAST *asIfStatement();
+ LabeledStatementAST *asLabeledStatement();
+ LinkageBodyAST *asLinkageBody();
+ LinkageSpecificationAST *asLinkageSpecification();
+ MemInitializerAST *asMemInitializer();
+ MemberAccessAST *asMemberAccess();
+ NameAST *asName();
+ NamedTypeSpecifierAST *asNamedTypeSpecifier();
+ NamespaceAST *asNamespace();
+ NamespaceAliasDefinitionAST *asNamespaceAliasDefinition();
+ NestedDeclaratorAST *asNestedDeclarator();
+ NestedExpressionAST *asNestedExpression();
+ NestedNameSpecifierAST *asNestedNameSpecifier();
+ NewDeclaratorAST *asNewDeclarator();
+ NewExpressionAST *asNewExpression();
+ NewInitializerAST *asNewInitializer();
+ NewTypeIdAST *asNewTypeId();
+ NumericLiteralAST *asNumericLiteral();
+ OperatorAST *asOperator();
+ OperatorFunctionIdAST *asOperatorFunctionId();
+ ParameterDeclarationAST *asParameterDeclaration();
+ ParameterDeclarationClauseAST *asParameterDeclarationClause();
+ PointerAST *asPointer();
+ PointerToMemberAST *asPointerToMember();
+ PostIncrDecrAST *asPostIncrDecr();
+ PostfixAST *asPostfix();
+ PostfixDeclaratorAST *asPostfixDeclarator();
+ PostfixExpressionAST *asPostfixExpression();
+ PtrOperatorAST *asPtrOperator();
+ QualifiedNameAST *asQualifiedName();
+ ReferenceAST *asReference();
+ ReturnStatementAST *asReturnStatement();
+ SimpleDeclarationAST *asSimpleDeclaration();
+ SimpleNameAST *asSimpleName();
+ SimpleSpecifierAST *asSimpleSpecifier();
+ SizeofExpressionAST *asSizeofExpression();
+ SpecifierAST *asSpecifier();
+ StatementAST *asStatement();
+ StringLiteralAST *asStringLiteral();
+ SwitchStatementAST *asSwitchStatement();
+ TemplateArgumentListAST *asTemplateArgumentList();
+ TemplateDeclarationAST *asTemplateDeclaration();
+ TemplateIdAST *asTemplateId();
+ TemplateTypeParameterAST *asTemplateTypeParameter();
+ ThisExpressionAST *asThisExpression();
+ ThrowExpressionAST *asThrowExpression();
+ TranslationUnitAST *asTranslationUnit();
+ TryBlockStatementAST *asTryBlockStatement();
+ TypeConstructorCallAST *asTypeConstructorCall();
+ TypeIdAST *asTypeId();
+ TypeidExpressionAST *asTypeidExpression();
+ TypenameCallExpressionAST *asTypenameCallExpression();
+ TypenameTypeParameterAST *asTypenameTypeParameter();
+ TypeofSpecifierAST *asTypeofSpecifier();
+ UnaryExpressionAST *asUnaryExpression();
+ UsingAST *asUsing();
+ UsingDirectiveAST *asUsingDirective();
+ WhileStatementAST *asWhileStatement();
+
+protected:
+ virtual void accept0(ASTVisitor *visitor) = 0;
+};
+
+class CPLUSPLUS_EXPORT SpecifierAST: public AST
+{
+public:
+ SpecifierAST *next;
+};
+
+class CPLUSPLUS_EXPORT SimpleSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned specifier_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AttributeSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned attribute_token;
+ unsigned first_lparen_token;
+ unsigned second_lparen_token;
+ AttributeAST *attributes;
+ unsigned first_rparen_token;
+ unsigned second_rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AttributeAST: public AST
+{
+public:
+ unsigned identifier_token;
+ unsigned lparen_token;
+ unsigned tag_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+ AttributeAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeofSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned typeof_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT StatementAST: public AST
+{
+public:
+ StatementAST *next;
+};
+
+class CPLUSPLUS_EXPORT ExpressionAST: public AST
+{
+public:
+};
+
+class CPLUSPLUS_EXPORT DeclarationAST: public AST
+{
+public:
+ DeclarationAST *next;
+};
+
+class CPLUSPLUS_EXPORT CoreDeclaratorAST: public AST
+{
+public:
+};
+
+class CPLUSPLUS_EXPORT PostfixDeclaratorAST: public AST
+{
+public:
+ PostfixDeclaratorAST *next;
+};
+
+class CPLUSPLUS_EXPORT DeclaratorAST: public AST
+{
+public:
+ PtrOperatorAST *ptr_operators;
+ CoreDeclaratorAST *core_declarator;
+ PostfixDeclaratorAST *postfix_declarators;
+ SpecifierAST *attributes;
+ ExpressionAST *initializer;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExpressionListAST: public ExpressionAST
+{
+public:
+ ExpressionAST *expression;
+ ExpressionListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SimpleDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *decl_specifier_seq;
+ DeclaratorListAST *declarators;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT EmptyDeclarationAST: public DeclarationAST
+{
+public:
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AccessDeclarationAST: public DeclarationAST
+{
+public:
+ unsigned access_specifier_token;
+ unsigned slots_token;
+ unsigned colon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AsmDefinitionAST: public DeclarationAST
+{
+public:
+ unsigned asm_token;
+ SpecifierAST *cv_qualifier_seq;
+ unsigned lparen_token;
+ unsigned rparen_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BaseSpecifierAST: public AST
+{
+public:
+ unsigned token_virtual;
+ unsigned token_access_specifier;
+ NameAST *name;
+ BaseSpecifierAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT QtMethodAST: public ExpressionAST
+{
+public:
+ unsigned method_token;
+ unsigned lparen_token;
+ DeclaratorAST *declarator;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BinaryExpressionAST: public ExpressionAST
+{
+public:
+ unsigned binary_op_token;
+ ExpressionAST *left_expression;
+ ExpressionAST *right_expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CastExpressionAST: public ExpressionAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *type_id;
+ unsigned rparen_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ClassSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned classkey_token;
+ SpecifierAST *attributes;
+ NameAST *name;
+ BaseSpecifierAST *base_clause;
+ unsigned lbrace_token;
+ DeclarationAST *member_specifiers;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CaseStatementAST: public StatementAST
+{
+public:
+ unsigned case_token;
+ ExpressionAST *expression;
+ unsigned colon_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CompoundStatementAST: public StatementAST
+{
+public:
+ unsigned lbrace_token;
+ StatementAST *statements;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ConditionAST: public ExpressionAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ConditionalExpressionAST: public ExpressionAST
+{
+public:
+ ExpressionAST *condition;
+ unsigned question_token;
+ ExpressionAST *left_expression;
+ unsigned colon_token;
+ ExpressionAST *right_expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CppCastExpressionAST: public ExpressionAST
+{
+public:
+ unsigned cast_token;
+ unsigned less_token;
+ ExpressionAST *type_id;
+ unsigned greater_token;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CtorInitializerAST: public AST
+{
+public:
+ unsigned colon_token;
+ MemInitializerAST *member_initializers;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeclarationStatementAST: public StatementAST
+{
+public:
+ DeclarationAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeclaratorIdAST: public CoreDeclaratorAST
+{
+public:
+ NameAST *name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NestedDeclaratorAST: public CoreDeclaratorAST
+{
+public:
+ unsigned lparen_token;
+ DeclaratorAST *declarator;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT FunctionDeclaratorAST: public PostfixDeclaratorAST
+{
+public:
+ unsigned lparen_token;
+ ParameterDeclarationClauseAST *parameters;
+ unsigned rparen_token;
+ SpecifierAST *cv_qualifier_seq;
+ ExceptionSpecificationAST *exception_specification;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ArrayDeclaratorAST: public PostfixDeclaratorAST
+{
+public:
+ unsigned lbracket_token;
+ ExpressionAST *expression;
+ unsigned rbracket_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeclaratorListAST: public AST
+{
+public:
+ DeclaratorAST *declarator;
+ DeclaratorListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeleteExpressionAST: public ExpressionAST
+{
+public:
+ unsigned scope_token;
+ unsigned delete_token;
+ unsigned lbracket_token;
+ unsigned rbracket_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DoStatementAST: public StatementAST
+{
+public:
+ unsigned do_token;
+ StatementAST *statement;
+ unsigned while_token;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NamedTypeSpecifierAST: public SpecifierAST
+{
+public:
+ NameAST *name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ElaboratedTypeSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned classkey_token;
+ NameAST *name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT EnumSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned enum_token;
+ NameAST *name;
+ unsigned lbrace_token;
+ EnumeratorAST *enumerators;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT EnumeratorAST: public AST
+{
+public:
+ unsigned identifier_token;
+ unsigned equal_token;
+ ExpressionAST *expression;
+ EnumeratorAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExceptionDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+ unsigned dot_dot_dot_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExceptionSpecificationAST: public AST
+{
+public:
+ unsigned throw_token;
+ unsigned lparen_token;
+ unsigned dot_dot_dot_token;
+ ExpressionListAST *type_ids;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExpressionOrDeclarationStatementAST: public StatementAST
+{
+public:
+ StatementAST *expression;
+ StatementAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExpressionStatementAST: public StatementAST
+{
+public:
+ ExpressionAST *expression;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT FunctionDefinitionAST: public DeclarationAST
+{
+public:
+ SpecifierAST *decl_specifier_seq;
+ DeclaratorAST *declarator;
+ CtorInitializerAST *ctor_initializer;
+ StatementAST *function_body;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ForStatementAST: public StatementAST
+{
+public:
+ unsigned for_token;
+ unsigned lparen_token;
+ StatementAST *initializer;
+ ExpressionAST *condition;
+ unsigned semicolon_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT IfStatementAST: public StatementAST
+{
+public:
+ unsigned if_token;
+ unsigned lparen_token;
+ ExpressionAST *condition;
+ unsigned rparen_token;
+ StatementAST *statement;
+ unsigned else_token;
+ StatementAST *else_statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ArrayInitializerAST: public ExpressionAST
+{
+public:
+ unsigned lbrace_token;
+ ExpressionListAST *expression_list;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT LabeledStatementAST: public StatementAST
+{
+public:
+ unsigned label_token;
+ unsigned colon_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT LinkageBodyAST: public DeclarationAST
+{
+public:
+ unsigned lbrace_token;
+ DeclarationAST *declarations;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT LinkageSpecificationAST: public DeclarationAST
+{
+public:
+ unsigned extern_token;
+ unsigned extern_type;
+ DeclarationAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT MemInitializerAST: public AST
+{
+public:
+ NameAST *name;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+ MemInitializerAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NameAST: public ExpressionAST
+{
+public:
+};
+
+class CPLUSPLUS_EXPORT NestedNameSpecifierAST: public AST
+{
+public:
+ NameAST *class_or_namespace_name;
+ unsigned scope_token;
+ NestedNameSpecifierAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT QualifiedNameAST: public NameAST
+{
+public:
+ unsigned global_scope_token;
+ NestedNameSpecifierAST *nested_name_specifier;
+ NameAST *unqualified_name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT OperatorFunctionIdAST: public NameAST
+{
+public:
+ unsigned operator_token;
+ OperatorAST *op;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ConversionFunctionIdAST: public NameAST
+{
+public:
+ unsigned operator_token;
+ SpecifierAST *type_specifier;
+ PtrOperatorAST *ptr_operators;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SimpleNameAST: public NameAST
+{
+public:
+ unsigned identifier_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DestructorNameAST: public NameAST
+{
+public:
+ unsigned tilde_token;
+ unsigned identifier_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateIdAST: public NameAST
+{
+public:
+ unsigned identifier_token;
+ unsigned less_token;
+ TemplateArgumentListAST *template_arguments;
+ unsigned greater_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NamespaceAST: public DeclarationAST
+{
+public:
+ unsigned namespace_token;
+ unsigned identifier_token;
+ SpecifierAST *attributes;
+ DeclarationAST *linkage_body;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NamespaceAliasDefinitionAST: public DeclarationAST
+{
+public:
+ unsigned namespace_token;
+ unsigned namespace_name;
+ unsigned equal_token;
+ NameAST *name;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewDeclaratorAST: public AST
+{
+public:
+ PtrOperatorAST *ptr_operators;
+ NewDeclaratorAST *declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewExpressionAST: public ExpressionAST
+{
+public:
+ unsigned scope_token;
+ unsigned new_token;
+ ExpressionAST *expression;
+ ExpressionAST *type_id;
+ NewTypeIdAST *new_type_id;
+ NewInitializerAST *new_initializer;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewInitializerAST: public AST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewTypeIdAST: public AST
+{
+public:
+ SpecifierAST *type_specifier;
+ NewInitializerAST *new_initializer;
+ NewDeclaratorAST *new_declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT OperatorAST: public AST
+{
+public:
+ unsigned op_token;
+ unsigned open_token;
+ unsigned close_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ParameterDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+ unsigned equal_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ParameterDeclarationClauseAST: public AST
+{
+public:
+ DeclarationAST *parameter_declarations;
+ unsigned dot_dot_dot_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PostfixAST: public AST
+{
+public:
+ PostfixAST *next;
+};
+
+class CPLUSPLUS_EXPORT CallAST: public PostfixAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ArrayAccessAST: public PostfixAST
+{
+public:
+ unsigned lbracket_token;
+ ExpressionAST *expression;
+ unsigned rbracket_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PostIncrDecrAST: public PostfixAST
+{
+public:
+ unsigned incr_decr_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT MemberAccessAST: public PostfixAST
+{
+public:
+ unsigned access_token;
+ unsigned template_token;
+ NameAST *member_name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeidExpressionAST: public ExpressionAST
+{
+public:
+ unsigned typeid_token;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypenameCallExpressionAST: public ExpressionAST
+{
+public:
+ unsigned typename_token;
+ NameAST *name;
+ unsigned lparen_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeConstructorCallAST: public ExpressionAST
+{
+public:
+ SpecifierAST *type_specifier;
+ unsigned lparen_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PostfixExpressionAST: public ExpressionAST
+{
+public:
+ ExpressionAST *base_expression;
+ PostfixAST *postfix_expressions;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PtrOperatorAST: public AST
+{
+public:
+ PtrOperatorAST *next;
+};
+
+class CPLUSPLUS_EXPORT PointerToMemberAST: public PtrOperatorAST
+{
+public:
+ unsigned global_scope_token;
+ NestedNameSpecifierAST *nested_name_specifier;
+ unsigned star_token;
+ SpecifierAST *cv_qualifier_seq;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PointerAST: public PtrOperatorAST
+{
+public:
+ unsigned star_token;
+ SpecifierAST *cv_qualifier_seq;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ReferenceAST: public PtrOperatorAST
+{
+public:
+ unsigned amp_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BreakStatementAST: public StatementAST
+{
+public:
+ unsigned break_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ContinueStatementAST: public StatementAST
+{
+public:
+ unsigned continue_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT GotoStatementAST: public StatementAST
+{
+public:
+ unsigned goto_token;
+ unsigned identifier_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ReturnStatementAST: public StatementAST
+{
+public:
+ unsigned return_token;
+ ExpressionAST *expression;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SizeofExpressionAST: public ExpressionAST
+{
+public:
+ unsigned sizeof_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NumericLiteralAST: public ExpressionAST
+{
+public:
+ unsigned token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BoolLiteralAST: public ExpressionAST
+{
+public:
+ unsigned token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ThisExpressionAST: public ExpressionAST
+{
+public:
+ unsigned this_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NestedExpressionAST: public ExpressionAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT StringLiteralAST: public ExpressionAST
+{
+public:
+ unsigned token;
+ StringLiteralAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SwitchStatementAST: public StatementAST
+{
+public:
+ unsigned switch_token;
+ unsigned lparen_token;
+ ExpressionAST *condition;
+ unsigned rparen_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateArgumentListAST: public AST
+{
+public:
+ ExpressionAST *template_argument;
+ TemplateArgumentListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateDeclarationAST: public DeclarationAST
+{
+public:
+ unsigned export_token;
+ unsigned template_token;
+ unsigned less_token;
+ DeclarationAST *template_parameters;
+ unsigned greater_token;
+ DeclarationAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ThrowExpressionAST: public ExpressionAST
+{
+public:
+ unsigned throw_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TranslationUnitAST: public AST
+{
+public:
+ DeclarationAST *declarations;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TryBlockStatementAST: public StatementAST
+{
+public:
+ unsigned try_token;
+ StatementAST *statement;
+ CatchClauseAST *catch_clause_seq;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CatchClauseAST: public StatementAST
+{
+public:
+ unsigned catch_token;
+ unsigned lparen_token;
+ ExceptionDeclarationAST *exception_declaration;
+ unsigned rparen_token;
+ StatementAST *statement;
+ CatchClauseAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeIdAST: public ExpressionAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypenameTypeParameterAST: public DeclarationAST
+{
+public:
+ unsigned classkey_token;
+ NameAST *name;
+ unsigned equal_token;
+ ExpressionAST *type_id;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateTypeParameterAST: public DeclarationAST
+{
+public:
+ unsigned template_token;
+ unsigned less_token;
+ DeclarationAST *template_parameters;
+ unsigned greater_token;
+ unsigned class_token;
+ NameAST *name;
+ unsigned equal_token;
+ ExpressionAST *type_id;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UnaryExpressionAST: public ExpressionAST
+{
+public:
+ unsigned unary_op_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UsingAST: public DeclarationAST
+{
+public:
+ unsigned using_token;
+ unsigned typename_token;
+ NameAST *name;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UsingDirectiveAST: public DeclarationAST
+{
+public:
+ unsigned using_token;
+ unsigned namespace_token;
+ NameAST *name;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT WhileStatementAST: public StatementAST
+{
+public:
+ unsigned while_token;
+ unsigned lparen_token;
+ ExpressionAST *condition;
+ unsigned rparen_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_AST_H
diff --git a/shared/cplusplus/ASTVisitor.cpp b/shared/cplusplus/ASTVisitor.cpp
new file mode 100644
index 0000000000..45d0157808
--- /dev/null
+++ b/shared/cplusplus/ASTVisitor.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "ASTVisitor.h"
+#include "AST.h"
+#include "TranslationUnit.h"
+#include "Control.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+ASTVisitor::ASTVisitor(Control *control)
+ : _control(control)
+{ }
+
+ASTVisitor::~ASTVisitor()
+{ }
+
+void ASTVisitor::accept(AST *ast)
+{ AST::accept(ast, this); }
+
+Control *ASTVisitor::control() const
+{ return _control; }
+
+TranslationUnit *ASTVisitor::translationUnit() const
+{ return _control->translationUnit(); }
+
+int ASTVisitor::tokenKind(unsigned index) const
+{ return translationUnit()->tokenKind(index); }
+
+const char *ASTVisitor::spell(unsigned index) const
+{
+ if (! index)
+ return 0;
+
+ return translationUnit()->tokenAt(index).spell();
+}
+
+Identifier *ASTVisitor::identifier(unsigned index) const
+{ return translationUnit()->identifier(index); }
+
+Literal *ASTVisitor::literal(unsigned index) const
+{ return translationUnit()->literal(index); }
+
+NumericLiteral *ASTVisitor::numericLiteral(unsigned index) const
+{ return translationUnit()->numericLiteral(index); }
+
+StringLiteral *ASTVisitor::stringLiteral(unsigned index) const
+{ return translationUnit()->stringLiteral(index); }
+
+void ASTVisitor::getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{ translationUnit()->getTokenPosition(index, line, column, fileName); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/ASTVisitor.h b/shared/cplusplus/ASTVisitor.h
new file mode 100644
index 0000000000..50f74c75d0
--- /dev/null
+++ b/shared/cplusplus/ASTVisitor.h
@@ -0,0 +1,195 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_ASTVISITOR_H
+#define CPLUSPLUS_ASTVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT ASTVisitor
+{
+ ASTVisitor(const ASTVisitor &other);
+ void operator =(const ASTVisitor &other);
+
+public:
+ ASTVisitor(Control *control);
+ virtual ~ASTVisitor();
+
+ Control *control() const;
+ TranslationUnit *translationUnit() const;
+
+ int tokenKind(unsigned index) const;
+ const char *spell(unsigned index) const;
+ Identifier *identifier(unsigned index) const;
+ Literal *literal(unsigned index) const;
+ NumericLiteral *numericLiteral(unsigned index) const;
+ StringLiteral *stringLiteral(unsigned index) const;
+
+ void getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column = 0,
+ StringLiteral **fileName = 0) const;
+
+ void accept(AST *ast);
+
+ virtual bool preVisit(AST *) { return true; }
+ virtual void postVisit(AST *) {}
+
+ virtual bool visit(AccessDeclarationAST *) { return true; }
+ virtual bool visit(ArrayAccessAST *) { return true; }
+ virtual bool visit(ArrayDeclaratorAST *) { return true; }
+ virtual bool visit(ArrayInitializerAST *) { return true; }
+ virtual bool visit(AsmDefinitionAST *) { return true; }
+ virtual bool visit(AttributeSpecifierAST *) { return true; }
+ virtual bool visit(AttributeAST *) { return true; }
+ virtual bool visit(BaseSpecifierAST *) { return true; }
+ virtual bool visit(BinaryExpressionAST *) { return true; }
+ virtual bool visit(BoolLiteralAST *) { return true; }
+ virtual bool visit(BreakStatementAST *) { return true; }
+ virtual bool visit(CallAST *) { return true; }
+ virtual bool visit(CaseStatementAST *) { return true; }
+ virtual bool visit(CastExpressionAST *) { return true; }
+ virtual bool visit(CatchClauseAST *) { return true; }
+ virtual bool visit(ClassSpecifierAST *) { return true; }
+ virtual bool visit(CompoundStatementAST *) { return true; }
+ virtual bool visit(ConditionAST *) { return true; }
+ virtual bool visit(ConditionalExpressionAST *) { return true; }
+ virtual bool visit(ContinueStatementAST *) { return true; }
+ virtual bool visit(ConversionFunctionIdAST *) { return true; }
+ virtual bool visit(CppCastExpressionAST *) { return true; }
+ virtual bool visit(CtorInitializerAST *) { return true; }
+ virtual bool visit(DeclaratorAST *) { return true; }
+ virtual bool visit(DeclarationStatementAST *) { return true; }
+ virtual bool visit(DeclaratorIdAST *) { return true; }
+ virtual bool visit(DeclaratorListAST *) { return true; }
+ virtual bool visit(DeleteExpressionAST *) { return true; }
+ virtual bool visit(DestructorNameAST *) { return true; }
+ virtual bool visit(DoStatementAST *) { return true; }
+ virtual bool visit(ElaboratedTypeSpecifierAST *) { return true; }
+ virtual bool visit(EmptyDeclarationAST *) { return true; }
+ virtual bool visit(EnumSpecifierAST *) { return true; }
+ virtual bool visit(EnumeratorAST *) { return true; }
+ virtual bool visit(ExceptionDeclarationAST *) { return true; }
+ virtual bool visit(ExceptionSpecificationAST *) { return true; }
+ virtual bool visit(ExpressionListAST *) { return true; }
+ virtual bool visit(ExpressionOrDeclarationStatementAST *) { return true; }
+ virtual bool visit(ExpressionStatementAST *) { return true; }
+ virtual bool visit(ForStatementAST *) { return true; }
+ virtual bool visit(FunctionDeclaratorAST *) { return true; }
+ virtual bool visit(FunctionDefinitionAST *) { return true; }
+ virtual bool visit(GotoStatementAST *) { return true; }
+ virtual bool visit(IfStatementAST *) { return true; }
+ virtual bool visit(LabeledStatementAST *) { return true; }
+ virtual bool visit(LinkageBodyAST *) { return true; }
+ virtual bool visit(LinkageSpecificationAST *) { return true; }
+ virtual bool visit(MemInitializerAST *) { return true; }
+ virtual bool visit(MemberAccessAST *) { return true; }
+ virtual bool visit(NamedTypeSpecifierAST *) { return true; }
+ virtual bool visit(NamespaceAST *) { return true; }
+ virtual bool visit(NamespaceAliasDefinitionAST *) { return true; }
+ virtual bool visit(NestedDeclaratorAST *) { return true; }
+ virtual bool visit(NestedExpressionAST *) { return true; }
+ virtual bool visit(NestedNameSpecifierAST *) { return true; }
+ virtual bool visit(NewDeclaratorAST *) { return true; }
+ virtual bool visit(NewExpressionAST *) { return true; }
+ virtual bool visit(NewInitializerAST *) { return true; }
+ virtual bool visit(NewTypeIdAST *) { return true; }
+ virtual bool visit(NumericLiteralAST *) { return true; }
+ virtual bool visit(OperatorAST *) { return true; }
+ virtual bool visit(OperatorFunctionIdAST *) { return true; }
+ virtual bool visit(ParameterDeclarationAST *) { return true; }
+ virtual bool visit(ParameterDeclarationClauseAST *) { return true; }
+ virtual bool visit(PointerAST *) { return true; }
+ virtual bool visit(PointerToMemberAST *) { return true; }
+ virtual bool visit(PostIncrDecrAST *) { return true; }
+ virtual bool visit(PostfixExpressionAST *) { return true; }
+ virtual bool visit(QualifiedNameAST *) { return true; }
+ virtual bool visit(ReferenceAST *) { return true; }
+ virtual bool visit(ReturnStatementAST *) { return true; }
+ virtual bool visit(SimpleDeclarationAST *) { return true; }
+ virtual bool visit(SimpleNameAST *) { return true; }
+ virtual bool visit(SimpleSpecifierAST *) { return true; }
+ virtual bool visit(SizeofExpressionAST *) { return true; }
+ virtual bool visit(StringLiteralAST *) { return true; }
+ virtual bool visit(SwitchStatementAST *) { return true; }
+ virtual bool visit(TemplateArgumentListAST *) { return true; }
+ virtual bool visit(TemplateDeclarationAST *) { return true; }
+ virtual bool visit(TemplateIdAST *) { return true; }
+ virtual bool visit(TemplateTypeParameterAST *) { return true; }
+ virtual bool visit(ThisExpressionAST *) { return true; }
+ virtual bool visit(ThrowExpressionAST *) { return true; }
+ virtual bool visit(TranslationUnitAST *) { return true; }
+ virtual bool visit(TryBlockStatementAST *) { return true; }
+ virtual bool visit(TypeConstructorCallAST *) { return true; }
+ virtual bool visit(TypeIdAST *) { return true; }
+ virtual bool visit(TypeidExpressionAST *) { return true; }
+ virtual bool visit(TypeofSpecifierAST *) { return true; }
+ virtual bool visit(TypenameCallExpressionAST *) { return true; }
+ virtual bool visit(TypenameTypeParameterAST *) { return true; }
+ virtual bool visit(UnaryExpressionAST *) { return true; }
+ virtual bool visit(UsingAST *) { return true; }
+ virtual bool visit(UsingDirectiveAST *) { return true; }
+ virtual bool visit(WhileStatementAST *) { return true; }
+ virtual bool visit(QtMethodAST *) { return true; }
+
+private:
+ Control *_control;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_ASTVISITOR_H
diff --git a/shared/cplusplus/ASTfwd.h b/shared/cplusplus/ASTfwd.h
new file mode 100644
index 0000000000..dbabed9e49
--- /dev/null
+++ b/shared/cplusplus/ASTfwd.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_ASTFWD_H
+#define CPLUSPLUS_ASTFWD_H
+
+#include <CPlusPlusForwardDeclarations.h>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class AST;
+class ASTVisitor;
+
+class AccessDeclarationAST;
+class ArrayAccessAST;
+class ArrayDeclaratorAST;
+class ArrayInitializerAST;
+class AsmDefinitionAST;
+class AttributeAST;
+class AttributeSpecifierAST;
+class BaseSpecifierAST;
+class BinaryExpressionAST;
+class BoolLiteralAST;
+class BreakStatementAST;
+class CallAST;
+class CaseStatementAST;
+class CastExpressionAST;
+class CatchClauseAST;
+class ClassSpecifierAST;
+class CompoundStatementAST;
+class ConditionAST;
+class ConditionalExpressionAST;
+class ContinueStatementAST;
+class ConversionFunctionIdAST;
+class CoreDeclaratorAST;
+class CppCastExpressionAST;
+class CtorInitializerAST;
+class DeclarationAST;
+class DeclarationStatementAST;
+class DeclaratorAST;
+class DeclaratorIdAST;
+class DeclaratorListAST;
+class DeleteExpressionAST;
+class DestructorNameAST;
+class DoStatementAST;
+class ElaboratedTypeSpecifierAST;
+class EmptyDeclarationAST;
+class EnumSpecifierAST;
+class EnumeratorAST;
+class ExceptionDeclarationAST;
+class ExceptionSpecificationAST;
+class ExpressionAST;
+class ExpressionListAST;
+class ExpressionOrDeclarationStatementAST;
+class ExpressionStatementAST;
+class ForStatementAST;
+class FunctionDeclaratorAST;
+class FunctionDefinitionAST;
+class GotoStatementAST;
+class IfStatementAST;
+class LabeledStatementAST;
+class LinkageBodyAST;
+class LinkageSpecificationAST;
+class MemInitializerAST;
+class MemberAccessAST;
+class NameAST;
+class NamedTypeSpecifierAST;
+class NamespaceAST;
+class NamespaceAliasDefinitionAST;
+class NestedDeclaratorAST;
+class NestedExpressionAST;
+class NestedNameSpecifierAST;
+class NewDeclaratorAST;
+class NewExpressionAST;
+class NewInitializerAST;
+class NewTypeIdAST;
+class NumericLiteralAST;
+class OperatorAST;
+class OperatorFunctionIdAST;
+class ParameterDeclarationAST;
+class ParameterDeclarationClauseAST;
+class PointerAST;
+class PointerToMemberAST;
+class PostIncrDecrAST;
+class PostfixAST;
+class PostfixDeclaratorAST;
+class PostfixExpressionAST;
+class PtrOperatorAST;
+class QualifiedNameAST;
+class ReferenceAST;
+class ReturnStatementAST;
+class SimpleDeclarationAST;
+class SimpleNameAST;
+class SimpleSpecifierAST;
+class SizeofExpressionAST;
+class SpecifierAST;
+class StatementAST;
+class StringLiteralAST;
+class SwitchStatementAST;
+class TemplateArgumentListAST;
+class TemplateDeclarationAST;
+class TemplateIdAST;
+class TemplateTypeParameterAST;
+class ThisExpressionAST;
+class ThrowExpressionAST;
+class TranslationUnitAST;
+class TryBlockStatementAST;
+class TypeConstructorCallAST;
+class TypeIdAST;
+class TypeidExpressionAST;
+class TypenameCallExpressionAST;
+class TypenameTypeParameterAST;
+class TypeofSpecifierAST;
+class UnaryExpressionAST;
+class UsingAST;
+class UsingDirectiveAST;
+class WhileStatementAST;
+class QtMethodAST;
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_ASTFWD_H
diff --git a/shared/cplusplus/Array.cpp b/shared/cplusplus/Array.cpp
new file mode 100644
index 0000000000..e62ed1ee12
--- /dev/null
+++ b/shared/cplusplus/Array.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Array.h"
diff --git a/shared/cplusplus/Array.h b/shared/cplusplus/Array.h
new file mode 100644
index 0000000000..4f05996fec
--- /dev/null
+++ b/shared/cplusplus/Array.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_ARRAY_H
+#define CPLUSPLUS_ARRAY_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <new>
+#include <cstdlib>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+template <typename _Tp, int SEGMENT_SHIFT = 4>
+class Array
+{
+ Array(const Array &other);
+ void operator =(const Array &other);
+
+public:
+ Array()
+ : _segments(0),
+ _allocatedSegments(0),
+ _segmentCount(-1),
+ _allocatedElements(0),
+ _count(-1)
+ { }
+
+ ~Array()
+ {
+ if (_segments) {
+ for (int index = 0; index <= _segmentCount; ++index) {
+ delete[] (_segments[index] + (index << SEGMENT_SHIFT));
+ }
+ free(_segments);
+ }
+ }
+
+ inline unsigned size() const
+ { return _count + 1; }
+
+ inline unsigned count() const
+ { return _count + 1; }
+
+ inline const _Tp &at(unsigned index) const
+ { return _segments[index >> SEGMENT_SHIFT][index]; }
+
+ inline const _Tp &operator[](unsigned index) const
+ { return _segments[index >> SEGMENT_SHIFT][index]; }
+
+ inline _Tp &operator[](unsigned index)
+ { return _segments[index >> SEGMENT_SHIFT][index]; }
+
+ void push_back(const _Tp &value)
+ {
+ if (++_count == _allocatedElements) {
+ if (++_segmentCount == _allocatedSegments) {
+ _allocatedSegments += 4;
+ _segments = (_Tp **) realloc(_segments, _allocatedSegments * sizeof(_Tp *));
+ }
+
+ _Tp *segment = new _Tp[SEGMENT_SIZE];
+ _segments[_segmentCount] = segment - (_segmentCount << SEGMENT_SHIFT);
+ _allocatedElements += SEGMENT_SIZE;
+ }
+
+ _segments[_count >> SEGMENT_SHIFT][_count] = value;
+ }
+
+private:
+ enum {
+ SEGMENT_SIZE = 1 << SEGMENT_SHIFT
+ };
+
+ _Tp **_segments;
+ int _allocatedSegments;
+ int _segmentCount;
+
+ int _allocatedElements;
+ int _count;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_ARRAY_H
diff --git a/shared/cplusplus/CPlusPlusForwardDeclarations.h b/shared/cplusplus/CPlusPlusForwardDeclarations.h
new file mode 100644
index 0000000000..91c55ca646
--- /dev/null
+++ b/shared/cplusplus/CPlusPlusForwardDeclarations.h
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
+#define CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
+
+#ifdef HAVE_QT
+# include <QtCore/qglobal.h>
+# define CPLUSPLUS_BEGIN_HEADER
+# define CPLUSPLUS_END_HEADER
+# if defined(CPLUSPLUS_BUILD_LIB)
+# define CPLUSPLUS_EXPORT Q_DECL_EXPORT
+# else
+# define CPLUSPLUS_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define CPLUSPLUS_BEGIN_HEADER
+# define CPLUSPLUS_END_HEADER
+# define CPLUSPLUS_EXPORT
+#endif
+
+#ifdef CPLUSPLUS_WITH_NAMESPACE
+# define CPLUSPLUS_BEGIN_NAMESPACE namespace CPlusPlus {
+# define CPLUSPLUS_END_NAMESPACE } // end of namespace CPlusPLus
+# define CPLUSPLUS_USE_NAMESPACE using namespace CPlusPlus;
+#else
+# define CPLUSPLUS_BEGIN_NAMESPACE
+# define CPLUSPLUS_END_NAMESPACE
+# define CPLUSPLUS_USE_NAMESPACE ;
+#endif
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class TranslationUnit;
+class Semantic;
+class Control;
+class MemoryPool;
+class DiagnosticClient;
+
+class Identifier;
+class Literal;
+class StringLiteral;
+class NumericLiteral;
+
+class Scope;
+
+// names
+class NameVisitor;
+class Name;
+class NameId;
+class TemplateNameId;
+class DestructorNameId;
+class OperatorNameId;
+class ConversionNameId;
+class QualifiedNameId;
+
+// types
+class FullySpecifiedType;
+class TypeVisitor;
+class Type;
+class VoidType;
+class IntegerType;
+class FloatType;
+class PointerToMemberType;
+class PointerType;
+class ReferenceType;
+class ArrayType;
+class NamedType;
+
+// symbols
+class SymbolVisitor;
+class Symbol;
+class ScopedSymbol;
+class UsingNamespaceDirective;
+class UsingDeclaration;
+class Declaration;
+class Argument;
+class Function;
+class Namespace;
+class BaseClass;
+class Block;
+class Class;
+class Enum;
+
+class Use;
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
diff --git a/shared/cplusplus/CheckDeclaration.cpp b/shared/cplusplus/CheckDeclaration.cpp
new file mode 100644
index 0000000000..50ca8afc9e
--- /dev/null
+++ b/shared/cplusplus/CheckDeclaration.cpp
@@ -0,0 +1,366 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckDeclaration.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "TranslationUnit.h"
+#include "Scope.h"
+#include "Names.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Control.h"
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckDeclaration::CheckDeclaration(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _declaration(0),
+ _scope(0),
+ _templateParameters(0),
+ _checkAnonymousArguments(false)
+{ }
+
+CheckDeclaration::~CheckDeclaration()
+{ }
+
+void CheckDeclaration::check(DeclarationAST *declaration,
+ Scope *scope, Scope *templateParameters)
+{
+ Scope *previousScope = switchScope(scope);
+ Scope *previousTemplateParameters = switchTemplateParameters(templateParameters);
+ DeclarationAST *previousDeclaration = switchDeclaration(declaration);
+ accept(declaration);
+ (void) switchDeclaration(previousDeclaration);
+ (void) switchTemplateParameters(previousTemplateParameters);
+ (void) switchScope(previousScope);
+}
+
+DeclarationAST *CheckDeclaration::switchDeclaration(DeclarationAST *declaration)
+{
+ DeclarationAST *previousDeclaration = _declaration;
+ _declaration = declaration;
+ return previousDeclaration;
+}
+
+Scope *CheckDeclaration::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+Scope *CheckDeclaration::switchTemplateParameters(Scope *templateParameters)
+{
+ Scope *previousTemplateParameters = _templateParameters;
+ _templateParameters = templateParameters;
+ return previousTemplateParameters;
+}
+
+void CheckDeclaration::checkFunctionArguments(Function *fun)
+{
+ if (! _checkAnonymousArguments)
+ return;
+
+ if (_scope->isClassScope() && fun->isPublic()) {
+ for (unsigned argc = 0; argc < fun->argumentCount(); ++argc) {
+ Argument *arg = fun->argumentAt(argc)->asArgument();
+ assert(arg != 0);
+
+ if (! arg->name()) {
+ translationUnit()->warning(arg->sourceLocation(),
+ "anonymous argument");
+ }
+ }
+ }
+}
+
+bool CheckDeclaration::visit(SimpleDeclarationAST *ast)
+{
+ FullySpecifiedType ty = semantic()->check(ast->decl_specifier_seq, _scope);
+ FullySpecifiedType qualTy = ty.qualifiedType();
+
+ if (_templateParameters) {
+ if (Class *klass = ty->asClass()) {
+ klass->setTemplateParameters(_templateParameters);
+ }
+ }
+
+ for (DeclaratorListAST *it = ast->declarators; it; it = it->next) {
+ Name *name = 0;
+ FullySpecifiedType declTy = semantic()->check(it->declarator, qualTy,
+ _scope, &name);
+
+ if (Function *fun = declTy->asFunction()) {
+ fun->setScope(_scope);
+ fun->setName(name);
+ fun->setMethodKey(semantic()->currentMethodKey());
+ fun->setVisibility(semantic()->currentVisibility());
+ } else if (semantic()->currentMethodKey() != Function::NormalMethod) {
+ translationUnit()->warning(ast->firstToken(),
+ "expected a function declaration");
+ }
+
+ unsigned location = 0;
+ if (it->declarator)
+ location = it->declarator->firstToken();
+ else
+ location = ast->firstToken();
+
+ Declaration *symbol = control()->newDeclaration(location, name);
+ symbol->setType(control()->integerType(IntegerType::Int));
+ symbol->setType(declTy);
+
+ if (_templateParameters && it == ast->declarators && ! ty->asClass())
+ symbol->setTemplateParameters(_templateParameters);
+
+ symbol->setVisibility(semantic()->currentVisibility());
+
+ if (ty.isFriend())
+ symbol->setStorage(Symbol::Friend);
+ else if (ty.isRegister())
+ symbol->setStorage(Symbol::Register);
+ else if (ty.isStatic())
+ symbol->setStorage(Symbol::Static);
+ else if (ty.isExtern())
+ symbol->setStorage(Symbol::Extern);
+ else if (ty.isMutable())
+ symbol->setStorage(Symbol::Mutable);
+ else if (ty.isTypedef())
+ symbol->setStorage(Symbol::Typedef);
+
+ _scope->enterSymbol(symbol);
+ }
+ return false;
+}
+
+bool CheckDeclaration::visit(EmptyDeclarationAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(AccessDeclarationAST *ast)
+{
+ int accessSpecifier = tokenKind(ast->access_specifier_token);
+ int visibility = semantic()->visibilityForAccessSpecifier(accessSpecifier);
+ semantic()->switchVisibility(visibility);
+ if (ast->slots_token)
+ semantic()->switchMethodKey(Function::SlotMethod);
+ else if (accessSpecifier == T_SIGNALS)
+ semantic()->switchMethodKey(Function::SignalMethod);
+ else
+ semantic()->switchMethodKey(Function::NormalMethod);
+ return false;
+}
+
+bool CheckDeclaration::visit(AsmDefinitionAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(ExceptionDeclarationAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(FunctionDefinitionAST *ast)
+{
+ FullySpecifiedType ty = semantic()->check(ast->decl_specifier_seq, _scope);
+ FullySpecifiedType qualTy = ty.qualifiedType();
+ Name *name = 0;
+ FullySpecifiedType funTy = semantic()->check(ast->declarator, qualTy,
+ _scope, &name);
+ Function *fun = funTy->asFunction();
+ if (! fun) {
+ translationUnit()->error(ast->firstToken(),
+ "expected a function prototype");
+ return false;
+ }
+
+ fun->setName(name);
+ fun->setTemplateParameters(_templateParameters);
+ fun->setVisibility(semantic()->currentVisibility());
+ fun->setMethodKey(semantic()->currentMethodKey());
+
+ checkFunctionArguments(fun);
+
+ _scope->enterSymbol(fun);
+
+ if (ast->ctor_initializer && (ty.isValid() || (fun->identity() && ! fun->identity()->isNameId()))) {
+ translationUnit()->error(ast->ctor_initializer->firstToken(),
+ "only constructors take base initializers");
+ }
+
+ int previousVisibility = semantic()->switchVisibility(Symbol::Public);
+ int previousMethodKey = semantic()->switchMethodKey(Function::NormalMethod);
+
+ semantic()->check(ast->function_body, fun->members());
+
+ semantic()->switchMethodKey(previousMethodKey);
+ semantic()->switchVisibility(previousVisibility);
+
+ if (ast->next && ast->next->asEmptyDeclaration()) {
+ translationUnit()->warning(ast->next->firstToken(),
+ "unnecessary semicolon after function block");
+ }
+
+ return false;
+}
+
+bool CheckDeclaration::visit(LinkageBodyAST *ast)
+{
+ for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) {
+ semantic()->check(decl, _scope);
+ }
+ return false;
+}
+
+bool CheckDeclaration::visit(LinkageSpecificationAST *ast)
+{
+ for (DeclarationAST *decl = ast->declaration; decl; decl = decl->next) {
+ semantic()->check(decl, _scope);
+ }
+ return false;
+}
+
+bool CheckDeclaration::visit(NamespaceAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ Name *namespaceName = control()->nameId(id);
+ Namespace *ns = control()->newNamespace(ast->firstToken(), namespaceName);
+ _scope->enterSymbol(ns);
+ semantic()->check(ast->linkage_body, ns->members()); // ### we'll do the merge later.
+
+ if (ast->next && ast->next->asEmptyDeclaration()) {
+ translationUnit()->warning(ast->next->firstToken(),
+ "unnecessary semicolon after namespace");
+ }
+
+ return false;
+}
+
+bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(ParameterDeclarationAST *ast)
+{
+ Name *argName = 0;
+ FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope);
+ FullySpecifiedType argTy = semantic()->check(ast->declarator, ty.qualifiedType(),
+ _scope, &argName);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ Argument *arg = control()->newArgument(ast->firstToken(), argName);
+ if (ast->expression)
+ arg->setInitializer(true);
+ arg->setType(argTy);
+ _scope->enterSymbol(arg);
+ return false;
+}
+
+bool CheckDeclaration::visit(TemplateDeclarationAST *ast)
+{
+/*
+ Template *templ = control()->newTemplate(ast->firstToken());
+
+ for (DeclarationAST *param = ast->template_parameters; param;
+ param = param->next) {
+ semantic()->check(param, templ->members());
+ }
+*/
+
+ Scope *previousScope = switchScope(new Scope(_scope->owner()));
+ for (DeclarationAST *param = ast->template_parameters; param;
+ param = param->next) {
+ semantic()->check(param, _scope);
+ }
+
+ Scope *templateParameters = switchScope(previousScope);
+ semantic()->check(ast->declaration, _scope, templateParameters);
+ return false;
+}
+
+bool CheckDeclaration::visit(TypenameTypeParameterAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ Argument *arg = control()->newArgument(ast->firstToken(), name); // ### new template type
+ _scope->enterSymbol(arg);
+ return false;
+}
+
+bool CheckDeclaration::visit(TemplateTypeParameterAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ Argument *arg = control()->newArgument(ast->firstToken(), name); // ### new template type
+ _scope->enterSymbol(arg);
+ return false;
+}
+
+bool CheckDeclaration::visit(UsingAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ UsingDeclaration *u = control()->newUsingDeclaration(ast->firstToken(), name);
+ _scope->enterSymbol(u);
+ return false;
+}
+
+bool CheckDeclaration::visit(UsingDirectiveAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name);
+ _scope->enterSymbol(u);
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CheckDeclaration.h b/shared/cplusplus/CheckDeclaration.h
new file mode 100644
index 0000000000..333f33175d
--- /dev/null
+++ b/shared/cplusplus/CheckDeclaration.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKDECLARATION_H
+#define CPLUSPLUS_CHECKDECLARATION_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckDeclaration: public SemanticCheck
+{
+public:
+ CheckDeclaration(Semantic *semantic);
+ virtual ~CheckDeclaration();
+
+ void check(DeclarationAST *declaration, Scope *scope, Scope *templateParameters);
+
+protected:
+ DeclarationAST *switchDeclaration(DeclarationAST *declaration);
+ Scope *switchScope(Scope *scope);
+ Scope *switchTemplateParameters(Scope *templateParameters);
+
+ void checkFunctionArguments(Function *fun);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(SimpleDeclarationAST *ast);
+ virtual bool visit(EmptyDeclarationAST *ast);
+ virtual bool visit(AccessDeclarationAST *ast);
+ virtual bool visit(AsmDefinitionAST *ast);
+ virtual bool visit(ExceptionDeclarationAST *ast);
+ virtual bool visit(FunctionDefinitionAST *ast);
+ virtual bool visit(LinkageBodyAST *ast);
+ virtual bool visit(LinkageSpecificationAST *ast);
+ virtual bool visit(NamespaceAST *ast);
+ virtual bool visit(NamespaceAliasDefinitionAST *ast);
+ virtual bool visit(ParameterDeclarationAST *ast);
+ virtual bool visit(TemplateDeclarationAST *ast);
+ virtual bool visit(TypenameTypeParameterAST *ast);
+ virtual bool visit(TemplateTypeParameterAST *ast);
+ virtual bool visit(UsingAST *ast);
+ virtual bool visit(UsingDirectiveAST *ast);
+
+private:
+ DeclarationAST *_declaration;
+ Scope *_scope;
+ Scope *_templateParameters;
+ bool _checkAnonymousArguments: 1;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKDECLARATION_H
diff --git a/shared/cplusplus/CheckDeclarator.cpp b/shared/cplusplus/CheckDeclarator.cpp
new file mode 100644
index 0000000000..a451f78ba2
--- /dev/null
+++ b/shared/cplusplus/CheckDeclarator.cpp
@@ -0,0 +1,258 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckDeclarator.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "Control.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckDeclarator::CheckDeclarator(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _declarator(0),
+ _scope(0),
+ _name(0)
+{ }
+
+CheckDeclarator::~CheckDeclarator()
+{ }
+
+FullySpecifiedType CheckDeclarator::check(DeclaratorAST *declarator,
+ FullySpecifiedType type,
+ Scope *scope,
+ Name **name)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(type);
+ Scope *previousScope = switchScope(scope);
+ DeclaratorAST *previousDeclarator = switchDeclarator(declarator);
+ Name **previousName = switchName(name);
+ accept(declarator);
+ (void) switchName(previousName);
+ (void) switchDeclarator(previousDeclarator);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+FullySpecifiedType CheckDeclarator::check(PtrOperatorAST *ptrOperators,
+ FullySpecifiedType type,
+ Scope *scope)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(type);
+ Scope *previousScope = switchScope(scope);
+ accept(ptrOperators);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+DeclaratorAST *CheckDeclarator::switchDeclarator(DeclaratorAST *declarator)
+{
+ DeclaratorAST *previousDeclarator = _declarator;
+ _declarator = declarator;
+ return previousDeclarator;
+}
+
+FullySpecifiedType CheckDeclarator::switchFullySpecifiedType(FullySpecifiedType type)
+{
+ FullySpecifiedType previousType = _fullySpecifiedType;
+ _fullySpecifiedType = type;
+ return previousType;
+}
+
+Scope *CheckDeclarator::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+Name **CheckDeclarator::switchName(Name **name)
+{
+ Name **previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+bool CheckDeclarator::visit(DeclaratorAST *ast)
+{
+ accept(ast->ptr_operators);
+ accept(ast->postfix_declarators);
+ accept(ast->core_declarator);
+
+ // ### check the initializer
+ // FullySpecifiedType exprTy = semantic()->check(ast->initializer, _scope);
+
+ if (ast->initializer && _fullySpecifiedType->isFunction()) {
+ _fullySpecifiedType->asFunction()->setPureVirtual(true);
+ }
+ return false;
+}
+
+bool CheckDeclarator::visit(DeclaratorIdAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ if (_name)
+ *_name = name;
+ return false;
+}
+
+bool CheckDeclarator::visit(NestedDeclaratorAST *ast)
+{
+ accept(ast->declarator);
+ return false;
+}
+
+bool CheckDeclarator::visit(FunctionDeclaratorAST *ast)
+{
+ Function *fun = control()->newFunction(ast->firstToken());
+ fun->setReturnType(_fullySpecifiedType);
+
+ if (ast->parameters) {
+ DeclarationAST *parameter_declarations = ast->parameters->parameter_declarations;
+ for (DeclarationAST *decl = parameter_declarations; decl; decl = decl->next) {
+ semantic()->check(decl, fun->arguments());
+ }
+
+ if (ast->parameters->dot_dot_dot_token)
+ fun->setVariadic(true);
+ }
+
+ // check the arguments
+ bool hasDefaultArguments = false;
+ for (unsigned i = 0; i < fun->argumentCount(); ++i) {
+ Argument *arg = fun->argumentAt(i)->asArgument();
+ if (hasDefaultArguments && ! arg->hasInitializer()) {
+ translationUnit()->error(ast->firstToken(),
+ "default argument missing for parameter at position %d", i + 1);
+ } else if (! hasDefaultArguments) {
+ hasDefaultArguments = arg->hasInitializer();
+ }
+ }
+
+ FullySpecifiedType funTy(fun);
+ _fullySpecifiedType = funTy;
+
+ for (SpecifierAST *it = ast->cv_qualifier_seq; it; it = it->next) {
+ SimpleSpecifierAST *cv = static_cast<SimpleSpecifierAST *>(it);
+ int k = tokenKind(cv->specifier_token);
+ if (k == T_CONST)
+ fun->setConst(true);
+ else if (k == T_VOLATILE)
+ fun->setVolatile(true);
+ }
+
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(ArrayDeclaratorAST *ast)
+{
+ ArrayType *ty = control()->arrayType(_fullySpecifiedType); // ### set the dimension
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ FullySpecifiedType arrTy(ty);
+ _fullySpecifiedType = ty;
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(PointerToMemberAST *ast)
+{
+ Name *memberName = semantic()->check(ast->nested_name_specifier, _scope);
+ PointerToMemberType *ptrTy = control()->pointerToMemberType(memberName, _fullySpecifiedType);
+ FullySpecifiedType ty(ptrTy);
+ _fullySpecifiedType = ty;
+ applyCvQualifiers(ast->cv_qualifier_seq);
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(PointerAST *ast)
+{
+ PointerType *ptrTy = control()->pointerType(_fullySpecifiedType);
+ FullySpecifiedType ty(ptrTy);
+ _fullySpecifiedType = ty;
+ applyCvQualifiers(ast->cv_qualifier_seq);
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(ReferenceAST *ast)
+{
+ ReferenceType *refTy = control()->referenceType(_fullySpecifiedType);
+ FullySpecifiedType ty(refTy);
+ _fullySpecifiedType = ty;
+ accept(ast->next);
+ return false;
+}
+
+void CheckDeclarator::applyCvQualifiers(SpecifierAST *cv)
+{
+ for (; cv; cv = cv->next) {
+ SimpleSpecifierAST *spec = static_cast<SimpleSpecifierAST *>(cv);
+ switch (translationUnit()->tokenKind(spec->specifier_token)) {
+ case T_VOLATILE:
+ _fullySpecifiedType.setVolatile(true);
+ break;
+ case T_CONST:
+ _fullySpecifiedType.setConst(true);
+ break;
+ default:
+ break;
+ } // switch
+ }
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CheckDeclarator.h b/shared/cplusplus/CheckDeclarator.h
new file mode 100644
index 0000000000..c391bf99e6
--- /dev/null
+++ b/shared/cplusplus/CheckDeclarator.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKDECLARATOR_H
+#define CPLUSPLUS_CHECKDECLARATOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckDeclarator: public SemanticCheck
+{
+public:
+ CheckDeclarator(Semantic *semantic);
+ virtual ~CheckDeclarator();
+
+ FullySpecifiedType check(DeclaratorAST *declarator,
+ FullySpecifiedType type,
+ Scope *scope,
+ Name **name);
+
+ FullySpecifiedType check(PtrOperatorAST *ptrOperators,
+ FullySpecifiedType type,
+ Scope *scope);
+
+protected:
+ DeclaratorAST *switchDeclarator(DeclaratorAST *declarator);
+ FullySpecifiedType switchFullySpecifiedType(FullySpecifiedType type);
+ Scope *switchScope(Scope *scope);
+ Name **switchName(Name **name);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(DeclaratorAST *ast);
+ // ptr operators
+ virtual bool visit(PointerToMemberAST *ast);
+ virtual bool visit(PointerAST *ast);
+ virtual bool visit(ReferenceAST *ast);
+ // core declarators
+ virtual bool visit(DeclaratorIdAST *ast);
+ virtual bool visit(NestedDeclaratorAST *ast);
+ // postfix declarators
+ virtual bool visit(FunctionDeclaratorAST *ast);
+ virtual bool visit(ArrayDeclaratorAST *ast);
+
+ void applyCvQualifiers(SpecifierAST *cv);
+
+private:
+ DeclaratorAST *_declarator;
+ Scope *_scope;
+ Name **_name;
+ FullySpecifiedType _fullySpecifiedType;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKDECLARATOR_H
diff --git a/shared/cplusplus/CheckExpression.cpp b/shared/cplusplus/CheckExpression.cpp
new file mode 100644
index 0000000000..080f74eef1
--- /dev/null
+++ b/shared/cplusplus/CheckExpression.cpp
@@ -0,0 +1,362 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckExpression.h"
+#include "Semantic.h"
+#include "TranslationUnit.h"
+#include "AST.h"
+#include "Scope.h"
+#include "Literals.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Control.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckExpression::CheckExpression(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _expression(0),
+ _scope(0),
+ _checkOldStyleCasts(false)
+{ }
+
+CheckExpression::~CheckExpression()
+{ }
+
+FullySpecifiedType CheckExpression::check(ExpressionAST *expression, Scope *scope)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(FullySpecifiedType());
+ Scope *previousScope = switchScope(scope);
+ ExpressionAST *previousExpression = switchExpression(expression);
+ accept(expression);
+ (void) switchExpression(previousExpression);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+ExpressionAST *CheckExpression::switchExpression(ExpressionAST *expression)
+{
+ ExpressionAST *previousExpression = _expression;
+ _expression = expression;
+ return previousExpression;
+}
+
+FullySpecifiedType CheckExpression::switchFullySpecifiedType(FullySpecifiedType type)
+{
+ FullySpecifiedType previousType = _fullySpecifiedType;
+ _fullySpecifiedType = type;
+ return previousType;
+}
+
+Scope *CheckExpression::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckExpression::visit(ExpressionListAST *ast)
+{
+ for (ExpressionListAST *it = ast; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(BinaryExpressionAST *ast)
+{
+ FullySpecifiedType leftExprTy = semantic()->check(ast->left_expression, _scope);
+ FullySpecifiedType rightExprTy = semantic()->check(ast->right_expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(CastExpressionAST *ast)
+{
+ FullySpecifiedType castTy = semantic()->check(ast->type_id, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ if (_checkOldStyleCasts && ! castTy->isVoidType())
+ translationUnit()->warning(ast->firstToken(),
+ "ugly old style cast");
+ return false;
+}
+
+bool CheckExpression::visit(ConditionAST *ast)
+{
+ FullySpecifiedType typeSpecTy = semantic()->check(ast->type_specifier, _scope);
+ Name *name = 0;
+ FullySpecifiedType declTy = semantic()->check(ast->declarator, typeSpecTy.qualifiedType(),
+ _scope, &name);
+ Declaration *decl = control()->newDeclaration(ast->declarator->firstToken(), name);
+ decl->setType(declTy);
+ _scope->enterSymbol(decl);
+ return false;
+}
+
+bool CheckExpression::visit(ConditionalExpressionAST *ast)
+{
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ FullySpecifiedType leftExprTy = semantic()->check(ast->left_expression, _scope);
+ FullySpecifiedType rightExprTy = semantic()->check(ast->right_expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(CppCastExpressionAST *ast)
+{
+ FullySpecifiedType typeIdTy = semantic()->check(ast->type_id, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(DeleteExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(ArrayInitializerAST *ast)
+{
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(QualifiedNameAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(OperatorFunctionIdAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(ConversionFunctionIdAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(SimpleNameAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(DestructorNameAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(TemplateIdAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(NewExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ FullySpecifiedType typeIdTy = semantic()->check(ast->type_id, _scope);
+ // ### process new-typeid
+ // ### process new-initializer
+ return false;
+}
+
+bool CheckExpression::visit(TypeidExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(TypenameCallExpressionAST *ast)
+{
+ if (Name *name = semantic()->check(ast->name, _scope)) {
+ _scope->addUse(ast->name->firstToken(), name);
+ }
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(TypeConstructorCallAST *ast)
+{
+ FullySpecifiedType typeSpecTy = semantic()->check(ast->type_specifier, _scope);
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(PostfixExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->base_expression, _scope);
+ for (PostfixAST *fx = ast->postfix_expressions; fx; fx = fx->next) {
+ accept(fx); // ### not exactly.
+ }
+ return false;
+}
+
+bool CheckExpression::visit(SizeofExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(NumericLiteralAST *)
+{
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Int));
+ return false;
+}
+
+bool CheckExpression::visit(BoolLiteralAST *)
+{
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Bool));
+ return false;
+}
+
+bool CheckExpression::visit(StringLiteralAST *)
+{
+ IntegerType *charTy = control()->integerType(IntegerType::Char);
+ _fullySpecifiedType.setType(control()->pointerType(charTy));
+ return false;
+}
+
+bool CheckExpression::visit(ThisExpressionAST *)
+{
+ return false;
+}
+
+bool CheckExpression::visit(NestedExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(ThrowExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(TypeIdAST *ast)
+{
+ FullySpecifiedType typeSpecTy = semantic()->check(ast->type_specifier, _scope);
+ FullySpecifiedType declTy = semantic()->check(ast->declarator, typeSpecTy.qualifiedType(),
+ _scope);
+ _fullySpecifiedType = declTy;
+ return false;
+}
+
+bool CheckExpression::visit(UnaryExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(QtMethodAST *ast)
+{
+ Name *name = 0;
+ Scope dummy;
+ FullySpecifiedType methTy = semantic()->check(ast->declarator, FullySpecifiedType(),
+ &dummy, &name);
+ Function *fty = methTy->asFunction();
+ if (! fty)
+ translationUnit()->warning(ast->firstToken(), "expected a function declarator");
+ else {
+ for (unsigned i = 0; i < fty->argumentCount(); ++i) {
+ Symbol *arg = fty->argumentAt(i);
+ if (arg->name())
+ translationUnit()->warning(arg->sourceLocation(),
+ "argument should be anonymous");
+ }
+ }
+ return false;
+}
+
+bool CheckExpression::visit(CallAST *ast)
+{
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(ArrayAccessAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(PostIncrDecrAST *)
+{
+ return false;
+}
+
+bool CheckExpression::visit(MemberAccessAST *ast)
+{
+ if (Name *name = semantic()->check(ast->member_name, _scope))
+ _scope->addUse(ast->member_name->firstToken(), name);
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CheckExpression.h b/shared/cplusplus/CheckExpression.h
new file mode 100644
index 0000000000..3501cf203c
--- /dev/null
+++ b/shared/cplusplus/CheckExpression.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKEXPRESSION_H
+#define CPLUSPLUS_CHECKEXPRESSION_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckExpression: public SemanticCheck
+{
+public:
+ CheckExpression(Semantic *semantic);
+ virtual ~CheckExpression();
+
+ FullySpecifiedType check(ExpressionAST *expression, Scope *scope);
+
+protected:
+ ExpressionAST *switchExpression(ExpressionAST *expression);
+ FullySpecifiedType switchFullySpecifiedType(FullySpecifiedType type);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+ virtual bool visit(QtMethodAST *ast);
+
+ //names
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+ // postfix expressions
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+
+private:
+ ExpressionAST *_expression;
+ FullySpecifiedType _fullySpecifiedType;
+ Scope *_scope;
+ bool _checkOldStyleCasts: 1;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKEXPRESSION_H
diff --git a/shared/cplusplus/CheckName.cpp b/shared/cplusplus/CheckName.cpp
new file mode 100644
index 0000000000..a0427e99a8
--- /dev/null
+++ b/shared/cplusplus/CheckName.cpp
@@ -0,0 +1,348 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckName.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "Control.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "Names.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckName::CheckName(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _name(0),
+ _scope(0)
+{ }
+
+CheckName::~CheckName()
+{ }
+
+Name *CheckName::check(NameAST *name, Scope *scope)
+{
+ Name *previousName = switchName(0);
+ Scope *previousScope = switchScope(scope);
+ accept(name);
+ (void) switchScope(previousScope);
+ return switchName(previousName);
+}
+
+Name *CheckName::check(NestedNameSpecifierAST *nested_name_specifier, Scope *scope)
+{
+ Name *previousName = switchName(0);
+ Scope *previousScope = switchScope(scope);
+
+ std::vector<Name *> names;
+ for (NestedNameSpecifierAST *it = nested_name_specifier;
+ it; it = it->next) {
+ names.push_back(semantic()->check(it->class_or_namespace_name, _scope));
+ }
+ _name = control()->qualifiedNameId(&names[0], names.size());
+
+ (void) switchScope(previousScope);
+ return switchName(previousName);
+}
+
+Name *CheckName::switchName(Name *name)
+{
+ Name *previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+Scope *CheckName::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckName::visit(QualifiedNameAST *ast)
+{
+ std::vector<Name *> names;
+ for (NestedNameSpecifierAST *it = ast->nested_name_specifier;
+ it; it = it->next) {
+ names.push_back(semantic()->check(it->class_or_namespace_name, _scope));
+ }
+ names.push_back(semantic()->check(ast->unqualified_name, _scope));
+ _name = control()->qualifiedNameId(&names[0], names.size(),
+ ast->global_scope_token != 0);
+ return false;
+}
+
+bool CheckName::visit(OperatorFunctionIdAST *ast)
+{
+ assert(ast->op != 0);
+
+ OperatorNameId::Kind kind = OperatorNameId::InvalidOp;
+
+ switch (tokenKind(ast->op->op_token)) {
+ case T_NEW:
+ if (ast->op->open_token)
+ kind = OperatorNameId::NewArrayOp;
+ else
+ kind = OperatorNameId::NewOp;
+ break;
+
+ case T_DELETE:
+ if (ast->op->open_token)
+ kind = OperatorNameId::DeleteArrayOp;
+ else
+ kind = OperatorNameId::DeleteOp;
+ break;
+
+ case T_PLUS:
+ kind = OperatorNameId::PlusOp;
+ break;
+
+ case T_MINUS:
+ kind = OperatorNameId::MinusOp;
+ break;
+
+ case T_STAR:
+ kind = OperatorNameId::StarOp;
+ break;
+
+ case T_SLASH:
+ kind = OperatorNameId::SlashOp;
+ break;
+
+ case T_PERCENT:
+ kind = OperatorNameId::PercentOp;
+ break;
+
+ case T_CARET:
+ kind = OperatorNameId::CaretOp;
+ break;
+
+ case T_AMPER:
+ kind = OperatorNameId::AmpOp;
+ break;
+
+ case T_PIPE:
+ kind = OperatorNameId::PipeOp;
+ break;
+
+ case T_TILDE:
+ kind = OperatorNameId::TildeOp;
+ break;
+
+ case T_EXCLAIM:
+ kind = OperatorNameId::ExclaimOp;
+ break;
+
+ case T_EQUAL:
+ kind = OperatorNameId::EqualOp;
+ break;
+
+ case T_LESS:
+ kind = OperatorNameId::LessOp;
+ break;
+
+ case T_GREATER:
+ kind = OperatorNameId::GreaterOp;
+ break;
+
+ case T_PLUS_EQUAL:
+ kind = OperatorNameId::PlusEqualOp;
+ break;
+
+ case T_MINUS_EQUAL:
+ kind = OperatorNameId::MinusEqualOp;
+ break;
+
+ case T_STAR_EQUAL:
+ kind = OperatorNameId::StarEqualOp;
+ break;
+
+ case T_SLASH_EQUAL:
+ kind = OperatorNameId::SlashEqualOp;
+ break;
+
+ case T_PERCENT_EQUAL:
+ kind = OperatorNameId::PercentEqualOp;
+ break;
+
+ case T_CARET_EQUAL:
+ kind = OperatorNameId::CaretEqualOp;
+ break;
+
+ case T_AMPER_EQUAL:
+ kind = OperatorNameId::AmpEqualOp;
+ break;
+
+ case T_PIPE_EQUAL:
+ kind = OperatorNameId::PipeEqualOp;
+ break;
+
+ case T_LESS_LESS:
+ kind = OperatorNameId::LessLessOp;
+ break;
+
+ case T_GREATER_GREATER:
+ kind = OperatorNameId::GreaterGreaterOp;
+ break;
+
+ case T_LESS_LESS_EQUAL:
+ kind = OperatorNameId::LessLessEqualOp;
+ break;
+
+ case T_GREATER_GREATER_EQUAL:
+ kind = OperatorNameId::GreaterGreaterEqualOp;
+ break;
+
+ case T_EQUAL_EQUAL:
+ kind = OperatorNameId::EqualEqualOp;
+ break;
+
+ case T_EXCLAIM_EQUAL:
+ kind = OperatorNameId::ExclaimEqualOp;
+ break;
+
+ case T_LESS_EQUAL:
+ kind = OperatorNameId::LessEqualOp;
+ break;
+
+ case T_GREATER_EQUAL:
+ kind = OperatorNameId::GreaterEqualOp;
+ break;
+
+ case T_AMPER_AMPER:
+ kind = OperatorNameId::AmpAmpOp;
+ break;
+
+ case T_PIPE_PIPE:
+ kind = OperatorNameId::PipePipeOp;
+ break;
+
+ case T_PLUS_PLUS:
+ kind = OperatorNameId::PlusPlusOp;
+ break;
+
+ case T_MINUS_MINUS:
+ kind = OperatorNameId::MinusMinusOp;
+ break;
+
+ case T_COMMA:
+ kind = OperatorNameId::CommaOp;
+ break;
+
+ case T_ARROW_STAR:
+ kind = OperatorNameId::ArrowStarOp;
+ break;
+
+ case T_ARROW:
+ kind = OperatorNameId::ArrowOp;
+ break;
+
+ case T_LPAREN:
+ kind = OperatorNameId::FunctionCallOp;
+ break;
+
+ case T_LBRACKET:
+ kind = OperatorNameId::ArrayAccessOp;
+ break;
+
+ default:
+ kind = OperatorNameId::InvalidOp;
+ } // switch
+
+ _name = control()->operatorNameId(kind);
+ return false;
+}
+
+bool CheckName::visit(ConversionFunctionIdAST *ast)
+{
+ FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope);
+ ty = semantic()->check(ast->ptr_operators, ty, _scope);
+ _name = control()->conversionNameId(ty);
+ return false;
+}
+
+bool CheckName::visit(SimpleNameAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ _name = control()->nameId(id);
+ return false;
+}
+
+bool CheckName::visit(DestructorNameAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ _name = control()->destructorNameId(id);
+ return false;
+}
+
+bool CheckName::visit(TemplateIdAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ std::vector<FullySpecifiedType> templateArguments;
+ for (TemplateArgumentListAST *it = ast->template_arguments; it;
+ it = it->next) {
+ ExpressionAST *arg = it->template_argument;
+ FullySpecifiedType exprTy = semantic()->check(arg, _scope);
+ templateArguments.push_back(exprTy);
+ }
+ if (templateArguments.empty())
+ _name = control()->templateNameId(id);
+ else
+ _name = control()->templateNameId(id, &templateArguments[0],
+ templateArguments.size());
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CheckName.h b/shared/cplusplus/CheckName.h
new file mode 100644
index 0000000000..55cbe0fd92
--- /dev/null
+++ b/shared/cplusplus/CheckName.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKNAME_H
+#define CPLUSPLUS_CHECKNAME_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckName: public SemanticCheck
+{
+public:
+ CheckName(Semantic *semantic);
+ virtual ~CheckName();
+
+ Name *check(NameAST *name, Scope *scope);
+ Name *check(NestedNameSpecifierAST *name, Scope *scope);
+
+protected:
+ Name *switchName(Name *name);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+private:
+ Name *_name;
+ Scope *_scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKNAME_H
diff --git a/shared/cplusplus/CheckSpecifier.cpp b/shared/cplusplus/CheckSpecifier.cpp
new file mode 100644
index 0000000000..fba99c4e3a
--- /dev/null
+++ b/shared/cplusplus/CheckSpecifier.cpp
@@ -0,0 +1,392 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckSpecifier.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "Token.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "Names.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Control.h"
+#include "Scope.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckSpecifier::CheckSpecifier(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _specifier(0),
+ _scope(0)
+{ }
+
+CheckSpecifier::~CheckSpecifier()
+{ }
+
+FullySpecifiedType CheckSpecifier::check(SpecifierAST *specifier, Scope *scope)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(FullySpecifiedType());
+ Scope *previousScope = switchScope(scope);
+ SpecifierAST *previousSpecifier = switchSpecifier(specifier);
+ accept(specifier);
+ (void) switchSpecifier(previousSpecifier);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+SpecifierAST *CheckSpecifier::switchSpecifier(SpecifierAST *specifier)
+{
+ SpecifierAST *previousSpecifier = _specifier;
+ _specifier = specifier;
+ return previousSpecifier;
+}
+
+FullySpecifiedType CheckSpecifier::switchFullySpecifiedType(FullySpecifiedType type)
+{
+ FullySpecifiedType previousType = _fullySpecifiedType;
+ _fullySpecifiedType = type;
+ return previousType;
+}
+
+Scope *CheckSpecifier::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckSpecifier::visit(SimpleSpecifierAST *ast)
+{
+ switch (tokenKind(ast->specifier_token)) {
+ case T_CONST:
+ if (_fullySpecifiedType.isConst())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setConst(true);
+ break;
+
+ case T_VOLATILE:
+ if (_fullySpecifiedType.isVolatile())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setVolatile(true);
+ break;
+
+ case T_FRIEND:
+ if (_fullySpecifiedType.isFriend())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setFriend(true);
+ break;
+
+ case T_REGISTER:
+ if (_fullySpecifiedType.isRegister())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setRegister(true);
+ break;
+
+ case T_STATIC:
+ if (_fullySpecifiedType.isStatic())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setStatic(true);
+ break;
+
+ case T_EXTERN:
+ if (_fullySpecifiedType.isExtern())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setExtern(true);
+ break;
+
+ case T_MUTABLE:
+ if (_fullySpecifiedType.isMutable())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setMutable(true);
+ break;
+
+ case T_TYPEDEF:
+ if (_fullySpecifiedType.isTypedef())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setTypedef(true);
+ break;
+
+ case T_INLINE:
+ if (_fullySpecifiedType.isInline())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setInline(true);
+ break;
+
+ case T_VIRTUAL:
+ if (_fullySpecifiedType.isVirtual())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setVirtual(true);
+ break;
+
+ case T_EXPLICIT:
+ if (_fullySpecifiedType.isExplicit())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setExplicit(true);
+ break;
+
+ case T_SIGNED:
+ if (_fullySpecifiedType.isSigned())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setSigned(true);
+ break;
+
+ case T_UNSIGNED:
+ if (_fullySpecifiedType.isUnsigned())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setUnsigned(true);
+ break;
+
+ case T_CHAR:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Char));
+ break;
+
+ case T_WCHAR_T:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::WideChar));
+ break;
+
+ case T_BOOL:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Bool));
+ break;
+
+ case T_SHORT:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *intType = control()->integerType(IntegerType::Int);
+ if (tp != intType)
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Short));
+ break;
+
+ case T_INT:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *shortType = control()->integerType(IntegerType::Short);
+ IntegerType *longType = control()->integerType(IntegerType::Long);
+ IntegerType *longLongType = control()->integerType(IntegerType::LongLong);
+ if (tp == shortType || tp == longType || tp == longLongType)
+ break;
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Int));
+ break;
+
+ case T_LONG:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *intType = control()->integerType(IntegerType::Int);
+ IntegerType *longType = control()->integerType(IntegerType::Long);
+ FloatType *doubleType = control()->floatType(FloatType::Double);
+ if (tp == longType) {
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::LongLong));
+ break;
+ } else if (tp == doubleType) {
+ _fullySpecifiedType.setType(control()->floatType(FloatType::LongDouble));
+ break;
+ } else if (tp != intType) {
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ }
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Long));
+ break;
+
+ case T_FLOAT:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->floatType(FloatType::Float));
+ break;
+
+ case T_DOUBLE:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *longType = control()->integerType(IntegerType::Long);
+ if (tp == longType) {
+ _fullySpecifiedType.setType(control()->floatType(FloatType::LongDouble));
+ break;
+ }
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ _fullySpecifiedType.setType(control()->floatType(FloatType::Double));
+ break;
+
+ case T_VOID:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->voidType());
+ break;
+
+ default:
+ break;
+ } // switch
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(ClassSpecifierAST *ast)
+{
+ Name *className = semantic()->check(ast->name, _scope);
+ Class *klass = control()->newClass(ast->firstToken(), className);
+ unsigned classKey = tokenKind(ast->classkey_token);
+ if (classKey == T_CLASS)
+ klass->setClassKey(Class::ClassKey);
+ else if (classKey == T_STRUCT)
+ klass->setClassKey(Class::StructKey);
+ else if (classKey == T_UNION)
+ klass->setClassKey(Class::UnionKey);
+ klass->setVisibility(semantic()->currentVisibility());
+ _scope->enterSymbol(klass);
+ _fullySpecifiedType.setType(klass);
+
+ for (BaseSpecifierAST *base = ast->base_clause; base; base = base->next) {
+ Name *baseClassName = semantic()->check(base->name, _scope);
+ BaseClass *baseClass = control()->newBaseClass(ast->firstToken(), baseClassName);
+ if (base->token_virtual)
+ baseClass->setVirtual(true);
+ if (base->token_access_specifier) {
+ int accessSpecifier = tokenKind(base->token_access_specifier);
+ int visibility = semantic()->visibilityForAccessSpecifier(accessSpecifier);
+ baseClass->setVisibility(visibility);
+ }
+ klass->addBaseClass(baseClass);
+ }
+
+ int visibility = semantic()->visibilityForClassKey(classKey);
+ int previousVisibility = semantic()->switchVisibility(visibility);
+ int previousMethodKey = semantic()->switchMethodKey(Function::NormalMethod);
+
+ for (DeclarationAST *member = ast->member_specifiers;
+ member; member = member->next) {
+ semantic()->check(member, klass->members());
+ }
+
+ (void) semantic()->switchMethodKey(previousMethodKey);
+ (void) semantic()->switchVisibility(previousVisibility);
+
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(NamedTypeSpecifierAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ _fullySpecifiedType.setType(control()->namedType(name));
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(ElaboratedTypeSpecifierAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ _fullySpecifiedType.setType(control()->namedType(name));
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(EnumSpecifierAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ Enum *e = control()->newEnum(ast->firstToken(), name);
+ e->setVisibility(semantic()->currentVisibility());
+ _scope->enterSymbol(e);
+ _fullySpecifiedType.setType(e);
+ for (EnumeratorAST *enumerator = ast->enumerators; enumerator;
+ enumerator = enumerator->next) {
+ Identifier *id = identifier(enumerator->identifier_token);
+ if (! id)
+ continue;
+ NameId *enumeratorName = control()->nameId(id);
+ Declaration *decl = control()->newDeclaration(enumerator->firstToken(),
+ enumeratorName);
+ e->addMember(decl);
+ }
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(TypeofSpecifierAST *ast)
+{
+ semantic()->check(ast->expression, _scope);
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(AttributeSpecifierAST *)
+{
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CheckSpecifier.h b/shared/cplusplus/CheckSpecifier.h
new file mode 100644
index 0000000000..72e9073258
--- /dev/null
+++ b/shared/cplusplus/CheckSpecifier.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKSPECIFIER_H
+#define CPLUSPLUS_CHECKSPECIFIER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckSpecifier: public SemanticCheck
+{
+public:
+ CheckSpecifier(Semantic *semantic);
+ virtual ~CheckSpecifier();
+
+ FullySpecifiedType check(SpecifierAST *specifier, Scope *scope);
+
+protected:
+ SpecifierAST *switchSpecifier(SpecifierAST *specifier);
+ FullySpecifiedType switchFullySpecifiedType(FullySpecifiedType type);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(SimpleSpecifierAST *ast);
+ virtual bool visit(ClassSpecifierAST *ast);
+ virtual bool visit(NamedTypeSpecifierAST *ast);
+ virtual bool visit(ElaboratedTypeSpecifierAST *ast);
+ virtual bool visit(EnumSpecifierAST *ast);
+ virtual bool visit(TypeofSpecifierAST *ast);
+ virtual bool visit(AttributeSpecifierAST *ast);
+
+private:
+ SpecifierAST *_specifier;
+ FullySpecifiedType _fullySpecifiedType;
+ Scope *_scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKSPECIFIER_H
diff --git a/shared/cplusplus/CheckStatement.cpp b/shared/cplusplus/CheckStatement.cpp
new file mode 100644
index 0000000000..71ceb25a43
--- /dev/null
+++ b/shared/cplusplus/CheckStatement.cpp
@@ -0,0 +1,239 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckStatement.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "TranslationUnit.h"
+#include "Scope.h"
+#include "CoreTypes.h"
+#include "Control.h"
+#include "Symbols.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckStatement::CheckStatement(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _statement(0),
+ _scope(0)
+{ }
+
+CheckStatement::~CheckStatement()
+{ }
+
+void CheckStatement::check(StatementAST *statement, Scope *scope)
+{
+ Scope *previousScope = switchScope(scope);
+ StatementAST *previousStatement = switchStatement(statement);
+ accept(statement);
+ (void) switchStatement(previousStatement);
+ (void) switchScope(previousScope);
+}
+
+StatementAST *CheckStatement::switchStatement(StatementAST *statement)
+{
+ StatementAST *previousStatement = _statement;
+ _statement = statement;
+ return previousStatement;
+}
+
+Scope *CheckStatement::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckStatement::visit(CaseStatementAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ semantic()->check(ast->statement, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(CompoundStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->lbrace_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ for (StatementAST *it = ast->statements; it; it = it->next) {
+ semantic()->check(it, _scope);
+ }
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(DeclarationStatementAST *ast)
+{
+ semantic()->check(ast->declaration, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(DoStatementAST *ast)
+{
+ semantic()->check(ast->statement, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(ExpressionOrDeclarationStatementAST *ast)
+{
+// translationUnit()->warning(ast->firstToken(),
+// "ambiguous expression or declaration statement");
+ if (ast->declaration)
+ semantic()->check(ast->declaration, _scope);
+ else
+ semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(ExpressionStatementAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(ForStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->for_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ semantic()->check(ast->initializer, _scope);
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(IfStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->if_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ FullySpecifiedType exprTy = semantic()->check(ast->condition, _scope);
+ semantic()->check(ast->statement, _scope);
+ semantic()->check(ast->else_statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(LabeledStatementAST *ast)
+{
+ semantic()->check(ast->statement, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(BreakStatementAST *)
+{
+ return false;
+}
+
+bool CheckStatement::visit(ContinueStatementAST *)
+{
+ return false;
+}
+
+bool CheckStatement::visit(GotoStatementAST *)
+{
+ return false;
+}
+
+bool CheckStatement::visit(ReturnStatementAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(SwitchStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->switch_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(TryBlockStatementAST *ast)
+{
+ semantic()->check(ast->statement, _scope);
+ for (CatchClauseAST *c = ast->catch_clause_seq; c; c = c->next) {
+ semantic()->check(c, _scope);
+ }
+ return false;
+}
+
+bool CheckStatement::visit(CatchClauseAST *ast)
+{
+ Block *block = control()->newBlock(ast->catch_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ semantic()->check(ast->exception_declaration, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(WhileStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->while_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CheckStatement.h b/shared/cplusplus/CheckStatement.h
new file mode 100644
index 0000000000..884c5a9225
--- /dev/null
+++ b/shared/cplusplus/CheckStatement.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKSTATEMENT_H
+#define CPLUSPLUS_CHECKSTATEMENT_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckStatement: public SemanticCheck
+{
+public:
+ CheckStatement(Semantic *semantic);
+ virtual ~CheckStatement();
+
+ void check(StatementAST *statement, Scope *scope);
+
+protected:
+ StatementAST *switchStatement(StatementAST *statement);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(CaseStatementAST *ast);
+ virtual bool visit(CompoundStatementAST *ast);
+ virtual bool visit(DeclarationStatementAST *ast);
+ virtual bool visit(DoStatementAST *ast);
+ virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
+ virtual bool visit(ExpressionStatementAST *ast);
+ virtual bool visit(ForStatementAST *ast);
+ virtual bool visit(IfStatementAST *ast);
+ virtual bool visit(LabeledStatementAST *ast);
+ virtual bool visit(BreakStatementAST *ast);
+ virtual bool visit(ContinueStatementAST *ast);
+ virtual bool visit(GotoStatementAST *ast);
+ virtual bool visit(ReturnStatementAST *ast);
+ virtual bool visit(SwitchStatementAST *ast);
+ virtual bool visit(TryBlockStatementAST *ast);
+ virtual bool visit(CatchClauseAST *ast);
+ virtual bool visit(WhileStatementAST *ast);
+
+private:
+ StatementAST *_statement;
+ Scope *_scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKSTATEMENT_H
diff --git a/shared/cplusplus/Control.cpp b/shared/cplusplus/Control.cpp
new file mode 100644
index 0000000000..f8bd8ea510
--- /dev/null
+++ b/shared/cplusplus/Control.cpp
@@ -0,0 +1,630 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Control.h"
+#include "MemoryPool.h"
+#include "Literals.h"
+#include "LiteralTable.h"
+#include "TranslationUnit.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Names.h"
+#include "Array.h"
+#include <map> // ### replace me with LiteralTable
+#include <string>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+template <typename _Iterator>
+static void delete_map_entries(_Iterator first, _Iterator last)
+{
+ for (; first != last; ++first)
+ delete first->second;
+}
+
+template <typename _Map>
+static void delete_map_entries(const _Map &m)
+{ delete_map_entries(m.begin(), m.end()); }
+
+template <typename _Iterator>
+static void delete_array_entries(_Iterator first, _Iterator last)
+{
+ for (; first != last; ++first)
+ delete *first;
+}
+
+template <typename _Array>
+static void delete_array_entries(const _Array &a)
+{ delete_array_entries(a.begin(), a.end()); }
+
+class Control::Data
+{
+public:
+ Data(Control *control)
+ : control(control),
+ translationUnit(0),
+ diagnosticClient(0)
+ { }
+
+ ~Data()
+ {
+ // names
+ delete_map_entries(nameIds);
+ delete_map_entries(destructorNameIds);
+ delete_map_entries(operatorNameIds);
+ delete_map_entries(conversionNameIds);
+ delete_map_entries(qualifiedNameIds);
+ delete_map_entries(templateNameIds);
+
+ // types
+ delete_map_entries(integerTypes);
+ delete_map_entries(floatTypes);
+ delete_map_entries(pointerToMemberTypes);
+ delete_map_entries(pointerTypes);
+ delete_map_entries(referenceTypes);
+ delete_map_entries(arrayTypes);
+ delete_map_entries(namedTypes);
+
+ // symbols
+ delete_array_entries(declarations);
+ delete_array_entries(arguments);
+ delete_array_entries(functions);
+ delete_array_entries(baseClasses);
+ delete_array_entries(blocks);
+ delete_array_entries(classes);
+ delete_array_entries(namespaces);
+ delete_array_entries(usingNamespaceDirectives);
+ delete_array_entries(enums);
+ delete_array_entries(usingDeclarations);
+ }
+
+ NameId *findOrInsertNameId(Identifier *id)
+ {
+ if (! id)
+ return 0;
+ std::map<Identifier *, NameId *>::iterator it = nameIds.lower_bound(id);
+ if (it == nameIds.end() || it->first != id)
+ it = nameIds.insert(it, std::make_pair(id, new NameId(id)));
+ return it->second;
+ }
+
+ TemplateNameId *findOrInsertTemplateNameId(Identifier *id,
+ const std::vector<FullySpecifiedType> &templateArguments)
+ {
+ if (! id)
+ return 0;
+ const TemplateNameIdKey key(id, templateArguments);
+ std::map<TemplateNameIdKey, TemplateNameId *>::iterator it =
+ templateNameIds.lower_bound(key);
+ if (it == templateNameIds.end() || it->first != key) {
+ const FullySpecifiedType *args = 0;
+ if (templateArguments.size())
+ args = &templateArguments[0];
+ TemplateNameId *templ = new TemplateNameId(id, args,
+ templateArguments.size());
+ it = templateNameIds.insert(it, std::make_pair(key, templ));
+ }
+ return it->second;
+ }
+
+ DestructorNameId *findOrInsertDestructorNameId(Identifier *id)
+ {
+ if (! id)
+ return 0;
+ std::map<Identifier *, DestructorNameId *>::iterator it = destructorNameIds.lower_bound(id);
+ if (it == destructorNameIds.end() || it->first != id)
+ it = destructorNameIds.insert(it, std::make_pair(id, new DestructorNameId(id)));
+ return it->second;
+ }
+
+ OperatorNameId *findOrInsertOperatorNameId(int kind)
+ {
+ const int key(kind);
+ std::map<int, OperatorNameId *>::iterator it = operatorNameIds.lower_bound(key);
+ if (it == operatorNameIds.end() || it->first != key)
+ it = operatorNameIds.insert(it, std::make_pair(key, new OperatorNameId(kind)));
+ return it->second;
+ }
+
+ ConversionNameId *findOrInsertConversionNameId(FullySpecifiedType type)
+ {
+ std::map<FullySpecifiedType, ConversionNameId *>::iterator it =
+ conversionNameIds.lower_bound(type);
+ if (it == conversionNameIds.end() || it->first != type)
+ it = conversionNameIds.insert(it, std::make_pair(type, new ConversionNameId(type)));
+ return it->second;
+ }
+
+ QualifiedNameId *findOrInsertQualifiedNameId(const std::vector<Name *> &names, bool isGlobal)
+ {
+ const QualifiedNameIdKey key(names, isGlobal);
+ std::map<QualifiedNameIdKey, QualifiedNameId *>::iterator it =
+ qualifiedNameIds.lower_bound(key);
+ if (it == qualifiedNameIds.end() || it->first != key) {
+ QualifiedNameId *name = new QualifiedNameId(&names[0], names.size(), isGlobal);
+ it = qualifiedNameIds.insert(it, std::make_pair(key, name));
+ }
+ return it->second;
+ }
+
+ IntegerType *findOrInsertIntegerType(int kind)
+ {
+ const int key = int(kind);
+ std::map<int, IntegerType *>::iterator it = integerTypes.lower_bound(key);
+ if (it == integerTypes.end() || it->first != key)
+ it = integerTypes.insert(it, std::make_pair(key, new IntegerType(kind)));
+ return it->second;
+ }
+
+ FloatType *findOrInsertFloatType(int kind)
+ {
+ const int key = int(kind);
+ std::map<int, FloatType *>::iterator it = floatTypes.lower_bound(key);
+ if (it == floatTypes.end() || it->first != key)
+ it = floatTypes.insert(it, std::make_pair(key, new FloatType(kind)));
+ return it->second;
+ }
+
+ PointerToMemberType *findOrInsertPointerToMemberType(Name *memberName, FullySpecifiedType elementType)
+ {
+ const PointerToMemberTypeKey key(memberName, elementType);
+ std::map<PointerToMemberTypeKey, PointerToMemberType *>::iterator it =
+ pointerToMemberTypes.lower_bound(key);
+ if (it == pointerToMemberTypes.end() || it->first != key)
+ it = pointerToMemberTypes.insert(it, std::make_pair(key, new PointerToMemberType(memberName, elementType)));
+ return it->second;
+ }
+
+ PointerType *findOrInsertPointerType(FullySpecifiedType elementType)
+ {
+ std::map<FullySpecifiedType, PointerType *>::iterator it =
+ pointerTypes.lower_bound(elementType);
+ if (it == pointerTypes.end() || it->first != elementType)
+ it = pointerTypes.insert(it, std::make_pair(elementType, new PointerType(elementType)));
+ return it->second;
+ }
+
+ ReferenceType *findOrInsertReferenceType(FullySpecifiedType elementType)
+ {
+ std::map<FullySpecifiedType, ReferenceType *>::iterator it =
+ referenceTypes.lower_bound(elementType);
+ if (it == referenceTypes.end() || it->first != elementType)
+ it = referenceTypes.insert(it, std::make_pair(elementType, new ReferenceType(elementType)));
+ return it->second;
+ }
+
+ ArrayType *findOrInsertArrayType(FullySpecifiedType elementType, size_t size)
+ {
+ const ArrayKey key(elementType, size);
+ std::map<ArrayKey, ArrayType *>::iterator it =
+ arrayTypes.lower_bound(key);
+ if (it == arrayTypes.end() || it->first != key)
+ it = arrayTypes.insert(it, std::make_pair(key, new ArrayType(elementType, size)));
+ return it->second;
+ }
+
+ NamedType *findOrInsertNamedType(Name *name)
+ {
+ std::map<Name *, NamedType *>::iterator it = namedTypes.lower_bound(name);
+ if (it == namedTypes.end() || it->first != name)
+ it = namedTypes.insert(it, std::make_pair(name, new NamedType(name)));
+ return it->second;
+ }
+
+ Declaration *newDeclaration(unsigned sourceLocation, Name *name)
+ {
+ Declaration *declaration = new Declaration(translationUnit,
+ sourceLocation, name);
+ declarations.push_back(declaration);
+ return declaration;
+ }
+
+ Argument *newArgument(unsigned sourceLocation, Name *name)
+ {
+ Argument *argument = new Argument(translationUnit,
+ sourceLocation, name);
+ arguments.push_back(argument);
+ return argument;
+ }
+
+ Function *newFunction(unsigned sourceLocation, Name *name)
+ {
+ Function *function = new Function(translationUnit,
+ sourceLocation, name);
+ functions.push_back(function);
+ return function;
+ }
+
+ BaseClass *newBaseClass(unsigned sourceLocation, Name *name)
+ {
+ BaseClass *baseClass = new BaseClass(translationUnit,
+ sourceLocation, name);
+ baseClasses.push_back(baseClass);
+ return baseClass;
+ }
+
+ Block *newBlock(unsigned sourceLocation)
+ {
+ Block *block = new Block(translationUnit, sourceLocation);
+ blocks.push_back(block);
+ return block;
+ }
+
+ Class *newClass(unsigned sourceLocation, Name *name)
+ {
+ Class *klass = new Class(translationUnit,
+ sourceLocation, name);
+ classes.push_back(klass);
+ return klass;
+ }
+
+ Namespace *newNamespace(unsigned sourceLocation, Name *name)
+ {
+ Namespace *ns = new Namespace(translationUnit,
+ sourceLocation, name);
+ namespaces.push_back(ns);
+ return ns;
+ }
+
+ UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, Name *name)
+ {
+ UsingNamespaceDirective *u = new UsingNamespaceDirective(translationUnit,
+ sourceLocation, name);
+ usingNamespaceDirectives.push_back(u);
+ return u;
+ }
+
+ Enum *newEnum(unsigned sourceLocation, Name *name)
+ {
+ Enum *e = new Enum(translationUnit,
+ sourceLocation, name);
+ enums.push_back(e);
+ return e;
+ }
+
+ UsingDeclaration *newUsingDeclaration(unsigned sourceLocation, Name *name)
+ {
+ UsingDeclaration *u = new UsingDeclaration(translationUnit,
+ sourceLocation, name);
+ usingDeclarations.push_back(u);
+ return u;
+ }
+
+ struct TemplateNameIdKey {
+ Identifier *id;
+ std::vector<FullySpecifiedType> templateArguments;
+
+ TemplateNameIdKey(Identifier *id, const std::vector<FullySpecifiedType> &templateArguments)
+ : id(id), templateArguments(templateArguments)
+ { }
+
+ bool operator == (const TemplateNameIdKey &other) const
+ { return id == other.id && templateArguments == other.templateArguments; }
+
+ bool operator != (const TemplateNameIdKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const TemplateNameIdKey &other) const
+ {
+ if (id == other.id)
+ return std::lexicographical_compare(templateArguments.begin(),
+ templateArguments.end(),
+ other.templateArguments.begin(),
+ other.templateArguments.end());
+ return id < other.id;
+ }
+ };
+
+ struct QualifiedNameIdKey {
+ std::vector<Name *> names;
+ bool isGlobal;
+
+ QualifiedNameIdKey(const std::vector<Name *> &names, bool isGlobal) :
+ names(names), isGlobal(isGlobal)
+ { }
+
+ bool operator == (const QualifiedNameIdKey &other) const
+ { return isGlobal == other.isGlobal && names == other.names; }
+
+ bool operator != (const QualifiedNameIdKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const QualifiedNameIdKey &other) const
+ {
+ if (isGlobal == other.isGlobal)
+ return std::lexicographical_compare(names.begin(), names.end(),
+ other.names.begin(), other.names.end());
+ return isGlobal < other.isGlobal;
+ }
+ };
+
+ struct ArrayKey {
+ FullySpecifiedType type;
+ size_t size;
+
+ ArrayKey() :
+ size(0)
+ { }
+
+ ArrayKey(FullySpecifiedType type, size_t size) :
+ type(type), size(size)
+ { }
+
+ bool operator == (const ArrayKey &other) const
+ { return type == other.type && size == other.size; }
+
+ bool operator != (const ArrayKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const ArrayKey &other) const
+ {
+ if (type == other.type)
+ return size < other.size;
+ return type < other.type;
+ }
+ };
+
+ struct PointerToMemberTypeKey {
+ Name *memberName;
+ FullySpecifiedType type;
+
+ PointerToMemberTypeKey()
+ : memberName(0)
+ { }
+
+ PointerToMemberTypeKey(Name *memberName, FullySpecifiedType type)
+ : memberName(memberName), type(type)
+ { }
+
+ bool operator == (const PointerToMemberTypeKey &other) const
+ { return memberName == other.memberName && type == other.type; }
+
+ bool operator != (const PointerToMemberTypeKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const PointerToMemberTypeKey &other) const
+ {
+ if (memberName == other.memberName)
+ return type < other.type;
+ return memberName < other.memberName;
+ }
+ };
+
+ Control *control;
+ TranslationUnit *translationUnit;
+ DiagnosticClient *diagnosticClient;
+ LiteralTable<Identifier> identifiers;
+ LiteralTable<StringLiteral> stringLiterals;
+ LiteralTable<NumericLiteral> numericLiterals;
+ LiteralTable<StringLiteral> fileNames;
+
+ // ### replace std::map with lookup tables. ASAP!
+
+ // names
+ std::map<Identifier *, NameId *> nameIds;
+ std::map<Identifier *, DestructorNameId *> destructorNameIds;
+ std::map<int, OperatorNameId *> operatorNameIds;
+ std::map<FullySpecifiedType, ConversionNameId *> conversionNameIds;
+ std::map<TemplateNameIdKey, TemplateNameId *> templateNameIds;
+ std::map<QualifiedNameIdKey, QualifiedNameId *> qualifiedNameIds;
+
+ // types
+ VoidType voidType;
+ std::map<int, IntegerType *> integerTypes;
+ std::map<int, FloatType *> floatTypes;
+ std::map<PointerToMemberTypeKey, PointerToMemberType *> pointerToMemberTypes;
+ std::map<FullySpecifiedType, PointerType *> pointerTypes;
+ std::map<FullySpecifiedType, ReferenceType *> referenceTypes;
+ std::map<ArrayKey, ArrayType *> arrayTypes;
+ std::map<Name *, NamedType *> namedTypes;
+
+ // symbols
+ std::vector<Declaration *> declarations;
+ std::vector<Argument *> arguments;
+ std::vector<Function *> functions;
+ std::vector<BaseClass *> baseClasses;
+ std::vector<Block *> blocks;
+ std::vector<Class *> classes;
+ std::vector<Namespace *> namespaces;
+ std::vector<UsingNamespaceDirective *> usingNamespaceDirectives;
+ std::vector<Enum *> enums;
+ std::vector<UsingDeclaration *> usingDeclarations;
+};
+
+Control::Control()
+{ d = new Data(this); }
+
+Control::~Control()
+{ delete d; }
+
+TranslationUnit *Control::translationUnit() const
+{ return d->translationUnit; }
+
+TranslationUnit *Control::switchTranslationUnit(TranslationUnit *unit)
+{
+ TranslationUnit *previousTranslationUnit = d->translationUnit;
+ d->translationUnit = unit;
+ return previousTranslationUnit;
+}
+
+DiagnosticClient *Control::diagnosticClient() const
+{ return d->diagnosticClient; }
+
+void Control::setDiagnosticClient(DiagnosticClient *diagnosticClient)
+{ d->diagnosticClient = diagnosticClient; }
+
+Identifier *Control::findOrInsertIdentifier(const char *chars, unsigned size)
+{ return d->identifiers.findOrInsertLiteral(chars, size); }
+
+Identifier *Control::findOrInsertIdentifier(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertIdentifier(chars, length);
+}
+
+StringLiteral *Control::findOrInsertStringLiteral(const char *chars, unsigned size)
+{ return d->stringLiterals.findOrInsertLiteral(chars, size); }
+
+StringLiteral *Control::findOrInsertStringLiteral(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertStringLiteral(chars, length);
+}
+
+NumericLiteral *Control::findOrInsertNumericLiteral(const char *chars, unsigned size)
+{ return d->numericLiterals.findOrInsertLiteral(chars, size); }
+
+NumericLiteral *Control::findOrInsertNumericLiteral(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertNumericLiteral(chars, length);
+}
+
+unsigned Control::fileNameCount() const
+{ return d->fileNames.size(); }
+
+StringLiteral *Control::fileNameAt(unsigned index) const
+{ return d->fileNames.at(index); }
+
+StringLiteral *Control::findOrInsertFileName(const char *chars, unsigned size)
+{ return d->fileNames.findOrInsertLiteral(chars, size); }
+
+StringLiteral *Control::findOrInsertFileName(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertFileName(chars, length);
+}
+
+NameId *Control::nameId(Identifier *id)
+{ return d->findOrInsertNameId(id); }
+
+TemplateNameId *Control::templateNameId(Identifier *id,
+ FullySpecifiedType *const args,
+ unsigned argv)
+{
+ std::vector<FullySpecifiedType> templateArguments(args, args + argv);
+ return d->findOrInsertTemplateNameId(id, templateArguments);
+}
+
+DestructorNameId *Control::destructorNameId(Identifier *id)
+{ return d->findOrInsertDestructorNameId(id); }
+
+OperatorNameId *Control::operatorNameId(int kind)
+{ return d->findOrInsertOperatorNameId(kind); }
+
+ConversionNameId *Control::conversionNameId(FullySpecifiedType type)
+{ return d->findOrInsertConversionNameId(type); }
+
+QualifiedNameId *Control::qualifiedNameId(Name *const *names,
+ unsigned nameCount,
+ bool isGlobal)
+{
+ std::vector<Name *> classOrNamespaceNames(names, names + nameCount);
+ return d->findOrInsertQualifiedNameId(classOrNamespaceNames, isGlobal);
+}
+
+VoidType *Control::voidType()
+{ return &d->voidType; }
+
+IntegerType *Control::integerType(int kind)
+{ return d->findOrInsertIntegerType(kind); }
+
+FloatType *Control::floatType(int kind)
+{ return d->findOrInsertFloatType(kind); }
+
+PointerToMemberType *Control::pointerToMemberType(Name *memberName, FullySpecifiedType elementType)
+{ return d->findOrInsertPointerToMemberType(memberName, elementType); }
+
+PointerType *Control::pointerType(FullySpecifiedType elementType)
+{ return d->findOrInsertPointerType(elementType); }
+
+ReferenceType *Control::referenceType(FullySpecifiedType elementType)
+{ return d->findOrInsertReferenceType(elementType); }
+
+ArrayType *Control::arrayType(FullySpecifiedType elementType, size_t size)
+{ return d->findOrInsertArrayType(elementType, size); }
+
+NamedType *Control::namedType(Name *name)
+{ return d->findOrInsertNamedType(name); }
+
+Argument *Control::newArgument(unsigned sourceLocation, Name *name)
+{ return d->newArgument(sourceLocation, name); }
+
+Function *Control::newFunction(unsigned sourceLocation, Name *name)
+{ return d->newFunction(sourceLocation, name); }
+
+Namespace *Control::newNamespace(unsigned sourceLocation, Name *name)
+{ return d->newNamespace(sourceLocation, name); }
+
+BaseClass *Control::newBaseClass(unsigned sourceLocation, Name *name)
+{ return d->newBaseClass(sourceLocation, name); }
+
+Class *Control::newClass(unsigned sourceLocation, Name *name)
+{ return d->newClass(sourceLocation, name); }
+
+Enum *Control::newEnum(unsigned sourceLocation, Name *name)
+{ return d->newEnum(sourceLocation, name); }
+
+Block *Control::newBlock(unsigned sourceLocation)
+{ return d->newBlock(sourceLocation); }
+
+Declaration *Control::newDeclaration(unsigned sourceLocation, Name *name)
+{ return d->newDeclaration(sourceLocation, name); }
+
+UsingNamespaceDirective *Control::newUsingNamespaceDirective(unsigned sourceLocation,
+ Name *name)
+{ return d->newUsingNamespaceDirective(sourceLocation, name); }
+
+UsingDeclaration *Control::newUsingDeclaration(unsigned sourceLocation, Name *name)
+{ return d->newUsingDeclaration(sourceLocation, name); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Control.h b/shared/cplusplus/Control.h
new file mode 100644
index 0000000000..be45afa3c2
--- /dev/null
+++ b/shared/cplusplus/Control.h
@@ -0,0 +1,175 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CONTROL_H
+#define CPLUSPLUS_CONTROL_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Control
+{
+public:
+ Control();
+ ~Control();
+
+ TranslationUnit *translationUnit() const;
+ TranslationUnit *switchTranslationUnit(TranslationUnit *unit);
+
+ DiagnosticClient *diagnosticClient() const;
+ void setDiagnosticClient(DiagnosticClient *diagnosticClient);
+
+ /// Returns the canonical name id.
+ NameId *nameId(Identifier *id);
+
+ /// Returns the canonical template name id.
+ TemplateNameId *templateNameId(Identifier *id,
+ FullySpecifiedType *const args = 0,
+ unsigned argc = 0);
+
+ /// Returns the canonical destructor name id.
+ DestructorNameId *destructorNameId(Identifier *id);
+
+ /// Returns the canonical operator name id.
+ OperatorNameId *operatorNameId(int operatorId);
+
+ /// Returns the canonical conversion name id.
+ ConversionNameId *conversionNameId(FullySpecifiedType type);
+
+ /// Returns the canonical qualified name id.
+ QualifiedNameId *qualifiedNameId(Name *const *names,
+ unsigned nameCount,
+ bool isGlobal = false);
+
+ /// Returns a Type object of type VoidType.
+ VoidType *voidType();
+
+ /// Returns a Type object of type IntegerType.
+ IntegerType *integerType(int integerId);
+
+ /// Returns a Type object of type FloatType.
+ FloatType *floatType(int floatId);
+
+ /// Returns a Type object of type PointertoMemberType.
+ PointerToMemberType *pointerToMemberType(Name *memberName,
+ FullySpecifiedType elementType);
+
+ /// Returns a Type object of type PointerType.
+ PointerType *pointerType(FullySpecifiedType elementType);
+
+ /// Returns a Type object of type ReferenceType.
+ ReferenceType *referenceType(FullySpecifiedType elementType);
+
+ /// Retruns a Type object of type ArrayType.
+ ArrayType *arrayType(FullySpecifiedType elementType, size_t size = 0);
+
+ /// Returns a Type object of type NamedType.
+ NamedType *namedType(Name *name);
+
+ /// Creates a new Declaration symbol.
+ Declaration *newDeclaration(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Argument symbol.
+ Argument *newArgument(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Function symbol.
+ Function *newFunction(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Namespace symbol.
+ Namespace *newNamespace(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new BaseClass symbol.
+ BaseClass *newBaseClass(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Class symbol.
+ Class *newClass(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Enum symbol.
+ Enum *newEnum(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Block symbol.
+ Block *newBlock(unsigned sourceLocation);
+
+ /// Creates a new UsingNamespaceDirective symbol.
+ UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new UsingDeclaration symbol.
+ UsingDeclaration *newUsingDeclaration(unsigned sourceLocation, Name *name = 0);
+
+ Identifier *findOrInsertIdentifier(const char *chars, unsigned size);
+ Identifier *findOrInsertIdentifier(const char *chars);
+
+ StringLiteral *findOrInsertStringLiteral(const char *chars, unsigned size);
+ StringLiteral *findOrInsertStringLiteral(const char *chars);
+
+ NumericLiteral *findOrInsertNumericLiteral(const char *chars, unsigned size);
+ NumericLiteral *findOrInsertNumericLiteral(const char *chars);
+
+ StringLiteral *findOrInsertFileName(const char *chars, unsigned size);
+ StringLiteral *findOrInsertFileName(const char *chars);
+
+ unsigned fileNameCount() const;
+ StringLiteral *fileNameAt(unsigned index) const;
+
+private:
+ class Data;
+ friend class Data;
+ Data *d;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CONTROL_H
diff --git a/shared/cplusplus/CoreTypes.cpp b/shared/cplusplus/CoreTypes.cpp
new file mode 100644
index 0000000000..6bcaf91053
--- /dev/null
+++ b/shared/cplusplus/CoreTypes.cpp
@@ -0,0 +1,237 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CoreTypes.h"
+#include "TypeVisitor.h"
+#include "Names.h"
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+
+bool VoidType::isEqualTo(const Type *other) const
+{
+ const VoidType *o = other->asVoidType();
+ return o != 0;
+}
+
+void VoidType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+PointerToMemberType::PointerToMemberType(Name *memberName, FullySpecifiedType elementType)
+ : _memberName(memberName),
+ _elementType(elementType)
+{ }
+
+PointerToMemberType::~PointerToMemberType()
+{ }
+
+Name *PointerToMemberType::memberName() const
+{ return _memberName; }
+
+FullySpecifiedType PointerToMemberType::elementType() const
+{ return _elementType; }
+
+bool PointerToMemberType::isEqualTo(const Type *other) const
+{
+ const PointerToMemberType *o = other->asPointerToMemberType();
+ if (! o)
+ return false;
+ else if (! _memberName->isEqualTo(o->_memberName))
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void PointerToMemberType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+PointerType::PointerType(FullySpecifiedType elementType)
+ : _elementType(elementType)
+{ }
+
+PointerType::~PointerType()
+{ }
+
+bool PointerType::isEqualTo(const Type *other) const
+{
+ const PointerType *o = other->asPointerType();
+ if (! o)
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void PointerType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType PointerType::elementType() const
+{ return _elementType; }
+
+ReferenceType::ReferenceType(FullySpecifiedType elementType)
+ : _elementType(elementType)
+{ }
+
+ReferenceType::~ReferenceType()
+{ }
+
+bool ReferenceType::isEqualTo(const Type *other) const
+{
+ const ReferenceType *o = other->asReferenceType();
+ if (! o)
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void ReferenceType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType ReferenceType::elementType() const
+{ return _elementType; }
+
+IntegerType::IntegerType(int kind)
+ : _kind(kind)
+{ }
+
+IntegerType::~IntegerType()
+{ }
+
+bool IntegerType::isEqualTo(const Type *other) const
+{
+ const IntegerType *o = other->asIntegerType();
+ if (! o)
+ return false;
+ return _kind == o->_kind;
+}
+
+void IntegerType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+int IntegerType::kind() const
+{ return _kind; }
+
+FloatType::FloatType(int kind)
+ : _kind(kind)
+{ }
+
+FloatType::~FloatType()
+{ }
+
+void FloatType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+int FloatType::kind() const
+{ return _kind; }
+
+bool FloatType::isEqualTo(const Type *other) const
+{
+ const FloatType *o = other->asFloatType();
+ if (! o)
+ return false;
+ return _kind == o->_kind;
+}
+
+ArrayType::ArrayType(FullySpecifiedType elementType, size_t size)
+ : _elementType(elementType), _size(size)
+{ }
+
+ArrayType::~ArrayType()
+{ }
+
+bool ArrayType::isEqualTo(const Type *other) const
+{
+ const ArrayType *o = other->asArrayType();
+ if (! o)
+ return false;
+ else if (_size != o->_size)
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void ArrayType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType ArrayType::elementType() const
+{ return _elementType; }
+
+size_t ArrayType::size() const
+{ return _size; }
+
+NamedType::NamedType(Name *name)
+ : _name(name)
+{ }
+
+NamedType::~NamedType()
+{ }
+
+Name *NamedType::name() const
+{ return _name; }
+
+bool NamedType::isEqualTo(const Type *other) const
+{
+ const NamedType *o = other->asNamedType();
+ if (! o)
+ return false;
+
+ Name *name = _name;
+ if (QualifiedNameId *q = name->asQualifiedNameId())
+ name = q->unqualifiedNameId();
+
+ Name *otherName = o->name();
+ if (QualifiedNameId *q = otherName->asQualifiedNameId())
+ otherName = q->unqualifiedNameId();
+
+ return name->isEqualTo(otherName);
+}
+
+void NamedType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/CoreTypes.h b/shared/cplusplus/CoreTypes.h
new file mode 100644
index 0000000000..4a516870d3
--- /dev/null
+++ b/shared/cplusplus/CoreTypes.h
@@ -0,0 +1,217 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CORETYPES_H
+#define CPLUSPLUS_CORETYPES_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Type.h"
+#include "FullySpecifiedType.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT VoidType: public Type
+{
+public:
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT IntegerType: public Type
+{
+public:
+ enum Kind {
+ Char,
+ WideChar,
+ Bool,
+ Short,
+ Int,
+ Long,
+ LongLong
+ };
+
+public:
+ IntegerType(int kind);
+ virtual ~IntegerType();
+
+ int kind() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ int _kind;
+};
+
+class CPLUSPLUS_EXPORT FloatType: public Type
+{
+public:
+ enum Kind {
+ Float,
+ Double,
+ LongDouble
+ };
+
+public:
+ FloatType(int kind);
+ virtual ~FloatType();
+
+ int kind() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ int _kind;
+};
+
+class CPLUSPLUS_EXPORT PointerType: public Type
+{
+public:
+ PointerType(FullySpecifiedType elementType);
+ virtual ~PointerType();
+
+ FullySpecifiedType elementType() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ FullySpecifiedType _elementType;
+};
+
+class CPLUSPLUS_EXPORT PointerToMemberType: public Type
+{
+public:
+ PointerToMemberType(Name *memberName, FullySpecifiedType elementType);
+ virtual ~PointerToMemberType();
+
+ Name *memberName() const;
+ FullySpecifiedType elementType() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Name *_memberName;
+ FullySpecifiedType _elementType;
+};
+
+class CPLUSPLUS_EXPORT ReferenceType: public Type
+{
+public:
+ ReferenceType(FullySpecifiedType elementType);
+ virtual ~ReferenceType();
+
+ FullySpecifiedType elementType() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ FullySpecifiedType _elementType;
+};
+
+class CPLUSPLUS_EXPORT ArrayType: public Type
+{
+public:
+ ArrayType(FullySpecifiedType elementType, size_t size);
+ virtual ~ArrayType();
+
+ FullySpecifiedType elementType() const;
+ size_t size() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ FullySpecifiedType _elementType;
+ size_t _size;
+};
+
+class CPLUSPLUS_EXPORT NamedType: public Type
+{
+public:
+ NamedType(Name *name);
+ virtual ~NamedType();
+
+ Name *name() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Name *_name;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CORETYPES_H
diff --git a/shared/cplusplus/DiagnosticClient.cpp b/shared/cplusplus/DiagnosticClient.cpp
new file mode 100644
index 0000000000..f44f23f158
--- /dev/null
+++ b/shared/cplusplus/DiagnosticClient.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "DiagnosticClient.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+DiagnosticClient::DiagnosticClient()
+{ }
+
+DiagnosticClient::~DiagnosticClient()
+{ }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/DiagnosticClient.h b/shared/cplusplus/DiagnosticClient.h
new file mode 100644
index 0000000000..1bc4bd9d45
--- /dev/null
+++ b/shared/cplusplus/DiagnosticClient.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_DIAGNOSTICCLIENT_H
+#define CPLUSPLUS_DIAGNOSTICCLIENT_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstdarg>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT DiagnosticClient
+{
+ DiagnosticClient(const DiagnosticClient &other);
+ void operator =(const DiagnosticClient &other);
+
+public:
+ enum Level {
+ Warning,
+ Error,
+ Fatal
+ };
+
+ DiagnosticClient();
+ virtual ~DiagnosticClient();
+
+ virtual void report(int level,
+ StringLiteral *fileName,
+ unsigned line, unsigned column,
+ const char *format, va_list ap) = 0;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_DIAGNOSTICCLIENT_H
diff --git a/shared/cplusplus/FullySpecifiedType.cpp b/shared/cplusplus/FullySpecifiedType.cpp
new file mode 100644
index 0000000000..dd70ec364e
--- /dev/null
+++ b/shared/cplusplus/FullySpecifiedType.cpp
@@ -0,0 +1,204 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "FullySpecifiedType.h"
+#include "Type.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+FullySpecifiedType::FullySpecifiedType(Type *type) :
+ _type(type), _flags(0)
+{ }
+
+FullySpecifiedType::~FullySpecifiedType()
+{ }
+
+bool FullySpecifiedType::isValid() const
+{ return _type != 0; }
+
+Type *FullySpecifiedType::type() const
+{ return _type; }
+
+void FullySpecifiedType::setType(Type *type)
+{ _type = type; }
+
+FullySpecifiedType FullySpecifiedType::qualifiedType() const
+{
+ FullySpecifiedType ty = *this;
+ ty.setFriend(false);
+ ty.setRegister(false);
+ ty.setStatic(false);
+ ty.setExtern(false);
+ ty.setMutable(false);
+ ty.setTypedef(false);
+ return ty;
+}
+
+bool FullySpecifiedType::isConst() const
+{ return _isConst; }
+
+void FullySpecifiedType::setConst(bool isConst)
+{ _isConst = isConst; }
+
+bool FullySpecifiedType::isVolatile() const
+{ return _isVolatile; }
+
+void FullySpecifiedType::setVolatile(bool isVolatile)
+{ _isVolatile = isVolatile; }
+
+bool FullySpecifiedType::isSigned() const
+{ return _isSigned; }
+
+void FullySpecifiedType::setSigned(bool isSigned)
+{ _isSigned = isSigned; }
+
+bool FullySpecifiedType::isUnsigned() const
+{ return _isUnsigned; }
+
+void FullySpecifiedType::setUnsigned(bool isUnsigned)
+{ _isUnsigned = isUnsigned; }
+
+bool FullySpecifiedType::isFriend() const
+{ return _isFriend; }
+
+void FullySpecifiedType::setFriend(bool isFriend)
+{ _isFriend = isFriend; }
+
+bool FullySpecifiedType::isRegister() const
+{ return _isRegister; }
+
+void FullySpecifiedType::setRegister(bool isRegister)
+{ _isRegister = isRegister; }
+
+bool FullySpecifiedType::isStatic() const
+{ return _isStatic; }
+
+void FullySpecifiedType::setStatic(bool isStatic)
+{ _isStatic = isStatic; }
+
+bool FullySpecifiedType::isExtern() const
+{ return _isExtern; }
+
+void FullySpecifiedType::setExtern(bool isExtern)
+{ _isExtern = isExtern; }
+
+bool FullySpecifiedType::isMutable() const
+{ return _isMutable; }
+
+void FullySpecifiedType::setMutable(bool isMutable)
+{ _isMutable = isMutable; }
+
+bool FullySpecifiedType::isTypedef() const
+{ return _isTypedef; }
+
+void FullySpecifiedType::setTypedef(bool isTypedef)
+{ _isTypedef = isTypedef; }
+
+bool FullySpecifiedType::isInline() const
+{ return _isInline; }
+
+void FullySpecifiedType::setInline(bool isInline)
+{ _isInline = isInline; }
+
+bool FullySpecifiedType::isVirtual() const
+{ return _isVirtual; }
+
+void FullySpecifiedType::setVirtual(bool isVirtual)
+{ _isVirtual = isVirtual; }
+
+bool FullySpecifiedType::isExplicit() const
+{ return _isExplicit; }
+
+void FullySpecifiedType::setExplicit(bool isExplicit)
+{ _isExplicit = isExplicit; }
+
+bool FullySpecifiedType::isEqualTo(const FullySpecifiedType &other) const
+{
+ if (_flags != other._flags)
+ return false;
+ if (_type == other._type)
+ return true;
+ else if (! _type)
+ return false;
+ else
+ return _type->isEqualTo(other._type);
+}
+
+Type &FullySpecifiedType::operator*()
+{ return *_type; }
+
+FullySpecifiedType::operator bool() const
+{ return _type != 0; }
+
+const Type &FullySpecifiedType::operator*() const
+{ return *_type; }
+
+Type *FullySpecifiedType::operator->()
+{ return _type; }
+
+const Type *FullySpecifiedType::operator->() const
+{ return _type; }
+
+bool FullySpecifiedType::operator == (const FullySpecifiedType &other) const
+{ return _type == other._type && _flags == other._flags; }
+
+bool FullySpecifiedType::operator != (const FullySpecifiedType &other) const
+{ return ! operator ==(other); }
+
+bool FullySpecifiedType::operator < (const FullySpecifiedType &other) const
+{
+ if (_type == other._type)
+ return _flags < other._flags;
+ return _type < other._type;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/FullySpecifiedType.h b/shared/cplusplus/FullySpecifiedType.h
new file mode 100644
index 0000000000..98951b27fd
--- /dev/null
+++ b/shared/cplusplus/FullySpecifiedType.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_FULLYSPECIFIEDTYPE_H
+#define CPLUSPLUS_FULLYSPECIFIEDTYPE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT FullySpecifiedType
+{
+public:
+ FullySpecifiedType(Type *type = 0);
+ ~FullySpecifiedType();
+
+ bool isValid() const;
+ operator bool() const;
+
+ Type *type() const;
+ void setType(Type *type);
+
+ FullySpecifiedType qualifiedType() const;
+
+ bool isConst() const;
+ void setConst(bool isConst);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isSigned() const;
+ void setSigned(bool isSigned);
+
+ bool isUnsigned() const;
+ void setUnsigned(bool isUnsigned);
+
+ bool isFriend() const;
+ void setFriend(bool isFriend);
+
+ bool isRegister() const;
+ void setRegister(bool isRegister);
+
+ bool isStatic() const;
+ void setStatic(bool isStatic);
+
+ bool isExtern() const;
+ void setExtern(bool isExtern);
+
+ bool isMutable() const;
+ void setMutable(bool isMutable);
+
+ bool isTypedef() const;
+ void setTypedef(bool isTypedef);
+
+ bool isInline() const;
+ void setInline(bool isInline);
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ bool isExplicit() const;
+ void setExplicit(bool isExplicit);
+
+ bool isEqualTo(const FullySpecifiedType &other) const;
+
+ Type &operator*();
+ const Type &operator*() const;
+
+ Type *operator->();
+ const Type *operator->() const;
+
+ bool operator == (const FullySpecifiedType &other) const;
+ bool operator != (const FullySpecifiedType &other) const;
+ bool operator < (const FullySpecifiedType &other) const;
+
+private:
+ Type *_type;
+ union {
+ unsigned _flags;
+ struct {
+ // cv qualifiers
+ unsigned _isConst: 1;
+ unsigned _isVolatile: 1;
+
+ // sign
+ unsigned _isSigned: 1;
+ unsigned _isUnsigned: 1;
+
+ // storage class specifiers
+ unsigned _isFriend: 1;
+ unsigned _isRegister: 1;
+ unsigned _isStatic: 1;
+ unsigned _isExtern: 1;
+ unsigned _isMutable: 1;
+ unsigned _isTypedef: 1;
+
+ // function specifiers
+ unsigned _isInline: 1;
+ unsigned _isVirtual: 1;
+ unsigned _isExplicit: 1;
+ };
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_FULLYSPECIFIEDTYPE_H
diff --git a/shared/cplusplus/Keywords.cpp b/shared/cplusplus/Keywords.cpp
new file mode 100644
index 0000000000..f1c53d3c6a
--- /dev/null
+++ b/shared/cplusplus/Keywords.cpp
@@ -0,0 +1,1211 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Lexer.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+static inline int classify2(const char *s, bool) {
+ if (s[0] == 'd') {
+ if (s[1] == 'o') {
+ return T_DO;
+ }
+ }
+ else if (s[0] == 'i') {
+ if (s[1] == 'f') {
+ return T_IF;
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify3(const char *s, bool) {
+ if (s[0] == 'a') {
+ if (s[1] == 's') {
+ if (s[2] == 'm') {
+ return T_ASM;
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'o') {
+ if (s[2] == 'r') {
+ return T_FOR;
+ }
+ }
+ }
+ else if (s[0] == 'i') {
+ if (s[1] == 'n') {
+ if (s[2] == 't') {
+ return T_INT;
+ }
+ }
+ }
+ else if (s[0] == 'n') {
+ if (s[1] == 'e') {
+ if (s[2] == 'w') {
+ return T_NEW;
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'r') {
+ if (s[2] == 'y') {
+ return T_TRY;
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify4(const char *s, bool q) {
+ if (s[0] == 'a') {
+ if (s[1] == 'u') {
+ if (s[2] == 't') {
+ if (s[3] == 'o') {
+ return T_AUTO;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'b') {
+ if (s[1] == 'o') {
+ if (s[2] == 'o') {
+ if (s[3] == 'l') {
+ return T_BOOL;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'a') {
+ if (s[2] == 's') {
+ if (s[3] == 'e') {
+ return T_CASE;
+ }
+ }
+ }
+ else if (s[1] == 'h') {
+ if (s[2] == 'a') {
+ if (s[3] == 'r') {
+ return T_CHAR;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'e') {
+ if (s[1] == 'l') {
+ if (s[2] == 's') {
+ if (s[3] == 'e') {
+ return T_ELSE;
+ }
+ }
+ }
+ else if (s[1] == 'n') {
+ if (s[2] == 'u') {
+ if (s[3] == 'm') {
+ return T_ENUM;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'g') {
+ if (s[1] == 'o') {
+ if (s[2] == 't') {
+ if (s[3] == 'o') {
+ return T_GOTO;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'l') {
+ if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 'g') {
+ return T_LONG;
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'h') {
+ if (s[2] == 'i') {
+ if (s[3] == 's') {
+ return T_THIS;
+ }
+ }
+ }
+ else if (s[1] == 'r') {
+ if (s[2] == 'u') {
+ if (s[3] == 'e') {
+ return T_TRUE;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'v') {
+ if (s[1] == 'o') {
+ if (s[2] == 'i') {
+ if (s[3] == 'd') {
+ return T_VOID;
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'S') {
+ if (s[1] == 'L') {
+ if (s[2] == 'O') {
+ if (s[3] == 'T') {
+ return T_SLOT;
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify5(const char *s, bool q) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 'm') {
+ return T___ASM;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'b') {
+ if (s[1] == 'r') {
+ if (s[2] == 'e') {
+ if (s[3] == 'a') {
+ if (s[4] == 'k') {
+ return T_BREAK;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'a') {
+ if (s[2] == 't') {
+ if (s[3] == 'c') {
+ if (s[4] == 'h') {
+ return T_CATCH;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'l') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 's') {
+ return T_CLASS;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 's') {
+ if (s[4] == 't') {
+ return T_CONST;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'a') {
+ if (s[2] == 'l') {
+ if (s[3] == 's') {
+ if (s[4] == 'e') {
+ return T_FALSE;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'l') {
+ if (s[2] == 'o') {
+ if (s[3] == 'a') {
+ if (s[4] == 't') {
+ return T_FLOAT;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 'h') {
+ if (s[2] == 'o') {
+ if (s[3] == 'r') {
+ if (s[4] == 't') {
+ return T_SHORT;
+ }
+ }
+ }
+ }
+ else if (q) {
+ if (s[1] == 'l') {
+ if (s[2] == 'o') {
+ if (s[3] == 't') {
+ if (s[4] == 's') {
+ return T_SLOTS;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'h') {
+ if (s[2] == 'r') {
+ if (s[3] == 'o') {
+ if (s[4] == 'w') {
+ return T_THROW;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'u') {
+ if (s[1] == 'n') {
+ if (s[2] == 'i') {
+ if (s[3] == 'o') {
+ if (s[4] == 'n') {
+ return T_UNION;
+ }
+ }
+ }
+ }
+ else if (s[1] == 's') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 'g') {
+ return T_USING;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'w') {
+ if (s[1] == 'h') {
+ if (s[2] == 'i') {
+ if (s[3] == 'l') {
+ if (s[4] == 'e') {
+ return T_WHILE;
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify6(const char *s, bool q) {
+ if (s[0] == 'd') {
+ if (s[1] == 'e') {
+ if (s[2] == 'l') {
+ if (s[3] == 'e') {
+ if (s[4] == 't') {
+ if (s[5] == 'e') {
+ return T_DELETE;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'o') {
+ if (s[2] == 'u') {
+ if (s[3] == 'b') {
+ if (s[4] == 'l') {
+ if (s[5] == 'e') {
+ return T_DOUBLE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'e') {
+ if (s[1] == 'x') {
+ if (s[2] == 'p') {
+ if (s[3] == 'o') {
+ if (s[4] == 'r') {
+ if (s[5] == 't') {
+ return T_EXPORT;
+ }
+ }
+ }
+ }
+ else if (s[2] == 't') {
+ if (s[3] == 'e') {
+ if (s[4] == 'r') {
+ if (s[5] == 'n') {
+ return T_EXTERN;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'r') {
+ if (s[2] == 'i') {
+ if (s[3] == 'e') {
+ if (s[4] == 'n') {
+ if (s[5] == 'd') {
+ return T_FRIEND;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'i') {
+ if (s[1] == 'n') {
+ if (s[2] == 'l') {
+ if (s[3] == 'i') {
+ if (s[4] == 'n') {
+ if (s[5] == 'e') {
+ return T_INLINE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'u') {
+ if (s[2] == 'b') {
+ if (s[3] == 'l') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ return T_PUBLIC;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 't') {
+ if (s[3] == 'u') {
+ if (s[4] == 'r') {
+ if (s[5] == 'n') {
+ return T_RETURN;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 'i') {
+ if (s[2] == 'g') {
+ if (s[3] == 'n') {
+ if (s[4] == 'e') {
+ if (s[5] == 'd') {
+ return T_SIGNED;
+ }
+ }
+ }
+ }
+ else if (s[2] == 'z') {
+ if (s[3] == 'e') {
+ if (s[4] == 'o') {
+ if (s[5] == 'f') {
+ return T_SIZEOF;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 't') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ return T_STATIC;
+ }
+ }
+ }
+ }
+ else if (s[2] == 'r') {
+ if (s[3] == 'u') {
+ if (s[4] == 'c') {
+ if (s[5] == 't') {
+ return T_STRUCT;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'w') {
+ if (s[2] == 'i') {
+ if (s[3] == 't') {
+ if (s[4] == 'c') {
+ if (s[5] == 'h') {
+ return T_SWITCH;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'y') {
+ if (s[2] == 'p') {
+ if (s[3] == 'e') {
+ if (s[4] == 'i') {
+ if (s[5] == 'd') {
+ return T_TYPEID;
+ }
+ }
+ else if (s[4] == 'o') {
+ if (s[5] == 'f') {
+ return T_TYPEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'S') {
+ if (s[1] == 'I') {
+ if (s[2] == 'G') {
+ if (s[3] == 'N') {
+ if (s[4] == 'A') {
+ if (s[5] == 'L') {
+ return T_SIGNAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify7(const char *s, bool q) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 'm') {
+ if (s[5] == '_') {
+ if (s[6] == '_') {
+ return T___ASM__;
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'c') {
+ if (s[3] == 'o') {
+ if (s[4] == 'n') {
+ if (s[5] == 's') {
+ if (s[6] == 't') {
+ return T___CONST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'd') {
+ if (s[1] == 'e') {
+ if (s[2] == 'f') {
+ if (s[3] == 'a') {
+ if (s[4] == 'u') {
+ if (s[5] == 'l') {
+ if (s[6] == 't') {
+ return T_DEFAULT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'm') {
+ if (s[1] == 'u') {
+ if (s[2] == 't') {
+ if (s[3] == 'a') {
+ if (s[4] == 'b') {
+ if (s[5] == 'l') {
+ if (s[6] == 'e') {
+ return T_MUTABLE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'r') {
+ if (s[2] == 'i') {
+ if (s[3] == 'v') {
+ if (s[4] == 'a') {
+ if (s[5] == 't') {
+ if (s[6] == 'e') {
+ return T_PRIVATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 's') {
+ if (s[1] == 'i') {
+ if (s[2] == 'g') {
+ if (s[3] == 'n') {
+ if (s[4] == 'a') {
+ if (s[5] == 'l') {
+ if (s[6] == 's') {
+ return T_SIGNALS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'y') {
+ if (s[2] == 'p') {
+ if (s[3] == 'e') {
+ if (s[4] == 'd') {
+ if (s[5] == 'e') {
+ if (s[6] == 'f') {
+ return T_TYPEDEF;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'v') {
+ if (s[1] == 'i') {
+ if (s[2] == 'r') {
+ if (s[3] == 't') {
+ if (s[4] == 'u') {
+ if (s[5] == 'a') {
+ if (s[6] == 'l') {
+ return T_VIRTUAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'w') {
+ if (s[1] == 'c') {
+ if (s[2] == 'h') {
+ if (s[3] == 'a') {
+ if (s[4] == 'r') {
+ if (s[5] == '_') {
+ if (s[6] == 't') {
+ return T_WCHAR_T;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'Q') {
+ if (s[1] == '_') {
+ if (s[2] == 'S') {
+ if (s[3] == 'L') {
+ if (s[4] == 'O') {
+ if (s[5] == 'T') {
+ if (s[6] == 'S') {
+ return T_SLOTS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify8(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 'l') {
+ if (s[5] == 'i') {
+ if (s[6] == 'n') {
+ if (s[7] == 'e') {
+ return T___INLINE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 't') {
+ if (s[3] == 'y') {
+ if (s[4] == 'p') {
+ if (s[5] == 'e') {
+ if (s[6] == 'o') {
+ if (s[7] == 'f') {
+ return T___TYPEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 't') {
+ if (s[4] == 'i') {
+ if (s[5] == 'n') {
+ if (s[6] == 'u') {
+ if (s[7] == 'e') {
+ return T_CONTINUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'e') {
+ if (s[1] == 'x') {
+ if (s[2] == 'p') {
+ if (s[3] == 'l') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ if (s[6] == 'i') {
+ if (s[7] == 't') {
+ return T_EXPLICIT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'o') {
+ if (s[1] == 'p') {
+ if (s[2] == 'e') {
+ if (s[3] == 'r') {
+ if (s[4] == 'a') {
+ if (s[5] == 't') {
+ if (s[6] == 'o') {
+ if (s[7] == 'r') {
+ return T_OPERATOR;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 'g') {
+ if (s[3] == 'i') {
+ if (s[4] == 's') {
+ if (s[5] == 't') {
+ if (s[6] == 'e') {
+ if (s[7] == 'r') {
+ return T_REGISTER;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'e') {
+ if (s[2] == 'm') {
+ if (s[3] == 'p') {
+ if (s[4] == 'l') {
+ if (s[5] == 'a') {
+ if (s[6] == 't') {
+ if (s[7] == 'e') {
+ return T_TEMPLATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'y') {
+ if (s[2] == 'p') {
+ if (s[3] == 'e') {
+ if (s[4] == 'n') {
+ if (s[5] == 'a') {
+ if (s[6] == 'm') {
+ if (s[7] == 'e') {
+ return T_TYPENAME;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'u') {
+ if (s[1] == 'n') {
+ if (s[2] == 's') {
+ if (s[3] == 'i') {
+ if (s[4] == 'g') {
+ if (s[5] == 'n') {
+ if (s[6] == 'e') {
+ if (s[7] == 'd') {
+ return T_UNSIGNED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'v') {
+ if (s[1] == 'o') {
+ if (s[2] == 'l') {
+ if (s[3] == 'a') {
+ if (s[4] == 't') {
+ if (s[5] == 'i') {
+ if (s[6] == 'l') {
+ if (s[7] == 'e') {
+ return T_VOLATILE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify9(const char *s, bool q) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'c') {
+ if (s[3] == 'o') {
+ if (s[4] == 'n') {
+ if (s[5] == 's') {
+ if (s[6] == 't') {
+ if (s[7] == '_') {
+ if (s[8] == '_') {
+ return T___CONST__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'n') {
+ if (s[1] == 'a') {
+ if (s[2] == 'm') {
+ if (s[3] == 'e') {
+ if (s[4] == 's') {
+ if (s[5] == 'p') {
+ if (s[6] == 'a') {
+ if (s[7] == 'c') {
+ if (s[8] == 'e') {
+ return T_NAMESPACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'r') {
+ if (s[2] == 'o') {
+ if (s[3] == 't') {
+ if (s[4] == 'e') {
+ if (s[5] == 'c') {
+ if (s[6] == 't') {
+ if (s[7] == 'e') {
+ if (s[8] == 'd') {
+ return T_PROTECTED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'Q') {
+ if (s[1] == '_') {
+ if (s[2] == 'S') {
+ if (s[3] == 'I') {
+ if (s[4] == 'G') {
+ if (s[5] == 'N') {
+ if (s[6] == 'A') {
+ if (s[7] == 'L') {
+ if (s[8] == 'S') {
+ return T_SIGNALS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify10(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 'l') {
+ if (s[5] == 'i') {
+ if (s[6] == 'n') {
+ if (s[7] == 'e') {
+ if (s[8] == '_') {
+ if (s[9] == '_') {
+ return T___INLINE__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 't') {
+ if (s[3] == 'y') {
+ if (s[4] == 'p') {
+ if (s[5] == 'e') {
+ if (s[6] == 'o') {
+ if (s[7] == 'f') {
+ if (s[8] == '_') {
+ if (s[9] == '_') {
+ return T___TYPEOF__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'v') {
+ if (s[3] == 'o') {
+ if (s[4] == 'l') {
+ if (s[5] == 'a') {
+ if (s[6] == 't') {
+ if (s[7] == 'i') {
+ if (s[8] == 'l') {
+ if (s[9] == 'e') {
+ return T___VOLATILE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 's') {
+ if (s[4] == 't') {
+ if (s[5] == '_') {
+ if (s[6] == 'c') {
+ if (s[7] == 'a') {
+ if (s[8] == 's') {
+ if (s[9] == 't') {
+ return T_CONST_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify11(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 't') {
+ if (s[5] == 'r') {
+ if (s[6] == 'i') {
+ if (s[7] == 'b') {
+ if (s[8] == 'u') {
+ if (s[9] == 't') {
+ if (s[10] == 'e') {
+ return T___ATTRIBUTE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 't') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ if (s[6] == '_') {
+ if (s[7] == 'c') {
+ if (s[8] == 'a') {
+ if (s[9] == 's') {
+ if (s[10] == 't') {
+ return T_STATIC_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify12(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'v') {
+ if (s[3] == 'o') {
+ if (s[4] == 'l') {
+ if (s[5] == 'a') {
+ if (s[6] == 't') {
+ if (s[7] == 'i') {
+ if (s[8] == 'l') {
+ if (s[9] == 'e') {
+ if (s[10] == '_') {
+ if (s[11] == '_') {
+ return T___VOLATILE__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'd') {
+ if (s[1] == 'y') {
+ if (s[2] == 'n') {
+ if (s[3] == 'a') {
+ if (s[4] == 'm') {
+ if (s[5] == 'i') {
+ if (s[6] == 'c') {
+ if (s[7] == '_') {
+ if (s[8] == 'c') {
+ if (s[9] == 'a') {
+ if (s[10] == 's') {
+ if (s[11] == 't') {
+ return T_DYNAMIC_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify13(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 't') {
+ if (s[5] == 'r') {
+ if (s[6] == 'i') {
+ if (s[7] == 'b') {
+ if (s[8] == 'u') {
+ if (s[9] == 't') {
+ if (s[10] == 'e') {
+ if (s[11] == '_') {
+ if (s[12] == '_') {
+ return T___ATTRIBUTE__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify16(const char *s, bool) {
+ if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 't') {
+ if (s[5] == 'e') {
+ if (s[6] == 'r') {
+ if (s[7] == 'p') {
+ if (s[8] == 'r') {
+ if (s[9] == 'e') {
+ if (s[10] == 't') {
+ if (s[11] == '_') {
+ if (s[12] == 'c') {
+ if (s[13] == 'a') {
+ if (s[14] == 's') {
+ if (s[15] == 't') {
+ return T_REINTERPRET_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+int Lexer::classify(const char *s, int n, bool q) {
+ switch (n) {
+ case 2: return classify2(s, q);
+ case 3: return classify3(s, q);
+ case 4: return classify4(s, q);
+ case 5: return classify5(s, q);
+ case 6: return classify6(s, q);
+ case 7: return classify7(s, q);
+ case 8: return classify8(s, q);
+ case 9: return classify9(s, q);
+ case 10: return classify10(s, q);
+ case 11: return classify11(s, q);
+ case 12: return classify12(s, q);
+ case 13: return classify13(s, q);
+ case 16: return classify16(s, q);
+ default: return T_IDENTIFIER;
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Keywords.kwgen b/shared/cplusplus/Keywords.kwgen
new file mode 100644
index 0000000000..f23b3b7cea
--- /dev/null
+++ b/shared/cplusplus/Keywords.kwgen
@@ -0,0 +1,86 @@
+
+#include "Lexer.h"
+#include "Token.h"
+
+%token-prefix=T_
+%toupper
+%no-enums
+%namespace=Lexer
+
+%%
+__asm
+__asm__
+__attribute
+__attribute__
+__const
+__const__
+__inline
+__inline__
+__typeof
+__typeof__
+__volatile
+__volatile__
+asm
+auto
+bool
+break
+case
+catch
+char
+class
+const
+const_cast
+continue
+default
+delete
+do
+double
+dynamic_cast
+else
+enum
+explicit
+export
+extern
+false
+float
+for
+friend
+goto
+if
+inline
+int
+long
+mutable
+namespace
+new
+operator
+private
+protected
+public
+register
+reinterpret_cast
+return
+short
+signed
+sizeof
+static
+static_cast
+struct
+switch
+template
+this
+throw
+true
+try
+typedef
+typeid
+typename
+typeof
+union
+unsigned
+using
+virtual
+void
+volatile
+wchar_t
+while
diff --git a/shared/cplusplus/Lexer.cpp b/shared/cplusplus/Lexer.cpp
new file mode 100644
index 0000000000..1996bc5ea0
--- /dev/null
+++ b/shared/cplusplus/Lexer.cpp
@@ -0,0 +1,624 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Lexer.h"
+#include "Control.h"
+#include "TranslationUnit.h"
+#include <cctype>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Lexer::Lexer(TranslationUnit *unit)
+ : _translationUnit(unit),
+ _state(Lexer::DefaultState),
+ _flags(0),
+ _currentLine(1)
+{
+ _scanKeywords = true;
+ setSource(_translationUnit->firstSourceChar(),
+ _translationUnit->lastSourceChar());
+}
+
+Lexer::Lexer(const char *firstChar, const char *lastChar)
+ : _translationUnit(0),
+ _state(Lexer::DefaultState),
+ _flags(0),
+ _currentLine(1)
+{
+ _scanKeywords = true;
+ setSource(firstChar, lastChar);
+}
+
+Lexer::~Lexer()
+{ }
+
+TranslationUnit *Lexer::translationUnit() const
+{ return _translationUnit; }
+
+Control *Lexer::control() const
+{
+ if (_translationUnit)
+ return _translationUnit->control();
+
+ return 0;
+}
+
+void Lexer::setSource(const char *firstChar, const char *lastChar)
+{
+ _firstChar = firstChar;
+ _lastChar = lastChar;
+ _currentChar = _firstChar - 1;
+ _tokenStart = _currentChar;
+ _yychar = '\n';
+}
+
+void Lexer::setStartWithNewline(bool enabled)
+{
+ if (enabled)
+ _yychar = '\n';
+ else
+ _yychar = ' ';
+}
+
+int Lexer::state() const
+{ return _state; }
+
+void Lexer::setState(int state)
+{ _state = state; }
+
+bool Lexer::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void Lexer::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+bool Lexer::isIncremental() const
+{ return _isIncremental; }
+
+void Lexer::setIncremental(bool isIncremental)
+{ _isIncremental = isIncremental; }
+
+bool Lexer::scanCommentTokens() const
+{ return _scanCommentTokens; }
+
+void Lexer::setScanCommentTokens(bool onoff)
+{ _scanCommentTokens = onoff; }
+
+bool Lexer::scanKeywords() const
+{ return _scanKeywords; }
+
+void Lexer::setScanKeywords(bool onoff)
+{ _scanKeywords = onoff; }
+
+void Lexer::setScanAngleStringLiteralTokens(bool onoff)
+{ _scanAngleStringLiteralTokens = onoff; }
+
+void Lexer::pushLineStartOffset()
+{
+ ++_currentLine;
+
+ if (_translationUnit)
+ _translationUnit->pushLineOffset(_currentChar - _firstChar);
+}
+
+unsigned Lexer::tokenOffset() const
+{ return _tokenStart - _firstChar; }
+
+unsigned Lexer::tokenLength() const
+{ return _currentChar - _tokenStart; }
+
+const char *Lexer::tokenBegin() const
+{ return _tokenStart; }
+
+const char *Lexer::tokenEnd() const
+{ return _currentChar; }
+
+unsigned Lexer::currentLine() const
+{ return _currentLine; }
+
+void Lexer::scan(Token *tok)
+{
+ tok->reset();
+ scan_helper(tok);
+ tok->length = _currentChar - _tokenStart;
+}
+
+void Lexer::scan_helper(Token *tok)
+{
+ _Lagain:
+ while (_yychar && std::isspace(_yychar)) {
+ if (_yychar == '\n')
+ tok->newline = true;
+ else
+ tok->whitespace = true;
+ yyinp();
+ }
+
+ if (! _translationUnit)
+ tok->lineno = _currentLine;
+
+ _tokenStart = _currentChar;
+ tok->offset = _currentChar - _firstChar;
+
+ if (_state == MultiLineCommentState) {
+ if (! _yychar) {
+ tok->kind = T_EOF_SYMBOL;
+ return;
+ }
+
+ while (_yychar) {
+ if (_yychar != '*')
+ yyinp();
+ else {
+ yyinp();
+ if (_yychar == '/') {
+ yyinp();
+ _state = DefaultState;
+ break;
+ }
+ }
+ }
+
+ if (! _scanCommentTokens)
+ goto _Lagain;
+
+ tok->kind = T_COMMENT;
+ return; // done
+ }
+
+ if (! _yychar) {
+ tok->kind = T_EOF_SYMBOL;
+ return;
+ }
+
+ char ch = _yychar;
+ yyinp();
+
+ switch (ch) {
+ case '\\':
+ while (_yychar != '\n' && std::isspace(_yychar))
+ yyinp();
+ // ### assert(! _yychar || _yychar == '\n');
+ if (_yychar == '\n') {
+ tok->joined = true;
+ tok->newline = false;
+ yyinp();
+ }
+ goto _Lagain;
+
+ case '"': case '\'': {
+ const char quote = ch;
+
+ tok->kind = quote == '"'
+ ? T_STRING_LITERAL
+ : T_CHAR_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != quote) {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == quote);
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == quote)
+ yyinp();
+
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+ } break;
+
+ case '{':
+ tok->kind = T_LBRACE;
+ break;
+
+ case '}':
+ tok->kind = T_RBRACE;
+ break;
+
+ case '[':
+ tok->kind = T_LBRACKET;
+ break;
+
+ case ']':
+ tok->kind = T_RBRACKET;
+ break;
+
+ case '#':
+ if (_yychar == '#') {
+ tok->kind = T_POUND_POUND;
+ yyinp();
+ } else {
+ tok->kind = T_POUND;
+ }
+ break;
+
+ case '(':
+ tok->kind = T_LPAREN;
+ break;
+
+ case ')':
+ tok->kind = T_RPAREN;
+ break;
+
+ case ';':
+ tok->kind = T_SEMICOLON;
+ break;
+
+ case ':':
+ if (_yychar == ':') {
+ yyinp();
+ tok->kind = T_COLON_COLON;
+ } else {
+ tok->kind = T_COLON;
+ }
+ break;
+
+ case '.':
+ if (_yychar == '*') {
+ yyinp();
+ tok->kind = T_DOT_STAR;
+ } else if (_yychar == '.') {
+ yyinp();
+ // ### assert(_yychar);
+ if (_yychar == '.') {
+ yyinp();
+ tok->kind = T_DOT_DOT_DOT;
+ } else {
+ tok->kind = T_ERROR;
+ }
+ } else if (std::isdigit(_yychar)) {
+ const char *yytext = _currentChar - 2;
+ do {
+ if (_yychar == 'e' || _yychar == 'E') {
+ yyinp();
+ if (_yychar == '-' || _yychar == '+') {
+ yyinp();
+ // ### assert(std::isdigit(_yychar));
+ }
+ } else if (std::isalnum(_yychar) || _yychar == '.') {
+ yyinp();
+ } else {
+ break;
+ }
+ } while (_yychar);
+ int yylen = _currentChar - yytext;
+ tok->kind = T_INT_LITERAL;
+ if (control())
+ tok->number = control()->findOrInsertNumericLiteral(yytext, yylen);
+ } else {
+ tok->kind = T_DOT;
+ }
+ break;
+
+ case '?':
+ tok->kind = T_QUESTION;
+ break;
+
+ case '+':
+ if (_yychar == '+') {
+ yyinp();
+ tok->kind = T_PLUS_PLUS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_PLUS_EQUAL;
+ } else {
+ tok->kind = T_PLUS;
+ }
+ break;
+
+ case '-':
+ if (_yychar == '-') {
+ yyinp();
+ tok->kind = T_MINUS_MINUS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_MINUS_EQUAL;
+ } else if (_yychar == '>') {
+ yyinp();
+ if (_yychar == '*') {
+ yyinp();
+ tok->kind = T_ARROW_STAR;
+ } else {
+ tok->kind = T_ARROW;
+ }
+ } else {
+ tok->kind = T_MINUS;
+ }
+ break;
+
+ case '*':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_STAR_EQUAL;
+ } else {
+ tok->kind = T_STAR;
+ }
+ break;
+
+ case '/':
+ if (_yychar == '/') {
+ do {
+ yyinp();
+ } while (_yychar && _yychar != '\n');
+ if (! _scanCommentTokens)
+ goto _Lagain;
+ tok->kind = T_COMMENT;
+ } else if (_yychar == '*') {
+ yyinp();
+ while (_yychar) {
+ if (_yychar != '*') {
+ yyinp();
+ } else {
+ yyinp();
+ if (_yychar == '/')
+ break;
+ }
+ }
+
+ if (_yychar)
+ yyinp();
+ else
+ _state = MultiLineCommentState;
+
+ if (! _scanCommentTokens)
+ goto _Lagain;
+ tok->kind = T_COMMENT;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_SLASH_EQUAL;
+ } else {
+ tok->kind = T_SLASH;
+ }
+ break;
+
+ case '%':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_PERCENT_EQUAL;
+ } else {
+ tok->kind = T_PERCENT;
+ }
+ break;
+
+ case '^':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_CARET_EQUAL;
+ } else {
+ tok->kind = T_CARET;
+ }
+ break;
+
+ case '&':
+ if (_yychar == '&') {
+ yyinp();
+ tok->kind = T_AMPER_AMPER;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_AMPER_EQUAL;
+ } else {
+ tok->kind = T_AMPER;
+ }
+ break;
+
+ case '|':
+ if (_yychar == '|') {
+ yyinp();
+ tok->kind = T_PIPE_PIPE;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_PIPE_EQUAL;
+ } else {
+ tok->kind = T_PIPE;
+ }
+ break;
+
+ case '~':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_TILDE_EQUAL;
+ } else {
+ tok->kind = T_TILDE;
+ }
+ break;
+
+ case '!':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_EXCLAIM_EQUAL;
+ } else {
+ tok->kind = T_EXCLAIM;
+ }
+ break;
+
+ case '=':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_EQUAL_EQUAL;
+ } else {
+ tok->kind = T_EQUAL;
+ }
+ break;
+
+ case '<':
+ if (_scanAngleStringLiteralTokens) {
+ const char *yytext = _currentChar;
+ while (_yychar && _yychar != '>')
+ yyinp();
+ int yylen = _currentChar - yytext;
+ // ### assert(_yychar == '>');
+ if (_yychar == '>')
+ yyinp();
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+ tok->kind = T_ANGLE_STRING_LITERAL;
+ } else if (_yychar == '<') {
+ yyinp();
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_LESS_LESS_EQUAL;
+ } else
+ tok->kind = T_LESS_LESS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_LESS_EQUAL;
+ } else {
+ tok->kind = T_LESS;
+ }
+ break;
+
+ case '>':
+ if (_yychar == '>') {
+ yyinp();
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_GREATER_GREATER_EQUAL;
+ } else
+ tok->kind = T_LESS_LESS;
+ tok->kind = T_GREATER_GREATER;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_GREATER_EQUAL;
+ } else {
+ tok->kind = T_GREATER;
+ }
+ break;
+
+ case ',':
+ tok->kind = T_COMMA;
+ break;
+
+ default: {
+ if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) {
+ // wide char literals
+ ch = _yychar;
+ yyinp();
+
+ const char quote = ch;
+
+ tok->kind = quote == '"'
+ ? T_WIDE_STRING_LITERAL
+ : T_WIDE_CHAR_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != quote) {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == quote);
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == quote)
+ yyinp();
+
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+ } else if (std::isalpha(ch) || ch == '_') {
+ const char *yytext = _currentChar - 1;
+ while (std::isalnum(_yychar) || _yychar == '_')
+ yyinp();
+ int yylen = _currentChar - yytext;
+ if (_scanKeywords)
+ tok->kind = classify(yytext, yylen, _qtMocRunEnabled);
+ else
+ tok->kind = T_IDENTIFIER;
+ if (tok->kind == T_IDENTIFIER && control())
+ tok->identifier = control()->findOrInsertIdentifier(yytext, yylen);
+ break;
+ } else if (std::isdigit(ch)) {
+ const char *yytext = _currentChar - 1;
+ while (_yychar) {
+ if (_yychar == 'e' || _yychar == 'E') {
+ yyinp();
+ if (_yychar == '-' || _yychar == '+') {
+ yyinp();
+ // ### assert(std::isdigit(_yychar));
+ }
+ } else if (std::isalnum(_yychar) || _yychar == '.') {
+ yyinp();
+ } else {
+ break;
+ }
+ }
+ int yylen = _currentChar - yytext;
+ tok->kind = T_INT_LITERAL;
+ if (control())
+ tok->number = control()->findOrInsertNumericLiteral(yytext, yylen);
+ break;
+ } else {
+ tok->kind = T_ERROR;
+ break;
+ }
+ } // default
+
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Lexer.h b/shared/cplusplus/Lexer.h
new file mode 100644
index 0000000000..11d139cf05
--- /dev/null
+++ b/shared/cplusplus/Lexer.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LEXER_H
+#define CPLUSPLUS_LEXER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Lexer
+{
+ Lexer(const Lexer &other);
+ void operator =(const Lexer &other);
+
+public:
+ enum State {
+ DefaultState,
+ MultiLineCommentState
+ };
+
+ Lexer(TranslationUnit *unit);
+ Lexer(const char *firstChar, const char *lastChar);
+ ~Lexer();
+
+ Control *control() const;
+ TranslationUnit *translationUnit() const;
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ void scan(Token *tok);
+
+ inline void operator()(Token *tok)
+ { scan(tok); }
+
+ unsigned tokenOffset() const;
+ unsigned tokenLength() const;
+ const char *tokenBegin() const;
+ const char *tokenEnd() const;
+ unsigned currentLine() const;
+
+ bool scanCommentTokens() const;
+ void setScanCommentTokens(bool onoff);
+
+ bool scanKeywords() const;
+ void setScanKeywords(bool onoff);
+
+ bool scanAngleStringLiteralTokens() const;
+ void setScanAngleStringLiteralTokens(bool onoff);
+
+ void setStartWithNewline(bool enabled);
+
+ int state() const;
+ void setState(int state);
+
+ bool isIncremental() const;
+ void setIncremental(bool isIncremental);
+
+private:
+ void scan_helper(Token *tok);
+ void setSource(const char *firstChar, const char *lastChar);
+ static int classify(const char *string, int length, bool q);
+
+ inline void yyinp()
+ {
+ if (++_currentChar == _lastChar)
+ _yychar = 0;
+ else {
+ _yychar = *_currentChar;
+ if (_yychar == '\n')
+ pushLineStartOffset();
+ }
+ }
+
+ void pushLineStartOffset();
+
+private:
+ TranslationUnit *_translationUnit;
+ const char *_firstChar;
+ const char *_currentChar;
+ const char *_lastChar;
+ const char *_tokenStart;
+ char _yychar;
+ int _state;
+ union {
+ unsigned _flags;
+ struct {
+ unsigned _isIncremental: 1;
+ unsigned _scanCommentTokens: 1;
+ unsigned _scanKeywords: 1;
+ unsigned _scanAngleStringLiteralTokens: 1;
+ unsigned _qtMocRunEnabled: 1;
+ };
+ };
+ unsigned _currentLine;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_LEXER_H
diff --git a/shared/cplusplus/LiteralTable.cpp b/shared/cplusplus/LiteralTable.cpp
new file mode 100644
index 0000000000..8254c2868b
--- /dev/null
+++ b/shared/cplusplus/LiteralTable.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "LiteralTable.h"
diff --git a/shared/cplusplus/LiteralTable.h b/shared/cplusplus/LiteralTable.h
new file mode 100644
index 0000000000..e31930b10c
--- /dev/null
+++ b/shared/cplusplus/LiteralTable.h
@@ -0,0 +1,181 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LITERALTABLE_H
+#define CPLUSPLUS_LITERALTABLE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstring>
+#include <cstdlib>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+template <typename _Literal>
+class LiteralTable
+{
+ LiteralTable(const LiteralTable &other);
+ void operator =(const LiteralTable &other);
+
+public:
+ typedef _Literal **iterator;
+
+public:
+ LiteralTable()
+ : _literals(0),
+ _allocatedLiterals(0),
+ _literalCount(-1),
+ _buckets(0),
+ _allocatedBuckets(0)
+ { }
+
+ ~LiteralTable()
+ {
+ if (_literals) {
+ _Literal **lastLiteral = _literals + _literalCount + 1;
+ for (_Literal **it = _literals; it != lastLiteral; ++it)
+ delete *it;
+ free(_literals);
+ }
+ if (_buckets)
+ free(_buckets);
+ }
+
+ bool empty() const
+ { return _literalCount == -1; }
+
+ unsigned size() const
+ { return _literalCount + 1; }
+
+ _Literal *at(unsigned index) const
+ { return _literals[index]; }
+
+ iterator begin() const
+ { return _literals; }
+
+ iterator end() const
+ { return _literals + _literalCount + 1; }
+
+ _Literal *findOrInsertLiteral(const char *chars, unsigned size)
+ {
+ if (_buckets) {
+ unsigned h = _Literal::hashCode(chars, size);
+ _Literal *literal = _buckets[h % _allocatedBuckets];
+ for (; literal; literal = static_cast<_Literal *>(literal->_next)) {
+ if (literal->size() == size && ! strncmp(literal->chars(), chars, size))
+ return literal;
+ }
+ }
+
+ _Literal *literal = new _Literal(chars, size);
+
+ if (++_literalCount == _allocatedLiterals) {
+ _allocatedLiterals <<= 1;
+
+ if (! _allocatedLiterals)
+ _allocatedLiterals = 256;
+
+ _literals = (_Literal **) realloc(_literals, sizeof(_Literal *) * _allocatedLiterals);
+ }
+
+ _literals[_literalCount] = literal;
+
+ if (! _buckets || _literalCount >= _allocatedBuckets * .6)
+ rehash();
+ else {
+ unsigned h = literal->hashCode() % _allocatedBuckets;
+ literal->_next = _buckets[h];
+ _buckets[h] = literal;
+ }
+
+ return literal;
+ }
+
+protected:
+ void rehash()
+ {
+ if (_buckets)
+ free(_buckets);
+
+ _allocatedBuckets <<= 1;
+
+ if (! _allocatedBuckets)
+ _allocatedBuckets = 256;
+
+ _buckets = (_Literal **) calloc(_allocatedBuckets, sizeof(_Literal *));
+
+ _Literal **lastLiteral = _literals + (_literalCount + 1);
+
+ for (_Literal **it = _literals; it != lastLiteral; ++it) {
+ _Literal *literal = *it;
+ unsigned h = literal->hashCode() % _allocatedBuckets;
+
+ literal->_next = _buckets[h];
+ _buckets[h] = literal;
+ }
+ }
+
+protected:
+ MemoryPool *_pool;
+
+ _Literal **_literals;
+ int _allocatedLiterals;
+ int _literalCount;
+
+ _Literal **_buckets;
+ int _allocatedBuckets;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_LITERALTABLE_H
diff --git a/shared/cplusplus/Literals.cpp b/shared/cplusplus/Literals.cpp
new file mode 100644
index 0000000000..e94d53b565
--- /dev/null
+++ b/shared/cplusplus/Literals.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Literals.h"
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+////////////////////////////////////////////////////////////////////////////////
+Literal::Literal(const char *chars, unsigned size)
+ : _index(0), _next(0)
+{
+ _chars = new char[size + 1];
+
+ strncpy(_chars, chars, size);
+ _chars[size] = '\0';
+
+ _size = size;
+
+ _hashCode = hashCode(_chars, _size);
+}
+
+Literal::~Literal()
+{ delete[] _chars; }
+
+Literal::iterator Literal::begin() const
+{ return _chars; }
+
+Literal::iterator Literal::end() const
+{ return _chars + _size; }
+
+const char *Literal::chars() const
+{ return _chars; }
+
+char Literal::at(unsigned index) const
+{ return _chars[index]; }
+
+unsigned Literal::size() const
+{ return _size; }
+
+unsigned Literal::hashCode() const
+{ return _hashCode; }
+
+unsigned Literal::hashCode(const char *chars, unsigned size)
+{
+ unsigned h = 0;
+ for (unsigned i = 0; i < size; ++i)
+ h = (h >> 5) - h + chars[i];
+ return h;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+StringLiteral::StringLiteral(const char *chars, unsigned size)
+ : Literal(chars, size)
+{ }
+
+StringLiteral::~StringLiteral()
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+NumericLiteral::NumericLiteral(const char *chars, unsigned size)
+ : Literal(chars, size)
+{ }
+
+NumericLiteral::~NumericLiteral()
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+Identifier::Identifier(const char *chars, unsigned size)
+ : Literal(chars, size)
+{ }
+
+Identifier::~Identifier()
+{ }
+
+bool Identifier::isEqualTo(const Identifier *other) const
+{
+ if (this == other)
+ return true;
+ else if (hashCode() != other->hashCode())
+ return false;
+ else if (size() != other->size())
+ return false;
+ return ! strcmp(chars(), other->chars());
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Literals.h b/shared/cplusplus/Literals.h
new file mode 100644
index 0000000000..c5425942da
--- /dev/null
+++ b/shared/cplusplus/Literals.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LITERALS_H
+#define CPLUSPLUS_LITERALS_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Literal
+{
+ Literal(const Literal &other);
+ void operator =(const Literal &other);
+
+public:
+ typedef const char *iterator;
+ typedef iterator const_iterator;
+
+public:
+ Literal(const char *chars, unsigned size);
+ virtual ~Literal();
+
+ iterator begin() const;
+ iterator end() const;
+
+ char at(unsigned index) const;
+ const char *chars() const;
+ unsigned size() const;
+
+ unsigned hashCode() const;
+ static unsigned hashCode(const char *chars, unsigned size);
+
+private:
+ char *_chars;
+ unsigned _size;
+ unsigned _hashCode;
+
+public:
+ // ### private
+ unsigned _index;
+ Literal *_next;
+};
+
+class CPLUSPLUS_EXPORT StringLiteral: public Literal
+{
+public:
+ StringLiteral(const char *chars, unsigned size);
+ virtual ~StringLiteral();
+};
+
+class CPLUSPLUS_EXPORT NumericLiteral: public Literal
+{
+public:
+ NumericLiteral(const char *chars, unsigned size);
+ virtual ~NumericLiteral();
+};
+
+class CPLUSPLUS_EXPORT Identifier: public Literal
+{
+public:
+ Identifier(const char *chars, unsigned size);
+ virtual ~Identifier();
+
+ bool isEqualTo(const Identifier *other) const;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_LITERALS_H
diff --git a/shared/cplusplus/MemoryPool.cpp b/shared/cplusplus/MemoryPool.cpp
new file mode 100644
index 0000000000..6d6876f6f0
--- /dev/null
+++ b/shared/cplusplus/MemoryPool.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "MemoryPool.h"
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+MemoryPool::MemoryPool()
+ : _initializeAllocatedMemory(true),
+ _blocks(0),
+ _allocatedBlocks(0),
+ _blockCount(-1),
+ ptr(0),
+ end(0)
+{ }
+
+MemoryPool::~MemoryPool()
+{
+ if (_blockCount != -1) {
+ for (int i = 0; i < _blockCount + 1; ++i) {
+ free(_blocks[i]);
+ }
+ }
+
+ if (_blocks)
+ free(_blocks);
+}
+
+bool MemoryPool::initializeAllocatedMemory() const
+{ return _initializeAllocatedMemory; }
+
+void MemoryPool::setInitializeAllocatedMemory(bool initializeAllocatedMemory)
+{ _initializeAllocatedMemory = initializeAllocatedMemory; }
+
+void *MemoryPool::allocate_helper(size_t size)
+{
+ assert(size < BLOCK_SIZE);
+
+ if (++_blockCount == _allocatedBlocks) {
+ if (! _allocatedBlocks)
+ _allocatedBlocks = 8;
+ else
+ _allocatedBlocks *= 2;
+
+ _blocks = (char **) realloc(_blocks, sizeof(char *) * _allocatedBlocks);
+ }
+
+ char *&block = _blocks[_blockCount];
+
+ if (_initializeAllocatedMemory)
+ block = (char *) calloc(1, BLOCK_SIZE);
+ else
+ block = (char *) malloc(BLOCK_SIZE);
+
+ ptr = block;
+ end = ptr + BLOCK_SIZE;
+
+ void *addr = ptr;
+ ptr += size;
+ return addr;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/MemoryPool.h b/shared/cplusplus/MemoryPool.h
new file mode 100644
index 0000000000..7479ce6512
--- /dev/null
+++ b/shared/cplusplus/MemoryPool.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_MEMORYPOOL_H
+#define CPLUSPLUS_MEMORYPOOL_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT MemoryPool
+{
+ MemoryPool(const MemoryPool &other);
+ void operator =(const MemoryPool &other);
+
+public:
+ MemoryPool();
+ ~MemoryPool();
+
+ bool initializeAllocatedMemory() const;
+ void setInitializeAllocatedMemory(bool initializeAllocatedMemory);
+
+ inline void *allocate(size_t size)
+ {
+ size = (size + 7) & ~7;
+ if (ptr && (ptr + size < end)) {
+ void *addr = ptr;
+ ptr += size;
+ return addr;
+ }
+ return allocate_helper(size);
+ }
+
+private:
+ void *allocate_helper(size_t size);
+
+private:
+ bool _initializeAllocatedMemory;
+ char **_blocks;
+ int _allocatedBlocks;
+ int _blockCount;
+ char *ptr, *end;
+
+ enum
+ {
+ BLOCK_SIZE = 8 * 1024,
+ DEFAULT_BLOCK_COUNT = 8
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_MEMORYPOOL_H
diff --git a/shared/cplusplus/Name.cpp b/shared/cplusplus/Name.cpp
new file mode 100644
index 0000000000..864428b61c
--- /dev/null
+++ b/shared/cplusplus/Name.cpp
@@ -0,0 +1,133 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Name.h"
+#include "Names.h"
+#include "NameVisitor.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Name::Name()
+{ }
+
+Name::~Name()
+{ }
+
+bool Name::isNameId() const
+{ return dynamic_cast<const NameId *>(this) != 0; }
+
+bool Name::isTemplateNameId() const
+{ return dynamic_cast<const TemplateNameId *>(this) != 0; }
+
+bool Name::isDestructorNameId() const
+{ return dynamic_cast<const DestructorNameId *>(this) != 0; }
+
+bool Name::isOperatorNameId() const
+{ return dynamic_cast<const OperatorNameId *>(this) != 0; }
+
+bool Name::isConversionNameId() const
+{ return dynamic_cast<const ConversionNameId *>(this) != 0; }
+
+bool Name::isQualifiedNameId() const
+{ return dynamic_cast<const QualifiedNameId *>(this) != 0; }
+
+const NameId *Name::asNameId() const
+{ return dynamic_cast<const NameId *>(this); }
+
+const TemplateNameId *Name::asTemplateNameId() const
+{ return dynamic_cast<const TemplateNameId *>(this); }
+
+const DestructorNameId *Name::asDestructorNameId() const
+{ return dynamic_cast<const DestructorNameId *>(this); }
+
+const OperatorNameId *Name::asOperatorNameId() const
+{ return dynamic_cast<const OperatorNameId *>(this); }
+
+const ConversionNameId *Name::asConversionNameId() const
+{ return dynamic_cast<const ConversionNameId *>(this); }
+
+const QualifiedNameId *Name::asQualifiedNameId() const
+{ return dynamic_cast<const QualifiedNameId *>(this); }
+
+NameId *Name::asNameId()
+{ return dynamic_cast<NameId *>(this); }
+
+TemplateNameId *Name::asTemplateNameId()
+{ return dynamic_cast<TemplateNameId *>(this); }
+
+DestructorNameId *Name::asDestructorNameId()
+{ return dynamic_cast<DestructorNameId *>(this); }
+
+OperatorNameId *Name::asOperatorNameId()
+{ return dynamic_cast<OperatorNameId *>(this); }
+
+ConversionNameId *Name::asConversionNameId()
+{ return dynamic_cast<ConversionNameId *>(this); }
+
+QualifiedNameId *Name::asQualifiedNameId()
+{ return dynamic_cast<QualifiedNameId *>(this); }
+
+void Name::accept(NameVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ accept0(visitor);
+ visitor->postVisit(this);
+}
+
+void Name::accept(Name *name, NameVisitor *visitor)
+{
+ if (! name)
+ return;
+ name->accept(visitor);
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Name.h b/shared/cplusplus/Name.h
new file mode 100644
index 0000000000..250a988127
--- /dev/null
+++ b/shared/cplusplus/Name.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_NAME_H
+#define CPLUSPLUS_NAME_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Name
+{
+ Name(const Name &other);
+ void operator =(const Name &other);
+
+public:
+ Name();
+ virtual ~Name();
+
+ bool isNameId() const;
+ bool isTemplateNameId() const;
+ bool isDestructorNameId() const;
+ bool isOperatorNameId() const;
+ bool isConversionNameId() const;
+ bool isQualifiedNameId() const;
+
+ const NameId *asNameId() const;
+ const TemplateNameId *asTemplateNameId() const;
+ const DestructorNameId *asDestructorNameId() const;
+ const OperatorNameId *asOperatorNameId() const;
+ const ConversionNameId *asConversionNameId() const;
+ const QualifiedNameId *asQualifiedNameId() const;
+
+ NameId *asNameId();
+ TemplateNameId *asTemplateNameId();
+ DestructorNameId *asDestructorNameId();
+ OperatorNameId *asOperatorNameId();
+ ConversionNameId *asConversionNameId();
+ QualifiedNameId *asQualifiedNameId();
+
+ virtual bool isEqualTo(const Name *other) const = 0;
+
+ void accept(NameVisitor *visitor);
+ static void accept(Name *name, NameVisitor *visitor);
+
+protected:
+ virtual void accept0(NameVisitor *visitor) = 0;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_NAME_H
diff --git a/shared/cplusplus/NameVisitor.cpp b/shared/cplusplus/NameVisitor.cpp
new file mode 100644
index 0000000000..bc6f45f436
--- /dev/null
+++ b/shared/cplusplus/NameVisitor.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "NameVisitor.h"
+#include "Names.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+NameVisitor::NameVisitor()
+{ }
+
+NameVisitor::~NameVisitor()
+{ }
+
+void NameVisitor::accept(Name *name)
+{ Name::accept(name, this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/NameVisitor.h b/shared/cplusplus/NameVisitor.h
new file mode 100644
index 0000000000..24948bfa42
--- /dev/null
+++ b/shared/cplusplus/NameVisitor.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_NAMEVISITOR_H
+#define CPLUSPLUS_NAMEVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT NameVisitor
+{
+ NameVisitor(const NameVisitor &other);
+ void operator =(const NameVisitor &other);
+
+public:
+ NameVisitor();
+ virtual ~NameVisitor();
+
+ void accept(Name *name);
+
+ virtual bool preVisit(Name *) { return true; }
+ virtual void postVisit(Name *) {}
+
+ virtual void visit(NameId *) {}
+ virtual void visit(TemplateNameId *) {}
+ virtual void visit(DestructorNameId *) {}
+ virtual void visit(OperatorNameId *) {}
+ virtual void visit(ConversionNameId *) {}
+ virtual void visit(QualifiedNameId *) {}
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_NAMEVISITOR_H
diff --git a/shared/cplusplus/Names.cpp b/shared/cplusplus/Names.cpp
new file mode 100644
index 0000000000..b4e951ba49
--- /dev/null
+++ b/shared/cplusplus/Names.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Names.h"
+#include "NameVisitor.h"
+#include "Literals.h"
+#include <cstring>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+QualifiedNameId::QualifiedNameId(Name *const names[],
+ unsigned nameCount,
+ bool isGlobal)
+ : _names(0),
+ _nameCount(nameCount),
+ _isGlobal(isGlobal)
+{
+ if (_nameCount) {
+ _names = new Name *[_nameCount];
+ std::copy(&names[0], &names[nameCount], _names);
+ }
+}
+
+QualifiedNameId::~QualifiedNameId()
+{ delete[] _names; }
+
+void QualifiedNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+unsigned QualifiedNameId::nameCount() const
+{ return _nameCount; }
+
+Name *QualifiedNameId::nameAt(unsigned index) const
+{ return _names[index]; }
+
+Name *const *QualifiedNameId::names() const
+{ return _names; }
+
+bool QualifiedNameId::isGlobal() const
+{ return _isGlobal; }
+
+Name *QualifiedNameId::unqualifiedNameId() const
+{
+ if (! _nameCount)
+ return 0;
+
+ return _names[_nameCount - 1];
+}
+
+bool QualifiedNameId::isEqualTo(const Name *other) const
+{
+ const QualifiedNameId *q = other->asQualifiedNameId();
+ if (! q)
+ return false;
+ else if (isGlobal() != q->isGlobal())
+ return false;
+ else {
+ const unsigned count = nameCount();
+ if (count != q->nameCount())
+ return false;
+ for (unsigned i = 0; i < count; ++i) {
+ Name *l = nameAt(i);
+ Name *r = q->nameAt(i);
+ if (! l->isEqualTo(r))
+ return false;
+ }
+ }
+ return true;
+}
+
+NameId::NameId(Identifier *identifier)
+ : _identifier(identifier)
+{ }
+
+NameId::~NameId()
+{ }
+
+void NameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *NameId::identifier() const
+{ return _identifier; }
+
+bool NameId::isEqualTo(const Name *other) const
+{
+ const NameId *nameId = other->asNameId();
+ if (! nameId)
+ return false;
+ Identifier *l = identifier();
+ Identifier *r = nameId->identifier();
+ return l->isEqualTo(r);
+}
+
+DestructorNameId::DestructorNameId(Identifier *identifier)
+ : _identifier(identifier)
+{ }
+
+DestructorNameId::~DestructorNameId()
+{ }
+
+void DestructorNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *DestructorNameId::identifier() const
+{ return _identifier; }
+
+bool DestructorNameId::isEqualTo(const Name *other) const
+{
+ const DestructorNameId *d = other->asDestructorNameId();
+ if (! d)
+ return false;
+ Identifier *l = identifier();
+ Identifier *r = d->identifier();
+ return l->isEqualTo(r);
+}
+
+TemplateNameId::TemplateNameId(Identifier *identifier,
+ const FullySpecifiedType templateArguments[],
+ unsigned templateArgumentCount)
+ : _identifier(identifier),
+ _templateArguments(0),
+ _templateArgumentCount(templateArgumentCount)
+{
+ if (_templateArgumentCount) {
+ _templateArguments = new FullySpecifiedType[_templateArgumentCount];
+ std::copy(&templateArguments[0], &templateArguments[_templateArgumentCount],
+ _templateArguments);
+ }
+}
+
+TemplateNameId::~TemplateNameId()
+{ delete[] _templateArguments; }
+
+void TemplateNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *TemplateNameId::identifier() const
+{ return _identifier; }
+
+unsigned TemplateNameId::templateArgumentCount() const
+{ return _templateArgumentCount; }
+
+const FullySpecifiedType &TemplateNameId::templateArgumentAt(unsigned index) const
+{ return _templateArguments[index]; }
+
+const FullySpecifiedType *TemplateNameId::templateArguments() const
+{ return _templateArguments; }
+
+bool TemplateNameId::isEqualTo(const Name *other) const
+{
+ const TemplateNameId *t = other->asTemplateNameId();
+ if (! t)
+ return false;
+ Identifier *l = identifier();
+ Identifier *r = t->identifier();
+ if (! l->isEqualTo(r))
+ return false;
+ if (_templateArgumentCount != t->_templateArgumentCount)
+ return false;
+ for (unsigned i = 0; i < _templateArgumentCount; ++i) {
+ const FullySpecifiedType &l = _templateArguments[i];
+ const FullySpecifiedType &r = t->_templateArguments[i];
+ if (! l.isEqualTo(r))
+ return false;
+ }
+ return true;
+}
+
+OperatorNameId::OperatorNameId(int kind)
+ : _kind(kind)
+{ }
+
+OperatorNameId::~OperatorNameId()
+{ }
+
+void OperatorNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+int OperatorNameId::kind() const
+{ return _kind; }
+
+bool OperatorNameId::isEqualTo(const Name *other) const
+{
+ const OperatorNameId *o = other->asOperatorNameId();
+ if (! o)
+ return false;
+ return _kind == o->kind();
+}
+
+ConversionNameId::ConversionNameId(FullySpecifiedType type)
+ : _type(type)
+{ }
+
+ConversionNameId::~ConversionNameId()
+{ }
+
+void ConversionNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType ConversionNameId::type() const
+{ return _type; }
+
+bool ConversionNameId::isEqualTo(const Name *other) const
+{
+ const ConversionNameId *c = other->asConversionNameId();
+ if (! c)
+ return false;
+ return _type.isEqualTo(c->type());
+}
+
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Names.h b/shared/cplusplus/Names.h
new file mode 100644
index 0000000000..85059e551e
--- /dev/null
+++ b/shared/cplusplus/Names.h
@@ -0,0 +1,241 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_NAMES_H
+#define CPLUSPLUS_NAMES_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Name.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT QualifiedNameId: public Name
+{
+public:
+ QualifiedNameId(Name *const names[],
+ unsigned nameCount,
+ bool isGlobal = false);
+ virtual ~QualifiedNameId();
+
+ unsigned nameCount() const;
+ Name *nameAt(unsigned index) const;
+ Name *const *names() const;
+ Name *unqualifiedNameId() const;
+
+ bool isGlobal() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Name **_names;
+ unsigned _nameCount;
+ bool _isGlobal;
+};
+
+class CPLUSPLUS_EXPORT NameId: public Name
+{
+public:
+ NameId(Identifier *identifier);
+ virtual ~NameId();
+
+ Identifier *identifier() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Identifier *_identifier;
+};
+
+class CPLUSPLUS_EXPORT DestructorNameId: public Name
+{
+public:
+ DestructorNameId(Identifier *identifier);
+ virtual ~DestructorNameId();
+
+ Identifier *identifier() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Identifier *_identifier;
+};
+
+class CPLUSPLUS_EXPORT TemplateNameId: public Name
+{
+public:
+ TemplateNameId(Identifier *identifier,
+ const FullySpecifiedType templateArguments[],
+ unsigned templateArgumentCount);
+ virtual ~TemplateNameId();
+
+ Identifier *identifier() const;
+
+ // ### find a better name
+ unsigned templateArgumentCount() const;
+ const FullySpecifiedType &templateArgumentAt(unsigned index) const;
+ const FullySpecifiedType *templateArguments() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Identifier *_identifier;
+ FullySpecifiedType *_templateArguments;
+ unsigned _templateArgumentCount;
+};
+
+class CPLUSPLUS_EXPORT OperatorNameId: public Name
+{
+public:
+ /*
+ new delete new[] delete[]
+ + - * / % ^ & | ~
+ ! = < > += -= *= /= %=
+ ^= &= |= << >> >>= <<= == !=
+ <= >= && || ++ -- , ->* ->
+ () []
+ */
+ enum Kind {
+ InvalidOp,
+ NewOp,
+ DeleteOp,
+ NewArrayOp,
+ DeleteArrayOp,
+ PlusOp,
+ MinusOp,
+ StarOp,
+ SlashOp,
+ PercentOp,
+ CaretOp,
+ AmpOp,
+ PipeOp,
+ TildeOp,
+ ExclaimOp,
+ EqualOp,
+ LessOp,
+ GreaterOp,
+ PlusEqualOp,
+ MinusEqualOp,
+ StarEqualOp,
+ SlashEqualOp,
+ PercentEqualOp,
+ CaretEqualOp,
+ AmpEqualOp,
+ PipeEqualOp,
+ LessLessOp,
+ GreaterGreaterOp,
+ LessLessEqualOp,
+ GreaterGreaterEqualOp,
+ EqualEqualOp,
+ ExclaimEqualOp,
+ LessEqualOp,
+ GreaterEqualOp,
+ AmpAmpOp,
+ PipePipeOp,
+ PlusPlusOp,
+ MinusMinusOp,
+ CommaOp,
+ ArrowStarOp,
+ ArrowOp,
+ FunctionCallOp,
+ ArrayAccessOp
+ };
+
+public:
+ OperatorNameId(int kind);
+ virtual ~OperatorNameId();
+
+ int kind() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ int _kind;
+};
+
+class CPLUSPLUS_EXPORT ConversionNameId: public Name
+{
+public:
+ ConversionNameId(FullySpecifiedType type);
+ virtual ~ConversionNameId();
+
+ FullySpecifiedType type() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ FullySpecifiedType _type;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_NAMES_H
diff --git a/shared/cplusplus/Parser.cpp b/shared/cplusplus/Parser.cpp
new file mode 100644
index 0000000000..bbd783f818
--- /dev/null
+++ b/shared/cplusplus/Parser.cpp
@@ -0,0 +1,3238 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Parser.h"
+#include "Token.h"
+#include "Lexer.h"
+#include "Control.h"
+#include "AST.h"
+#include "Literals.h"
+#include <cstdlib>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Parser::Parser(TranslationUnit *unit)
+ : _translationUnit(unit),
+ _control(_translationUnit->control()),
+ _pool(_translationUnit->memoryPool()),
+ _tokenIndex(1),
+ _templateArguments(0),
+ _qtMocRunEnabled(false),
+ _inFunctionBody(false)
+{ }
+
+Parser::~Parser()
+{ }
+
+bool Parser::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void Parser::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+bool Parser::switchTemplateArguments(bool templateArguments)
+{
+ bool previousTemplateArguments = _templateArguments;
+ _templateArguments = templateArguments;
+ return previousTemplateArguments;
+}
+
+bool Parser::blockErrors(bool block)
+{ return _translationUnit->blockErrors(block); }
+
+bool Parser::skipUntil(int token)
+{
+ while (int tk = LA()) {
+ if (tk == token)
+ return true;
+
+ consumeToken();
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilDeclaration()
+{
+ while (int tk = LA()) {
+ switch (tk) {
+ case T_SEMICOLON:
+ case T_TILDE:
+ case T_COLON_COLON:
+ case T_IDENTIFIER:
+ case T_OPERATOR:
+ case T_CHAR:
+ case T_WCHAR_T:
+ case T_BOOL:
+ case T_SHORT:
+ case T_INT:
+ case T_LONG:
+ case T_SIGNED:
+ case T_UNSIGNED:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_VOID:
+ case T_EXTERN:
+ case T_NAMESPACE:
+ case T_USING:
+ case T_TYPEDEF:
+ case T_ASM:
+ case T_TEMPLATE:
+ case T_EXPORT:
+ case T_CONST:
+ case T_VOLATILE:
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE:
+ return true;
+
+ default:
+ consumeToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilStatement()
+{
+ while (int tk = LA()) {
+ switch (tk) {
+ case T_SEMICOLON:
+ case T_LBRACE:
+ case T_RBRACE:
+ case T_CONST:
+ case T_VOLATILE:
+ case T_IDENTIFIER:
+ case T_CASE:
+ case T_DEFAULT:
+ case T_IF:
+ case T_SWITCH:
+ case T_WHILE:
+ case T_DO:
+ case T_FOR:
+ case T_BREAK:
+ case T_CONTINUE:
+ case T_RETURN:
+ case T_GOTO:
+ case T_TRY:
+ case T_CATCH:
+ case T_THROW:
+ case T_CHAR:
+ case T_WCHAR_T:
+ case T_BOOL:
+ case T_SHORT:
+ case T_INT:
+ case T_LONG:
+ case T_SIGNED:
+ case T_UNSIGNED:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_VOID:
+ case T_CLASS:
+ case T_STRUCT:
+ case T_UNION:
+ case T_ENUM:
+ case T_COLON_COLON:
+ case T_TEMPLATE:
+ case T_USING:
+ return true;
+
+ default:
+ consumeToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skip(int l, int r)
+{
+ int count = 0;
+
+ while (int tk = LA()) {
+ if (tk == l)
+ ++count;
+ else if (tk == r)
+ --count;
+ else if (l != T_LBRACE && (tk == T_LBRACE ||
+ tk == T_RBRACE ||
+ tk == T_SEMICOLON))
+ return false;
+
+ if (count == 0)
+ return true;
+
+ consumeToken();
+ }
+
+ return false;
+}
+
+void Parser::match(int kind, unsigned *token)
+{
+ if (LA() == kind)
+ *token = consumeToken();
+ else {
+ *token = 0;
+ _translationUnit->error(_tokenIndex, "expected token `%s' got `%s'",
+ Token::name(kind), tok().spell());
+ }
+}
+
+bool Parser::parseClassOrNamespaceName(NameAST *&node)
+{
+ if (LA() == T_IDENTIFIER) {
+ unsigned identifier_token = cursor();
+
+ if (LA(2) == T_LESS && parseTemplateId(node) && LA() == T_COLON_COLON)
+ return true;
+
+ rewind(identifier_token);
+
+ if (LA(2) == T_COLON_COLON) {
+ SimpleNameAST *ast = new (_pool) SimpleNameAST;
+ ast->identifier_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ } else if (LA() == T_TEMPLATE) {
+ unsigned template_token = consumeToken();
+ if (parseTemplateId(node))
+ return true;
+ rewind(template_token);
+ }
+ return false;
+}
+
+bool Parser::parseTemplateId(NameAST *&node)
+{
+ if (LA() == T_IDENTIFIER && LA(2) == T_LESS) {
+ TemplateIdAST *ast = new (_pool) TemplateIdAST;
+ ast->identifier_token = consumeToken();
+ ast->less_token = consumeToken();
+ if (LA() == T_GREATER || parseTemplateArgumentList(
+ ast->template_arguments)) {
+ if (LA() == T_GREATER) {
+ ast->greater_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool Parser::parseNestedNameSpecifier(NestedNameSpecifierAST *&node,
+ bool /*acceptTemplateId*/)
+{
+ NestedNameSpecifierAST **nested_name_specifier = &node;
+ NameAST *class_or_namespace_name = 0;
+ if (parseClassOrNamespaceName(class_or_namespace_name) &&
+ LA() == T_COLON_COLON) {
+ unsigned scope_token = consumeToken();
+ *nested_name_specifier = new (_pool) NestedNameSpecifierAST;
+ (*nested_name_specifier)->class_or_namespace_name
+ = class_or_namespace_name;
+ (*nested_name_specifier)->scope_token = scope_token;
+
+ nested_name_specifier = &(*nested_name_specifier)->next;
+
+ while (parseClassOrNamespaceName(class_or_namespace_name) &&
+ LA() == T_COLON_COLON) {
+ scope_token = consumeToken();
+ *nested_name_specifier = new (_pool) NestedNameSpecifierAST;
+ (*nested_name_specifier)->class_or_namespace_name = class_or_namespace_name;
+ (*nested_name_specifier)->scope_token = scope_token;
+ nested_name_specifier = &(*nested_name_specifier)->next;
+ }
+
+ // ### ugly hack
+ rewind(scope_token);
+ consumeToken();
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name,
+ bool acceptTemplateId)
+{
+ unsigned start = cursor();
+ if (! parseNestedNameSpecifier(name, acceptTemplateId))
+ rewind(start);
+ return true;
+}
+
+bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
+{
+ unsigned global_scope_token = 0;
+ if (LA() == T_COLON_COLON)
+ global_scope_token = consumeToken();
+
+ NestedNameSpecifierAST *nested_name_specifier = 0;
+ parseNestedNameSpecifierOpt(nested_name_specifier,
+ /*acceptTemplateId=*/ true);
+
+ NameAST *unqualified_name = 0;
+ if (parseUnqualifiedName(unqualified_name,
+ /*acceptTemplateId=*/ acceptTemplateId || nested_name_specifier != 0)) {
+ if (! global_scope_token && ! nested_name_specifier) {
+ node = unqualified_name;
+ return true;
+ }
+
+ QualifiedNameAST *ast = new (_pool) QualifiedNameAST;
+ ast->global_scope_token = global_scope_token;
+ ast->nested_name_specifier = nested_name_specifier;
+ ast->unqualified_name = unqualified_name;
+ node = ast;
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
+{
+ TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
+ DeclarationAST **decl = &ast->declarations;
+
+ while (LA()) {
+ unsigned start_declaration = cursor();
+
+ if (parseDeclaration(*decl)) {
+ if (*decl)
+ decl = &(*decl)->next;
+ } else {
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+ }
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseEmptyDeclaration(DeclarationAST *&node)
+{
+ if (LA() == T_SEMICOLON) {
+ EmptyDeclarationAST *ast = new (_pool) EmptyDeclarationAST;
+ ast->semicolon_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseDeclaration(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_SEMICOLON:
+ return parseEmptyDeclaration(node);
+
+ case T_NAMESPACE:
+ return parseNamespace(node);
+
+ case T_USING:
+ return parseUsing(node);
+
+ case T_ASM:
+ return parseAsmDefinition(node);
+
+ case T_TEMPLATE:
+ case T_EXPORT:
+ return parseTemplateDeclaration(node);
+
+ default:
+ if (LA() == T_EXTERN && LA(2) == T_TEMPLATE)
+ return parseTemplateDeclaration(node);
+ else if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL)
+ return parseLinkageSpecification(node);
+ else
+ return parseSimpleDeclaration(node);
+ } // end switch
+}
+
+bool Parser::parseLinkageSpecification(DeclarationAST *&node)
+{
+ if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
+ LinkageSpecificationAST *ast = new (_pool) LinkageSpecificationAST;
+ ast->extern_token = consumeToken();
+ ast->extern_type = consumeToken();
+
+ if (LA() == T_LBRACE)
+ parseLinkageBody(ast->declaration);
+ else
+ parseDeclaration(ast->declaration);
+
+ node = ast;
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseLinkageBody(DeclarationAST *&node)
+{
+ if (LA() == T_LBRACE) {
+ LinkageBodyAST *ast = new (_pool) LinkageBodyAST;
+ ast->lbrace_token = consumeToken();
+ DeclarationAST **declaration_ptr = &ast->declarations;
+
+ while (int tk = LA()) {
+ if (tk == T_RBRACE)
+ break;
+
+ unsigned start_declaration = cursor();
+ if (parseDeclaration(*declaration_ptr)) {
+ if (*declaration_ptr) // ### remove me
+ declaration_ptr = &(*declaration_ptr)->next;
+ } else {
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+ }
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+// ### rename parseNamespaceAliarOrDeclaration?
+bool Parser::parseNamespace(DeclarationAST *&node)
+{
+ if (LA() != T_NAMESPACE)
+ return false;
+
+ unsigned namespace_token = consumeToken();
+
+ if (LA() == T_IDENTIFIER && LA(2) == T_EQUAL) {
+ NamespaceAliasDefinitionAST *ast =
+ new (_pool) NamespaceAliasDefinitionAST;
+ ast->namespace_token = namespace_token;
+ ast->namespace_name = consumeToken();
+ ast->equal_token = consumeToken();
+ parseName(ast->name);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+
+ NamespaceAST *ast = new (_pool) NamespaceAST;
+ ast->namespace_token = namespace_token;
+ if (LA() == T_IDENTIFIER)
+ ast->identifier_token = consumeToken();
+ SpecifierAST **attr_ptr = &ast->attributes;
+ while (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*attr_ptr);
+ attr_ptr = &(*attr_ptr)->next;
+ }
+ if (LA() == T_LBRACE)
+ parseLinkageBody(ast->linkage_body);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseUsing(DeclarationAST *&node)
+{
+ if (LA() != T_USING)
+ return false;
+
+ if (LA(2) == T_NAMESPACE)
+ return parseUsingDirective(node);
+
+ UsingAST *ast = new (_pool) UsingAST;
+ ast->using_token = consumeToken();
+
+ if (LA() == T_TYPENAME)
+ ast->typename_token = consumeToken();
+
+ parseName(ast->name);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseUsingDirective(DeclarationAST *&node)
+{
+ if (LA() == T_USING && LA(2) == T_NAMESPACE) {
+ UsingDirectiveAST *ast = new (_pool) UsingDirectiveAST;
+ ast->using_token = consumeToken();
+ ast->namespace_token = consumeToken();
+ if (! parseName(ast->name))
+ _translationUnit->warning(cursor(), "expected `namespace name' before `%s'",
+ tok().spell());
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseConversionFunctionId(NameAST *&node)
+{
+ if (LA() != T_OPERATOR)
+ return false;
+ unsigned operator_token = consumeToken();
+ SpecifierAST *type_specifier = 0;
+ if (! parseTypeSpecifier(type_specifier)) {
+ return false;
+ }
+ PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ ConversionFunctionIdAST *ast = new (_pool) ConversionFunctionIdAST;
+ ast->operator_token = operator_token;
+ ast->type_specifier = type_specifier;
+ ast->ptr_operators = ptr_operators;
+ node = ast;
+ return true;
+}
+
+bool Parser::parseOperatorFunctionId(NameAST *&node)
+{
+ if (LA() != T_OPERATOR)
+ return false;
+ unsigned operator_token = consumeToken();
+
+ OperatorAST *op = 0;
+ if (! parseOperator(op))
+ return false;
+
+ OperatorFunctionIdAST *ast = new (_pool) OperatorFunctionIdAST;
+ ast->operator_token = operator_token;
+ ast->op = op;
+ node = ast;
+ return true;
+}
+
+bool Parser::parseTemplateArgumentList(TemplateArgumentListAST *&node)
+{
+ TemplateArgumentListAST **template_argument_ptr = &node;
+ ExpressionAST *template_argument = 0;
+ if (parseTemplateArgument(template_argument)) {
+ *template_argument_ptr = new (_pool) TemplateArgumentListAST;
+ (*template_argument_ptr)->template_argument = template_argument;
+ template_argument_ptr = &(*template_argument_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseTemplateArgument(template_argument)) {
+ *template_argument_ptr = new (_pool) TemplateArgumentListAST;
+ (*template_argument_ptr)->template_argument = template_argument;
+ template_argument_ptr = &(*template_argument_ptr)->next;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseAsmDefinition(DeclarationAST *&node)
+{
+ if (LA() == T_ASM) {
+ AsmDefinitionAST *ast = new (_pool) AsmDefinitionAST;
+ ast->asm_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ if (LA() == T_LPAREN) {
+ ast->lparen_token = cursor();
+ if (skip(T_LPAREN, T_RPAREN))
+ ast->rparen_token = consumeToken();
+ }
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
+{
+ if (! (LA(1) == T_TEMPLATE || ((LA(1) == T_EXPORT || LA(1) == T_EXTERN)
+ && LA(2) == T_TEMPLATE)))
+ return false;
+
+ TemplateDeclarationAST *ast = new (_pool) TemplateDeclarationAST;
+
+ if (LA() == T_EXPORT || LA() == T_EXPORT)
+ ast->export_token = consumeToken();
+
+ ast->template_token = consumeToken();
+
+ if (LA() == T_LESS) {
+ ast->less_token = consumeToken();
+ if (LA() == T_GREATER || parseTemplateParameterList(ast->template_parameters))
+ match(T_GREATER, &ast->greater_token);
+ }
+
+ parseDeclaration(ast->declaration);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseOperator(OperatorAST *&node) // ### FIXME
+{
+ OperatorAST *ast = new (_pool) OperatorAST;
+
+ switch (LA()) {
+ case T_NEW:
+ case T_DELETE: {
+ ast->op_token = consumeToken();
+ if (LA() == T_LBRACKET) {
+ ast->open_token = consumeToken();
+ match(T_RBRACKET, &ast->close_token);
+ }
+ } break;
+
+ case T_PLUS:
+ case T_MINUS:
+ case T_STAR:
+ case T_SLASH:
+ case T_PERCENT:
+ case T_CARET:
+ case T_AMPER:
+ case T_PIPE:
+ case T_TILDE:
+ case T_EXCLAIM:
+ case T_LESS:
+ case T_GREATER:
+ case T_COMMA:
+ case T_AMPER_EQUAL:
+ case T_CARET_EQUAL:
+ case T_SLASH_EQUAL:
+ case T_EQUAL:
+ case T_EQUAL_EQUAL:
+ case T_EXCLAIM_EQUAL:
+ case T_GREATER_EQUAL:
+ case T_GREATER_GREATER_EQUAL:
+ case T_LESS_EQUAL:
+ case T_LESS_LESS_EQUAL:
+ case T_MINUS_EQUAL:
+ case T_PERCENT_EQUAL:
+ case T_PIPE_EQUAL:
+ case T_PLUS_EQUAL:
+ case T_STAR_EQUAL:
+ case T_TILDE_EQUAL:
+ case T_LESS_LESS:
+ case T_GREATER_GREATER:
+ case T_AMPER_AMPER:
+ case T_PIPE_PIPE:
+ case T_PLUS_PLUS:
+ case T_MINUS_MINUS:
+ case T_ARROW_STAR:
+ case T_DOT_STAR:
+ case T_ARROW:
+ ast->op_token = consumeToken();
+ break;
+
+ default:
+ if (LA() == T_LPAREN && LA(2) == T_RPAREN) {
+ ast->op_token = ast->open_token = consumeToken();
+ ast->close_token = consumeToken();
+ } else if (LA() == T_LBRACKET && LA(2) == T_RBRACKET) {
+ ast->op_token = ast->open_token = consumeToken();
+ ast->close_token = consumeToken();
+ } else {
+ return false;
+ }
+ }
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseCvQualifiers(SpecifierAST *&node)
+{
+ unsigned start = cursor();
+ SpecifierAST **ast = &node;
+ while (*ast)
+ ast = &(*ast)->next;
+
+ while (int tk = LA()) {
+ if (tk == T_CONST || tk == T_VOLATILE) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *ast = spec;
+ ast = &(*ast)->next;
+ } else {
+ break;
+ }
+ }
+
+ return start != cursor();
+}
+
+bool Parser::parsePtrOperator(PtrOperatorAST *&node)
+{
+ if (LA() == T_AMPER) {
+ ReferenceAST *ast = new (_pool) ReferenceAST;
+ ast->amp_token = consumeToken();
+ node = ast;
+ return true;
+ } else if (LA() == T_STAR) {
+ PointerAST *ast = new (_pool) PointerAST;
+ ast->star_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ node = ast;
+ return true;
+ } else if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER) {
+ unsigned scope_or_identifier_token = cursor();
+
+ unsigned global_scope_token = 0;
+ if (LA() == T_COLON_COLON)
+ global_scope_token = consumeToken();
+
+ NestedNameSpecifierAST *nested_name_specifier = 0;
+ bool has_nested_name_specifier = parseNestedNameSpecifier(
+ nested_name_specifier, true);
+ if (has_nested_name_specifier && LA() == T_STAR) {
+ PointerToMemberAST *ast = new (_pool) PointerToMemberAST;
+ ast->global_scope_token = global_scope_token;
+ ast->nested_name_specifier = nested_name_specifier;
+ ast->star_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ node = ast;
+ return true;
+ }
+ rewind(scope_or_identifier_token);
+ }
+ return false;
+}
+
+bool Parser::parseTemplateArgument(ExpressionAST *&node)
+{
+ unsigned start = cursor();
+ if (parseTypeId(node) && (LA() == T_COMMA || LA() == T_GREATER))
+ return true;
+
+ rewind(start);
+ bool previousTemplateArguments = switchTemplateArguments(true);
+ bool parsed = parseLogicalOrExpression(node);
+ (void) switchTemplateArguments(previousTemplateArguments);
+ return parsed;
+}
+
+bool Parser::parseDeclSpecifierSeq(SpecifierAST *&decl_specifier_seq,
+ bool onlyTypeSpecifiers,
+ bool simplified)
+{
+ bool has_type_specifier = false;
+ NameAST *named_type_specifier = 0;
+ SpecifierAST **decl_specifier_seq_ptr = &decl_specifier_seq;
+ for (;;) {
+ if (lookAtCVQualifier()) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (! onlyTypeSpecifiers && lookAtStorageClassSpecifier()) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (! named_type_specifier && lookAtBuiltinTypeSpecifier()) {
+ parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && (LA() == T_COLON_COLON ||
+ LA() == T_IDENTIFIER)) {
+ if (! parseName(named_type_specifier))
+ return false;
+ NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
+ spec->name = named_type_specifier;
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! simplified && ! has_type_specifier && (LA() == T_TYPENAME ||
+ LA() == T_ENUM ||
+ lookAtClassKey())) {
+ unsigned startOfElaboratedTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfElaboratedTypeSpecifier,
+ "expected an elaborated type specifier");
+ break;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else
+ break;
+ }
+
+ return decl_specifier_seq != 0;
+}
+
+bool Parser::parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node)
+{
+ unsigned start = cursor();
+ bool blocked = blockErrors(true);
+ if (parseDeclarator(node)) {
+ blockErrors(blocked);
+ return true;
+ }
+ blockErrors(blocked);
+ rewind(start);
+ return parseAbstractDeclarator(node);
+}
+
+bool Parser::parseCoreDeclarator(DeclaratorAST *&node)
+{
+ PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER || LA() == T_TILDE
+ || LA() == T_OPERATOR) {
+ NameAST *name = 0;
+ if (parseName(name)) {
+ DeclaratorIdAST *declarator_id = new (_pool) DeclaratorIdAST;
+ declarator_id->name = name;
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ ast->core_declarator = declarator_id;
+ node = ast;
+ return true;
+ }
+ } else if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ DeclaratorAST *declarator = 0;
+ if (parseDeclarator(declarator) && LA() == T_RPAREN) {
+ NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
+ nested_declarator->lparen_token = lparen_token;
+ nested_declarator->declarator = declarator;
+ nested_declarator->rparen_token = consumeToken();
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ ast->core_declarator = nested_declarator;
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseDeclarator(DeclaratorAST *&node)
+{
+ if (! parseCoreDeclarator(node))
+ return false;
+
+ PostfixDeclaratorAST **postfix_ptr = &node->postfix_declarators;
+
+ for (;;) {
+ unsigned startOfPostDeclarator = cursor();
+
+ if (LA() == T_LPAREN) {
+ FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+ ast->lparen_token = consumeToken();
+ parseParameterDeclarationClause(ast->parameters);
+ if (LA() != T_RPAREN) {
+ rewind(startOfPostDeclarator);
+ break;
+ }
+
+ ast->rparen_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ parseExceptionSpecification(ast->exception_specification);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_LBRACKET) {
+ ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
+ ast->lbracket_token = consumeToken();
+ if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
+ match(T_RBRACKET, &ast->rbracket_token);
+ }
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else
+ break;
+ }
+
+ SpecifierAST **spec_ptr = &node->attributes;
+ while (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*spec_ptr);
+ spec_ptr = &(*spec_ptr)->next;
+ }
+
+ return true;
+}
+
+bool Parser::parseAbstractCoreDeclarator(DeclaratorAST *&node)
+{
+ PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ unsigned after_ptr_operators = cursor();
+
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ DeclaratorAST *declarator = 0;
+ if (parseAbstractDeclarator(declarator) && LA() == T_RPAREN) {
+ NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
+ nested_declarator->lparen_token = lparen_token;
+ nested_declarator->declarator = declarator;
+ nested_declarator->rparen_token = consumeToken();
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ ast->core_declarator = nested_declarator;
+ node = ast;
+ return true;
+ }
+ }
+
+ rewind(after_ptr_operators);
+ if (ptr_operators) {
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseAbstractDeclarator(DeclaratorAST *&node)
+{
+ if (! parseAbstractCoreDeclarator(node))
+ return false;
+
+ PostfixDeclaratorAST *postfix_declarators = 0,
+ **postfix_ptr = &postfix_declarators;
+
+ for (;;) {
+ if (LA() == T_LPAREN) {
+ FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+ ast->lparen_token = consumeToken();
+ if (LA() == T_RPAREN || parseParameterDeclarationClause(ast->parameters)) {
+ if (LA() == T_RPAREN)
+ ast->rparen_token = consumeToken();
+ }
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ parseExceptionSpecification(ast->exception_specification);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_LBRACKET) {
+ ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
+ ast->lbracket_token = consumeToken();
+ if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
+ if (LA() == T_RBRACKET)
+ ast->rbracket_token = consumeToken();
+ }
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else
+ break;
+ }
+
+ if (postfix_declarators) {
+ if (! node)
+ node = new (_pool) DeclaratorAST;
+
+ node->postfix_declarators = postfix_declarators;
+ }
+
+ return true;
+}
+
+bool Parser::parseEnumSpecifier(SpecifierAST *&node)
+{
+ if (LA() == T_ENUM) {
+ unsigned enum_token = consumeToken();
+ NameAST *name = 0;
+ parseName(name);
+ if (LA() == T_LBRACE) {
+ EnumSpecifierAST *ast = new (_pool) EnumSpecifierAST;
+ ast->enum_token = enum_token;
+ ast->name = name;
+ ast->lbrace_token = consumeToken();
+ EnumeratorAST **enumerator_ptr = &ast->enumerators;
+ while (int tk = LA()) {
+ if (tk == T_RBRACE)
+ break;
+
+ if (LA() != T_IDENTIFIER) {
+ _translationUnit->error(cursor(), "expected identifier before '%s'", tok().spell());
+ skipUntil(T_IDENTIFIER);
+ }
+
+ if (parseEnumerator(*enumerator_ptr))
+ enumerator_ptr = &(*enumerator_ptr)->next;
+
+ if (LA() != T_RBRACE) {
+ unsigned comma_token = 0;
+ match(T_COMMA, &comma_token);
+ }
+ }
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseTemplateParameterList(DeclarationAST *&node)
+{
+ DeclarationAST **template_parameter_ptr = &node;
+ if (parseTemplateParameter(*template_parameter_ptr)) {
+ template_parameter_ptr = &(*template_parameter_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseTemplateParameter(*template_parameter_ptr))
+ template_parameter_ptr = &(*template_parameter_ptr)->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTemplateParameter(DeclarationAST *&node)
+{
+ if (parseTypeParameter(node))
+ return true;
+ bool previousTemplateArguments = switchTemplateArguments(true);
+ bool parsed = parseParameterDeclaration(node);
+ (void) switchTemplateArguments(previousTemplateArguments);
+ return parsed;
+}
+
+bool Parser::parseTypenameTypeParameter(DeclarationAST *&node)
+{
+ if (LA() == T_CLASS || LA() == T_TYPENAME) {
+ TypenameTypeParameterAST *ast = new (_pool) TypenameTypeParameterAST;
+ ast->classkey_token = consumeToken();
+ parseName(ast->name);
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseTypeId(ast->type_id);
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
+{
+ if (LA() == T_TEMPLATE) {
+ TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST;
+ ast->template_token = consumeToken();
+ if (LA() == T_LESS)
+ ast->less_token = consumeToken();
+ parseTemplateParameterList(ast->template_parameters);
+ if (LA() == T_GREATER)
+ ast->greater_token = consumeToken();
+ if (LA() == T_CLASS)
+ ast->class_token = consumeToken();
+
+ // parse optional name
+ parseName(ast->name);
+
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseTypeId(ast->type_id);
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTypeParameter(DeclarationAST *&node)
+{
+ if (LA() == T_CLASS || LA() == T_TYPENAME)
+ return parseTypenameTypeParameter(node);
+ else if (LA() == T_TEMPLATE)
+ return parseTemplateTypeParameter(node);
+ else
+ return false;
+}
+
+bool Parser::parseTypeId(ExpressionAST *&node)
+{
+ SpecifierAST *type_specifier = 0;
+ if (parseTypeSpecifier(type_specifier)) {
+ TypeIdAST *ast = new (_pool) TypeIdAST;
+ ast->type_specifier = type_specifier;
+ parseAbstractDeclarator(ast->declarator);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node)
+{
+ DeclarationAST *parameter_declarations = 0;
+ if (LA() != T_DOT_DOT_DOT)
+ parseParameterDeclarationList(parameter_declarations);
+ unsigned dot_dot_dot_token = 0;
+ if (LA() == T_DOT_DOT_DOT || (LA() == T_COMMA && LA(2) == T_DOT_DOT_DOT)) {
+ if (LA() == T_COMMA)
+ consumeToken();
+ dot_dot_dot_token = consumeToken();
+ }
+ ParameterDeclarationClauseAST *ast = new (_pool) ParameterDeclarationClauseAST;
+ ast->parameter_declarations = parameter_declarations;
+ ast->dot_dot_dot_token = dot_dot_dot_token;
+ node = ast;
+ return true;
+}
+
+bool Parser::parseParameterDeclarationList(DeclarationAST *&node)
+{
+ DeclarationAST **parameter_declaration_ptr = &node;
+ if (parseParameterDeclaration(*parameter_declaration_ptr)) {
+ parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (LA() == T_DOT_DOT_DOT)
+ break;
+
+ if (parseParameterDeclaration(*parameter_declaration_ptr))
+ parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseParameterDeclaration(DeclarationAST *&node)
+{
+ SpecifierAST *decl_specifier_seq = 0;
+ if (parseDeclSpecifierSeq(decl_specifier_seq)) {
+ ParameterDeclarationAST *ast = new (_pool) ParameterDeclarationAST;
+ ast->type_specifier = decl_specifier_seq;
+ parseDeclaratorOrAbstractDeclarator(ast->declarator);
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseLogicalOrExpression(ast->expression);
+ }
+
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseClassSpecifier(SpecifierAST *&node)
+{
+ if (! lookAtClassKey())
+ return false;
+
+ unsigned classkey_token = consumeToken();
+
+ SpecifierAST *attributes = 0, **attr_ptr = &attributes;
+ while (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*attr_ptr);
+ attr_ptr = &(*attr_ptr)->next;
+ }
+
+ if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) {
+ _translationUnit->warning(cursor(), "skip identifier `%s'",
+ tok().spell());
+ consumeToken();
+ }
+
+ NameAST *name = 0;
+ parseName(name);
+
+ if (LA() == T_COLON || LA() == T_LBRACE) {
+ BaseSpecifierAST *base_clause = 0;
+ if (LA() == T_COLON) {
+ parseBaseClause(base_clause);
+ if (LA() != T_LBRACE) {
+ _translationUnit->error(cursor(), "expected `{' before `%s'", tok().spell());
+ unsigned saved = cursor();
+ for (int n = 0; n < 3 && LA() != T_EOF_SYMBOL; ++n, consumeToken()) {
+ if (LA() == T_LBRACE)
+ break;
+ }
+ if (LA() != T_LBRACE)
+ rewind(saved);
+ }
+ }
+
+ ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST;
+ ast->classkey_token = classkey_token;
+ ast->attributes = attributes;
+ ast->name = name;
+ ast->base_clause = base_clause;
+
+ if (LA() == T_LBRACE)
+ ast->lbrace_token = consumeToken();
+
+ DeclarationAST **declaration_ptr = &ast->member_specifiers;
+ while (int tk = LA()) {
+ if (tk == T_RBRACE) {
+ ast->rbrace_token = consumeToken();
+ break;
+ }
+
+ unsigned start_declaration = cursor();
+ if (parseMemberSpecification(*declaration_ptr)) {
+ if (*declaration_ptr)
+ declaration_ptr = &(*declaration_ptr)->next;
+ } else {
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseAccessSpecifier(SpecifierAST *&node)
+{
+ switch (LA()) {
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE: {
+ SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
+ ast->specifier_token = consumeToken();
+ node = ast;
+ return true;
+ }
+
+ default:
+ return false;
+ } // switch
+}
+
+bool Parser::parseAccessDeclaration(DeclarationAST *&node)
+{
+ if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_SIGNALS) {
+ bool isSignals = LA() == T_SIGNALS;
+ AccessDeclarationAST *ast = new (_pool) AccessDeclarationAST;
+ ast->access_specifier_token = consumeToken();
+ if (! isSignals && LA() == T_SLOTS)
+ ast->slots_token = consumeToken();
+ match(T_COLON, &ast->colon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseMemberSpecification(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_SEMICOLON:
+ return parseEmptyDeclaration(node);
+
+ case T_USING:
+ return parseUsing(node);
+
+ case T_TEMPLATE:
+ return parseTemplateDeclaration(node);
+
+ case T_SIGNALS:
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE:
+ return parseAccessDeclaration(node);
+
+ default:
+ return parseSimpleDeclaration(node, /*acceptStructDeclarator=*/true);
+ } // switch
+}
+
+bool Parser::parseCtorInitializer(CtorInitializerAST *&node)
+{
+ if (LA() == T_COLON) {
+ unsigned colon_token = consumeToken();
+
+ CtorInitializerAST *ast = new (_pool) CtorInitializerAST;
+ ast->colon_token = colon_token;
+
+ parseMemInitializerList(ast->member_initializers);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseElaboratedTypeSpecifier(SpecifierAST *&node)
+{
+ if (lookAtClassKey() || LA() == T_ENUM || LA() == T_TYPENAME) {
+ unsigned classkey_token = consumeToken();
+ NameAST *name = 0;
+ if (parseName(name)) {
+ ElaboratedTypeSpecifierAST *ast =
+ new (_pool) ElaboratedTypeSpecifierAST;
+
+ ast->classkey_token = classkey_token;
+ ast->name = name;
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node)
+{
+ if (LA() == T_THROW) {
+ ExceptionSpecificationAST *ast = new (_pool) ExceptionSpecificationAST;
+ ast->throw_token = consumeToken();
+ if (LA() == T_LPAREN)
+ ast->lparen_token = consumeToken();
+ if (LA() == T_DOT_DOT_DOT)
+ ast->dot_dot_dot_token = consumeToken();
+ else
+ parseTypeIdList(ast->type_ids);
+ if (LA() == T_RPAREN)
+ ast->rparen_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseEnumerator(EnumeratorAST *&node)
+{
+ if (LA() == T_IDENTIFIER) {
+ EnumeratorAST *ast = new (_pool) EnumeratorAST;
+ ast->identifier_token = consumeToken();
+
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseConstantExpression(ast->expression);
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseInitDeclarator(DeclaratorAST *&node,
+ bool acceptStructDeclarator)
+{
+ unsigned start = cursor();
+
+ if (acceptStructDeclarator && LA() == T_COLON) {
+ // anonymous bit-field declaration.
+ // ### TODO create the AST
+ } else if (! parseDeclarator(node)) {
+ return false;
+ }
+
+ if (LA() == T_ASM && LA(2) == T_LPAREN) { // ### FIXME
+ consumeToken();
+
+ if (skip(T_LPAREN, T_RPAREN))
+ consumeToken();
+ }
+
+ if (acceptStructDeclarator && node &&
+ ! node->postfix_declarators &&
+ node->core_declarator &&
+ node->core_declarator->asNestedDeclarator()) {
+ rewind(start);
+ return false;
+ }
+
+ if (acceptStructDeclarator && LA() == T_COLON
+ && (! node || ! node->postfix_declarators)) {
+ unsigned colon_token = consumeToken();
+ ExpressionAST *expression = 0;
+ if (parseConstantExpression(expression) && (LA() == T_COMMA ||
+ LA() == T_SEMICOLON)) {
+ // recognized a bitfielddeclarator.
+ // ### TODO create the AST
+ return true;
+ }
+ rewind(colon_token);
+ } else if (LA() == T_EQUAL || (! acceptStructDeclarator && LA() == T_LPAREN)) {
+ parseInitializer(node->initializer);
+ }
+ return true;
+}
+
+bool Parser::parseBaseClause(BaseSpecifierAST *&node)
+{
+ if (LA() == T_COLON) {
+ consumeToken();
+
+ BaseSpecifierAST **ast = &node;
+ if (parseBaseSpecifier(*ast)) {
+ ast = &(*ast)->next;
+
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseBaseSpecifier(*ast))
+ ast = &(*ast)->next;
+ }
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseInitializer(ExpressionAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ return parsePrimaryExpression(node);
+ } else if (LA() == T_EQUAL) {
+ consumeToken();
+ return parseInitializerClause(node);
+ }
+ return false;
+}
+
+bool Parser::parseMemInitializerList(MemInitializerAST *&node)
+{
+ MemInitializerAST **initializer = &node;
+
+ if (parseMemInitializer(*initializer)) {
+ initializer = &(*initializer)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+ if (parseMemInitializer(*initializer))
+ initializer = &(*initializer)->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseMemInitializer(MemInitializerAST *&node)
+{
+ NameAST *name = 0;
+ if (parseName(name) && LA() == T_LPAREN) {
+ MemInitializerAST *ast = new (_pool) MemInitializerAST;
+ ast->name = name;
+ ast->lparen_token = consumeToken();
+ parseExpression(ast->expression);
+ if (LA() == T_RPAREN)
+ ast->rparen_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTypeIdList(ExpressionListAST *&node)
+{
+ ExpressionListAST **expression_list_ptr = &node;
+ ExpressionAST *typeId = 0;
+ if (parseTypeId(typeId)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = typeId;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseTypeId(typeId)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = typeId;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseExpressionList(ExpressionListAST *&node)
+{
+ ExpressionListAST **expression_list_ptr = &node;
+ ExpressionAST *expression = 0;
+ if (parseAssignmentExpression(expression)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = expression;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseExpression(expression)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = expression;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node)
+{
+ BaseSpecifierAST *ast = new (_pool) BaseSpecifierAST;
+
+ if (LA() == T_VIRTUAL) {
+ ast->token_virtual = consumeToken();
+
+ int tk = LA();
+ if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
+ ast->token_access_specifier = consumeToken();
+ } else {
+ int tk = LA();
+ if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
+ ast->token_access_specifier = consumeToken();
+
+ if (LA() == T_VIRTUAL)
+ ast->token_virtual = consumeToken();
+ }
+
+ parseName(ast->name);
+ if (! ast->name)
+ _translationUnit->error(cursor(), "expected class-name");
+ node = ast;
+ return true;
+}
+
+bool Parser::parseInitializerList(ExpressionListAST *&node)
+{
+ ExpressionListAST **initializer_ptr = &node;
+ ExpressionAST *initializer = 0;
+ if (parseInitializerClause(initializer)) {
+ *initializer_ptr = new (_pool) ExpressionListAST;
+ (*initializer_ptr)->expression = initializer;
+ initializer_ptr = &(*initializer_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+ initializer = 0;
+ parseInitializerClause(initializer);
+ *initializer_ptr = new (_pool) ExpressionListAST;
+ (*initializer_ptr)->expression = initializer;
+ initializer_ptr = &(*initializer_ptr)->next;
+ }
+ }
+ return true;
+}
+
+bool Parser::parseInitializerClause(ExpressionAST *&node)
+{
+ if (LA() == T_LBRACE) {
+ ArrayInitializerAST *ast = new (_pool) ArrayInitializerAST;
+ ast->lbrace_token = consumeToken();
+ parseInitializerList(ast->expression_list);
+ if (LA() == T_RBRACE)
+ ast->rbrace_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return parseAssignmentExpression(node);
+}
+
+bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId)
+{
+ if (LA() == T_TILDE && LA(2) == T_IDENTIFIER) {
+ DestructorNameAST *ast = new (_pool) DestructorNameAST;
+ ast->tilde_token = consumeToken();
+ ast->identifier_token = consumeToken();
+ node = ast;
+ return true;
+ } else if (LA() == T_OPERATOR) {
+ unsigned operator_token = cursor();
+ if (parseOperatorFunctionId(node))
+ return true;
+ rewind(operator_token);
+ return parseConversionFunctionId(node);
+ } else if (LA() == T_IDENTIFIER) {
+ unsigned identifier_token = cursor();
+ if (acceptTemplateId && LA(2) == T_LESS && parseTemplateId(node)) {
+ if (! _templateArguments || (LA() == T_COMMA || LA() == T_GREATER ||
+ LA() == T_LPAREN || LA() == T_RPAREN ||
+ LA() == T_COLON_COLON))
+ return true;
+ }
+ rewind(identifier_token);
+ SimpleNameAST *ast = new (_pool) SimpleNameAST;
+ ast->identifier_token = consumeToken();
+ node = ast;
+ return true;
+ } else if (LA() == T_TEMPLATE) {
+ unsigned template_token = consumeToken();
+ if (parseTemplateId(node))
+ return true;
+ rewind(template_token);
+ }
+ return false;
+}
+
+bool Parser::parseStringLiteral(ExpressionAST *&node)
+{
+ if (! (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL))
+ return false;
+
+ StringLiteralAST **ast = reinterpret_cast<StringLiteralAST **> (&node);
+
+ while (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL) {
+ *ast = new (_pool) StringLiteralAST;
+ (*ast)->token = consumeToken();
+ ast = &(*ast)->next;
+ }
+ return true;
+}
+
+bool Parser::parseExpressionStatement(StatementAST *&node)
+{
+ ExpressionAST *expression = 0;
+ if (LA() == T_SEMICOLON || parseExpression(expression)) {
+ ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
+ ast->expression = expression;
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseStatement(StatementAST *&node)
+{
+ switch (LA()) {
+ case T_WHILE:
+ return parseWhileStatement(node);
+
+ case T_DO:
+ return parseDoStatement(node);
+
+ case T_FOR:
+ return parseForStatement(node);
+
+ case T_IF:
+ return parseIfStatement(node);
+
+ case T_SWITCH:
+ return parseSwitchStatement(node);
+
+ case T_TRY:
+ return parseTryBlockStatement(node);
+
+ case T_CASE:
+ case T_DEFAULT:
+ return parseLabeledStatement(node);
+
+ case T_BREAK:
+ return parseBreakStatement(node);
+
+ case T_CONTINUE:
+ return parseContinueStatement(node);
+
+ case T_GOTO:
+ return parseGotoStatement(node);
+
+ case T_RETURN:
+ return parseReturnStatement(node);
+
+ case T_LBRACE:
+ return parseCompoundStatement(node);
+
+ case T_ASM:
+ case T_NAMESPACE:
+ case T_USING:
+ case T_TEMPLATE:
+ case T_CLASS: case T_STRUCT: case T_UNION:
+ return parseDeclarationStatement(node);
+
+ case T_SEMICOLON: {
+ ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
+ ast->semicolon_token = consumeToken();
+ node = ast;
+ return true;
+ }
+
+ default:
+ if (LA() == T_IDENTIFIER && LA(2) == T_COLON)
+ return parseLabeledStatement(node);
+
+ return parseExpressionOrDeclarationStatement(node);
+ } // switch
+ return false;
+}
+
+bool Parser::parseBreakStatement(StatementAST *&node)
+{
+ if (LA() == T_BREAK) {
+ BreakStatementAST *ast = new (_pool) BreakStatementAST;
+ ast->break_token = consumeToken();
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseContinueStatement(StatementAST *&node)
+{
+ if (LA() == T_CONTINUE) {
+ ContinueStatementAST *ast = new (_pool) ContinueStatementAST;
+ ast->continue_token = consumeToken();
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseGotoStatement(StatementAST *&node)
+{
+ if (LA() == T_GOTO) {
+ GotoStatementAST *ast = new (_pool) GotoStatementAST;
+ ast->goto_token = consumeToken();
+ match(T_IDENTIFIER, &ast->identifier_token);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseReturnStatement(StatementAST *&node)
+{
+ if (LA() == T_RETURN) {
+ ReturnStatementAST *ast = new (_pool) ReturnStatementAST;
+ ast->return_token = consumeToken();
+ parseExpression(ast->expression);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::maybeFunctionCall(SimpleDeclarationAST *simpleDecl)
+{
+ if (! simpleDecl)
+ return false;
+ else if (! simpleDecl->decl_specifier_seq)
+ return false;
+ else if (simpleDecl->decl_specifier_seq->next)
+ return false;
+
+ NamedTypeSpecifierAST *type_spec = simpleDecl->decl_specifier_seq->asNamedTypeSpecifier();
+ if (! type_spec)
+ return false;
+
+ DeclaratorListAST *first_declarator = simpleDecl->declarators;
+ if (! first_declarator)
+ return false;
+ else if (first_declarator->next)
+ return false;
+
+ DeclaratorAST *declarator = first_declarator->declarator;
+ if (! declarator)
+ return false;
+ else if (declarator->ptr_operators)
+ return false;
+ else if (declarator->postfix_declarators)
+ return false;
+ else if (declarator->initializer)
+ return false;
+ else if (! declarator->core_declarator)
+ return false;
+
+ NestedDeclaratorAST *nested_declarator = declarator->core_declarator->asNestedDeclarator();
+ if (! nested_declarator)
+ return false;
+
+ return true;
+}
+
+bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
+{
+ if (LA() == T_SEMICOLON)
+ return parseExpressionStatement(node);
+
+ unsigned start = cursor();
+ bool blocked = blockErrors(true);
+ if (parseDeclarationStatement(node)) {
+ DeclarationStatementAST *stmt = static_cast<DeclarationStatementAST *>(node);
+ SimpleDeclarationAST *simpleDecl = 0;
+ if (stmt->declaration)
+ simpleDecl = stmt->declaration->asSimpleDeclaration();
+ if (simpleDecl && simpleDecl->decl_specifier_seq && ! maybeFunctionCall(simpleDecl)) {
+ unsigned end_of_declaration_statement = cursor();
+ rewind(start);
+ StatementAST *expression = 0;
+ if (! parseExpressionStatement(expression) || cursor() != end_of_declaration_statement) {
+ rewind(end_of_declaration_statement);
+ } else {
+ ExpressionOrDeclarationStatementAST *ast =
+ new (_pool) ExpressionOrDeclarationStatementAST;
+ ast->declaration = node;
+ ast->expression = expression;
+ node = ast;
+ }
+ blockErrors(blocked);
+ return true;
+ }
+ }
+ blockErrors(blocked);
+ rewind(start);
+ return parseExpressionStatement(node);
+}
+
+bool Parser::parseCondition(ExpressionAST *&node)
+{
+ unsigned start = cursor();
+
+ bool blocked = blockErrors(true);
+ SpecifierAST *type_specifier = 0;
+ if (parseTypeSpecifier(type_specifier)) {
+ DeclaratorAST *declarator = 0;
+ if (parseInitDeclarator(declarator, /*acceptStructDeclarator=*/false)) {
+ if (declarator->initializer) {
+ ConditionAST *ast = new (_pool) ConditionAST;
+ ast->type_specifier = type_specifier;
+ ast->declarator = declarator;
+ node = ast;
+ blockErrors(blocked);
+ return true;
+ }
+ }
+ }
+
+ blockErrors(blocked);
+ rewind(start);
+ return parseExpression(node);
+}
+
+bool Parser::parseWhileStatement(StatementAST *&node)
+{
+ if (LA() == T_WHILE) {
+ WhileStatementAST *ast = new (_pool) WhileStatementAST;
+ ast->while_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseCondition(ast->condition);
+ match(T_RPAREN, &ast->rparen_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return true;
+}
+
+bool Parser::parseDoStatement(StatementAST *&node)
+{
+ if (LA() == T_DO) {
+ DoStatementAST *ast = new (_pool) DoStatementAST;
+ ast->do_token = consumeToken();
+ parseStatement(ast->statement);
+ match(T_WHILE, &ast->while_token);
+ match(T_LPAREN, &ast->lparen_token);
+ parseExpression(ast->expression);
+ match(T_RPAREN, &ast->rparen_token);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseForStatement(StatementAST *&node)
+{
+ if (LA() == T_FOR) {
+ ForStatementAST *ast = new (_pool) ForStatementAST;
+ ast->for_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseForInitStatement(ast->initializer);
+ parseExpression(ast->condition);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ parseExpression(ast->expression);
+ match(T_RPAREN, &ast->rparen_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseForInitStatement(StatementAST *&node)
+{
+ return parseExpressionOrDeclarationStatement(node);
+}
+
+bool Parser::parseCompoundStatement(StatementAST *&node)
+{
+ if (LA() == T_LBRACE) {
+ CompoundStatementAST *ast = new (_pool) CompoundStatementAST;
+ ast->lbrace_token = consumeToken();
+ StatementAST **statement_ptr = &ast->statements;
+ while (int tk = LA()) {
+ if (tk == T_RBRACE)
+ break;
+
+ unsigned start_statement = cursor();
+ if (! parseStatement(*statement_ptr)) {
+ rewind(start_statement + 1);
+ skipUntilStatement();
+ } else {
+ statement_ptr = &(*statement_ptr)->next;
+ }
+ }
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseIfStatement(StatementAST *&node)
+{
+ if (LA() == T_IF) {
+ IfStatementAST *ast = new (_pool) IfStatementAST;
+ ast->if_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseCondition(ast->condition);
+ match(T_RPAREN, &ast->rparen_token);
+ if (! parseStatement(ast->statement))
+ _translationUnit->error(cursor(), "expected statement");
+ if (LA() == T_ELSE) {
+ ast->else_token = consumeToken();
+ if (! parseStatement(ast->else_statement))
+ _translationUnit->error(cursor(), "expected statement");
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseSwitchStatement(StatementAST *&node)
+{
+ if (LA() == T_SWITCH) {
+ SwitchStatementAST *ast = new (_pool) SwitchStatementAST;
+ ast->switch_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseCondition(ast->condition);
+ match(T_RPAREN, &ast->rparen_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseLabeledStatement(StatementAST *&node)
+{
+ switch (LA()) {
+ case T_IDENTIFIER:
+ if (LA(2) == T_COLON) {
+ LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
+ ast->label_token = consumeToken();
+ ast->colon_token = consumeToken();
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ break;
+
+ case T_DEFAULT: {
+ LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
+ ast->label_token = consumeToken();
+ match(T_COLON, &ast->colon_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+
+ case T_CASE: {
+ CaseStatementAST *ast = new (_pool) CaseStatementAST;
+ ast->case_token = consumeToken();
+ parseConstantExpression(ast->expression);
+ match(T_COLON, &ast->colon_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+
+ default:
+ break;
+ } // switch
+ return false;
+}
+
+bool Parser::parseBlockDeclaration(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_USING:
+ return parseUsing(node);
+
+ case T_ASM:
+ return parseAsmDefinition(node);
+
+ case T_NAMESPACE:
+ return parseNamespaceAliasDefinition(node);
+
+ default:
+ return parseSimpleDeclaration(node);
+ } // switch
+
+}
+
+bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
+{
+ if (LA() == T_NAMESPACE && LA(2) == T_IDENTIFIER && LA(3) == T_EQUAL) {
+ NamespaceAliasDefinitionAST *ast = new (_pool) NamespaceAliasDefinitionAST;
+ ast->namespace_token = consumeToken();
+ ast->namespace_name = consumeToken();
+ ast->equal_token = consumeToken();
+ parseName(ast->name);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseDeclarationStatement(StatementAST *&node)
+{
+ DeclarationAST *declaration = 0;
+ if (! parseBlockDeclaration(declaration))
+ return false;
+
+ DeclarationStatementAST *ast = new (_pool) DeclarationStatementAST;
+ ast->declaration = declaration;
+ node = ast;
+ return true;
+}
+
+bool Parser::lookAtCVQualifier() const
+{
+ switch (LA()) {
+ case T_CONST:
+ case T_VOLATILE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtFunctionSpecifier() const
+{
+ switch (LA()) {
+ case T_INLINE:
+ case T_VIRTUAL:
+ case T_EXPLICIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtStorageClassSpecifier() const
+{
+ switch (LA()) {
+ case T_FRIEND:
+ case T_AUTO:
+ case T_REGISTER:
+ case T_STATIC:
+ case T_EXTERN:
+ case T_MUTABLE:
+ case T_TYPEDEF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtBuiltinTypeSpecifier() const
+{
+ switch (LA()) {
+ case T_CHAR:
+ case T_WCHAR_T:
+ case T_BOOL:
+ case T_SHORT:
+ case T_INT:
+ case T_LONG:
+ case T_SIGNED:
+ case T_UNSIGNED:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_VOID:
+ return true;
+ // [gcc] extensions
+ case T___TYPEOF__:
+ case T___ATTRIBUTE__:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtClassKey() const
+{
+ switch (LA()) {
+ case T_CLASS:
+ case T_STRUCT:
+ case T_UNION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::parseAttributeSpecifier(SpecifierAST *&node)
+{
+ if (LA() != T___ATTRIBUTE__)
+ return false;
+
+ AttributeSpecifierAST *ast = new (_pool) AttributeSpecifierAST;
+ ast->attribute_token = consumeToken();
+ match(T_LPAREN, &ast->first_lparen_token);
+ match(T_LPAREN, &ast->second_lparen_token);
+ parseAttributeList(ast->attributes);
+ match(T_RPAREN, &ast->first_rparen_token);
+ match(T_RPAREN, &ast->second_rparen_token);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseAttributeList(AttributeAST *&node)
+{
+ AttributeAST **attribute_ptr = &node;
+ while (LA() == T_IDENTIFIER || LA() == T_CONST) {
+ AttributeAST *ast = new (_pool) AttributeAST;
+ ast->identifier_token = consumeToken();
+ if (LA() == T_LPAREN) {
+ consumeToken();
+ if (LA() == T_IDENTIFIER && (LA(2) == T_COMMA || LA(2) == T_RPAREN)) {
+ ast->tag_token = consumeToken();
+ if (LA() == T_COMMA) {
+ consumeToken();
+ parseExpressionList(ast->expression_list);
+ }
+ } else {
+ parseExpressionList(ast->expression_list);
+ }
+ unsigned rparen_token = 0;
+ match(T_RPAREN, &rparen_token);
+ }
+ *attribute_ptr = ast;
+
+ if (LA() != T_COMMA)
+ break;
+
+ consumeToken();
+ attribute_ptr = &(*attribute_ptr)->next;
+ }
+ return true;
+}
+
+bool Parser::parseBuiltinTypeSpecifier(SpecifierAST *&node)
+{
+ if (LA() == T___ATTRIBUTE__) {
+ return parseAttributeSpecifier(node);
+ } else if (LA() == T___TYPEOF__) {
+ TypeofSpecifierAST *ast = new (_pool) TypeofSpecifierAST;
+ ast->typeof_token = consumeToken();
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
+ consumeToken();
+ node = ast;
+ return true;
+ }
+ rewind(lparen_token);
+ }
+ parseUnaryExpression(ast->expression);
+ node = ast;
+ return true;
+ } else if (lookAtBuiltinTypeSpecifier()) {
+ SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
+ ast->specifier_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseSimpleDeclaration(DeclarationAST *&node,
+ bool acceptStructDeclarator)
+{
+ // parse a simple declaration, a function definition,
+ // or a contructor declaration.
+ cursor();
+
+ bool has_type_specifier = false;
+ bool has_complex_type_specifier = false;
+ unsigned startOfNamedTypeSpecifier = 0;
+ NameAST *named_type_specifier = 0;
+ SpecifierAST *decl_specifier_seq = 0,
+ **decl_specifier_seq_ptr = &decl_specifier_seq;
+ for (;;) {
+ if (lookAtCVQualifier() || lookAtFunctionSpecifier()
+ || lookAtStorageClassSpecifier()) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*decl_specifier_seq_ptr);
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (! named_type_specifier && ! has_complex_type_specifier && lookAtBuiltinTypeSpecifier()) {
+ parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && (LA() == T_COLON_COLON ||
+ LA() == T_IDENTIFIER)) {
+ startOfNamedTypeSpecifier = cursor();
+ if (parseName(named_type_specifier)) {
+ NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
+ spec->name = named_type_specifier;
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else {
+ rewind(startOfNamedTypeSpecifier);
+ break;
+ }
+ } else if (! has_type_specifier && LA() == T_ENUM) {
+ unsigned startOfTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) || LA() == T_LBRACE) {
+ rewind(startOfTypeSpecifier);
+ if (! parseEnumSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfTypeSpecifier,
+ "expected an enum specifier");
+ break;
+ }
+ has_complex_type_specifier = true;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && LA() == T_TYPENAME) {
+ unsigned startOfElaboratedTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfElaboratedTypeSpecifier,
+ "expected an elaborated type specifier");
+ break;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && lookAtClassKey()) {
+ unsigned startOfTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) ||
+ (LA() == T_COLON || LA() == T_LBRACE || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER &&
+ (LA(2) == T_COLON || LA(2) == T_LBRACE)))) {
+ rewind(startOfTypeSpecifier);
+ if (! parseClassSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfTypeSpecifier,
+ "wrong type specifier");
+ break;
+ }
+ has_complex_type_specifier = true;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else
+ break;
+ }
+
+ DeclaratorListAST *declarator_list = 0,
+ **declarator_ptr = &declarator_list;
+
+ const bool maybeCtor = (LA() == T_LPAREN && named_type_specifier);
+ DeclaratorAST *declarator = 0;
+ if (! parseInitDeclarator(declarator, acceptStructDeclarator) && maybeCtor) {
+ rewind(startOfNamedTypeSpecifier);
+ named_type_specifier = 0;
+ // pop the named type specifier from the decl-specifier-seq
+ SpecifierAST **spec_ptr = &decl_specifier_seq;
+ for (; *spec_ptr; spec_ptr = &(*spec_ptr)->next) {
+ if (! (*spec_ptr)->next) {
+ *spec_ptr = 0;
+ break;
+ }
+ }
+ if (! parseInitDeclarator(declarator, acceptStructDeclarator))
+ return false;
+ }
+
+ DeclaratorAST *firstDeclarator = declarator;
+
+ if (declarator) {
+ *declarator_ptr = new (_pool) DeclaratorListAST;
+ (*declarator_ptr)->declarator = declarator;
+ declarator_ptr = &(*declarator_ptr)->next;
+ }
+
+ if (LA() == T_COMMA || LA() == T_SEMICOLON || has_complex_type_specifier) {
+ while (LA() == T_COMMA) {
+ consumeToken();
+ declarator = 0;
+ if (parseInitDeclarator(declarator, acceptStructDeclarator)) {
+ *declarator_ptr = new (_pool) DeclaratorListAST;
+ (*declarator_ptr)->declarator = declarator;
+ declarator_ptr = &(*declarator_ptr)->next;
+ }
+ }
+ SimpleDeclarationAST *ast = new (_pool) SimpleDeclarationAST;
+ ast->decl_specifier_seq = decl_specifier_seq;
+ ast->declarators = declarator_list;
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ } else if (! _inFunctionBody && declarator && (LA() == T_COLON || LA() == T_LBRACE || LA() == T_TRY)) {
+ CtorInitializerAST *ctor_initializer = 0;
+ if (LA() == T_COLON)
+ parseCtorInitializer(ctor_initializer);
+
+ if (LA() == T_LBRACE) {
+ FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
+ ast->decl_specifier_seq = decl_specifier_seq;
+ ast->declarator = firstDeclarator;
+ ast->ctor_initializer = ctor_initializer;
+ parseFunctionBody(ast->function_body);
+ node = ast;
+ return true; // recognized a function definition.
+ } else if (LA() == T_TRY) {
+ FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
+ ast->decl_specifier_seq = decl_specifier_seq;
+ ast->declarator = firstDeclarator;
+ ast->ctor_initializer = ctor_initializer;
+ parseTryBlockStatement(ast->function_body);
+ node = ast;
+ return true; // recognized a function definition.
+ }
+ }
+
+ _translationUnit->error(cursor(), "unexpected token `%s'", tok().spell());
+ return false;
+}
+
+bool Parser::parseFunctionBody(StatementAST *&node)
+{
+ if (_translationUnit->skipFunctionBody()) {
+ unsigned token_lbrace = 0;
+ match(T_LBRACE, &token_lbrace);
+ if (! token_lbrace)
+ return false;
+
+ const Token &tk = _translationUnit->tokenAt(token_lbrace);
+ if (tk.close_brace)
+ rewind(tk.close_brace);
+ unsigned token_rbrace = 0;
+ match(T_RBRACE, &token_rbrace);
+ return true;
+ }
+
+ _inFunctionBody = true;
+ const bool parsed = parseCompoundStatement(node);
+ _inFunctionBody = false;
+ return parsed;
+}
+
+bool Parser::parseTryBlockStatement(StatementAST *&node)
+{
+ if (LA() == T_TRY) {
+ TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST;
+ ast->try_token = consumeToken();
+ parseCompoundStatement(ast->statement);
+ CatchClauseAST **catch_clause_ptr = &ast->catch_clause_seq;
+ while (parseCatchClause(*catch_clause_ptr))
+ catch_clause_ptr = &(*catch_clause_ptr)->next;
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseCatchClause(CatchClauseAST *&node)
+{
+ if (LA() == T_CATCH) {
+ CatchClauseAST *ast = new (_pool) CatchClauseAST;
+ ast->catch_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseExceptionDeclaration(ast->exception_declaration);
+ match(T_RPAREN, &ast->rparen_token);
+ parseCompoundStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseExceptionDeclaration(ExceptionDeclarationAST *&node)
+{
+ if (LA() == T_DOT_DOT_DOT) {
+ ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
+ ast->dot_dot_dot_token = consumeToken();
+ node = ast;
+ return true;
+ }
+
+ SpecifierAST *type_specifier = 0;
+ if (parseTypeSpecifier(type_specifier)) {
+ ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
+ ast->type_specifier = type_specifier;
+ parseDeclaratorOrAbstractDeclarator(ast->declarator);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseBoolLiteral(ExpressionAST *&node)
+{
+ if (LA() == T_TRUE || LA() == T_FALSE) {
+ BoolLiteralAST *ast = new (_pool) BoolLiteralAST;
+ ast->token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseNumericLiteral(ExpressionAST *&node)
+{
+ if (LA() == T_INT_LITERAL || LA() == T_FLOAT_LITERAL || LA() == T_CHAR_LITERAL) {
+ NumericLiteralAST *ast = new (_pool) NumericLiteralAST;
+ ast->token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseThisExpression(ExpressionAST *&node)
+{
+ if (LA() == T_THIS) {
+ ThisExpressionAST *ast = new (_pool) ThisExpressionAST;
+ ast->this_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parsePrimaryExpression(ExpressionAST *&node)
+{
+ switch (LA()) {
+ case T_STRING_LITERAL:
+ case T_WIDE_STRING_LITERAL:
+ return parseStringLiteral(node);
+
+ case T_INT_LITERAL:
+ case T_FLOAT_LITERAL:
+ case T_CHAR_LITERAL:
+ case T_WIDE_CHAR_LITERAL:
+ return parseNumericLiteral(node);
+
+ case T_TRUE:
+ case T_FALSE:
+ return parseBoolLiteral(node);
+
+ case T_THIS:
+ return parseThisExpression(node);
+
+ case T_LPAREN:
+ return parseNestedExpression(node);
+
+ case T_SIGNAL:
+ case T_SLOT:
+ return parseQtMethod(node);
+
+ default: {
+ unsigned startOfName = cursor();
+ NameAST *name = 0;
+ if (parseName(name)) {
+ if (LA() == T_IDENTIFIER || tok().isLiteral() || (tok().isOperator() && LA() != T_LPAREN &&
+ LA() != T_LBRACKET)) {
+ rewind(startOfName);
+ parseName(name, false);
+ }
+ // literal
+ // identifier <unop> ?
+ // identifier <binop>
+ // identifier <access>
+ // identifier rparen
+ // lparen type rparen identifier [[cast-expression]]
+
+ node = name;
+ return true;
+ }
+ } // default
+
+ } // switch
+
+ return false;
+}
+
+bool Parser::parseNestedExpression(ExpressionAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+
+ if (LA() == T_LBRACE) {
+ NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
+ ast->lparen_token = lparen_token;
+
+ // ### ast
+ StatementAST *statement = 0;
+ parseCompoundStatement(statement);
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+
+ bool previousTemplateArguments = switchTemplateArguments(false);
+
+ ExpressionAST *expression = 0;
+ if (parseExpression(expression) && LA() == T_RPAREN) {
+ NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
+ ast->lparen_token = lparen_token;
+ ast->expression = expression;
+ ast->rparen_token = consumeToken();
+ node = ast;
+ (void) switchTemplateArguments(previousTemplateArguments);
+ return true;
+ }
+ (void) switchTemplateArguments(previousTemplateArguments);
+ }
+ return false;
+}
+
+bool Parser::parseCppCastExpression(ExpressionAST *&node)
+{
+ if (LA() == T_DYNAMIC_CAST || LA() == T_STATIC_CAST ||
+ LA() == T_REINTERPRET_CAST || LA() == T_CONST_CAST) {
+ CppCastExpressionAST *ast = new (_pool) CppCastExpressionAST;
+ ast->cast_token = consumeToken();
+ match(T_LESS, &ast->less_token);
+ parseTypeId(ast->type_id);
+ match(T_GREATER, &ast->greater_token);
+ match(T_LPAREN, &ast->lparen_token);
+ parseExpression(ast->expression);
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+// typename ::opt nested-name-specifier identifier ( expression-listopt )
+// typename ::opt nested-name-specifier templateopt template-id ( expression-listopt )
+bool Parser::parseTypenameCallExpression(ExpressionAST *&node)
+{
+ if (LA() == T_TYPENAME) {
+ unsigned typename_token = consumeToken();
+ NameAST *name = 0;
+ if (parseName(name) && LA() == T_LPAREN) {
+ TypenameCallExpressionAST *ast = new (_pool) TypenameCallExpressionAST;
+ ast->typename_token = typename_token;
+ ast->name = name;
+ ast->lparen_token = consumeToken();
+ parseExpressionList(ast->expression_list);
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+// typeid ( expression )
+// typeid ( type-id )
+bool Parser::parseTypeidExpression(ExpressionAST *&node)
+{
+ if (LA() == T_TYPEID) {
+ TypeidExpressionAST *ast = new (_pool) TypeidExpressionAST;
+ ast->typeid_token = consumeToken();
+ if (LA() == T_LPAREN)
+ ast->lparen_token = consumeToken();
+ unsigned saved = cursor();
+ if (! (parseTypeId(ast->expression) && LA() == T_RPAREN)) {
+ rewind(saved);
+ parseExpression(ast->expression);
+ }
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseCorePostfixExpression(ExpressionAST *&node)
+{
+ if (parseCppCastExpression(node))
+ return true;
+ else if (parseTypenameCallExpression(node))
+ return true;
+ else if (parseTypeidExpression(node))
+ return true;
+ else {
+ unsigned start = cursor();
+ SpecifierAST *type_specifier = 0;
+ bool blocked = blockErrors(true);
+ if (lookAtBuiltinTypeSpecifier() &&
+ parseSimpleTypeSpecifier(type_specifier) &&
+ LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionListAST *expression_list = 0;
+ parseExpressionList(expression_list);
+ if (LA() == T_RPAREN) {
+ unsigned rparen_token = consumeToken();
+ TypeConstructorCallAST *ast = new (_pool) TypeConstructorCallAST;
+ ast->type_specifier = type_specifier;
+ ast->lparen_token = lparen_token;
+ ast->expression_list = expression_list;
+ ast->rparen_token = rparen_token;
+ node = ast;
+ blockErrors(blocked);
+ return true;
+ }
+ }
+ blockErrors(blocked);
+ rewind(start);
+ return parsePrimaryExpression(node);
+ }
+}
+
+bool Parser::parsePostfixExpression(ExpressionAST *&node)
+{
+ if (parseCorePostfixExpression(node)) {
+ PostfixAST *postfix_expressions = 0,
+ **postfix_ptr = &postfix_expressions;
+ while (LA()) {
+ if (LA() == T_LPAREN) {
+ CallAST *ast = new (_pool) CallAST;
+ ast->lparen_token = consumeToken();
+ parseExpressionList(ast->expression_list);
+ match(T_RPAREN, &ast->rparen_token);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_LBRACKET) {
+ ArrayAccessAST *ast = new (_pool) ArrayAccessAST;
+ ast->lbracket_token = consumeToken();
+ parseExpression(ast->expression);
+ match(T_RBRACKET, &ast->rbracket_token);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_PLUS_PLUS || LA() == T_MINUS_MINUS) {
+ PostIncrDecrAST *ast = new (_pool) PostIncrDecrAST;
+ ast->incr_decr_token = consumeToken();
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_DOT || LA() == T_ARROW) {
+ MemberAccessAST *ast = new (_pool) MemberAccessAST;
+ ast->access_token = consumeToken();
+ if (LA() == T_TEMPLATE)
+ ast->template_token = consumeToken();
+ if (! parseName(ast->member_name))
+ _translationUnit->error(cursor(), "expected unqualified-id before token `%s'",
+ tok().spell());
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else break;
+ } // while
+
+ if (postfix_expressions) {
+ PostfixExpressionAST *ast = new (_pool) PostfixExpressionAST;
+ ast->base_expression = node;
+ ast->postfix_expressions = postfix_expressions;
+ node = ast;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseUnaryExpression(ExpressionAST *&node)
+{
+ switch (LA()) {
+ case T_PLUS_PLUS:
+ case T_MINUS_MINUS:
+ case T_STAR:
+ case T_AMPER:
+ case T_PLUS:
+ case T_MINUS:
+ case T_EXCLAIM: {
+ UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
+ ast->unary_op_token = consumeToken();
+ parseCastExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+
+ case T_TILDE: {
+ if (LA(2) == T_IDENTIFIER && LA(3) == T_LPAREN)
+ break; // prefer destructor names
+
+ UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
+ ast->unary_op_token = consumeToken();
+ parseCastExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+
+ case T_SIZEOF: {
+ SizeofExpressionAST *ast = new (_pool) SizeofExpressionAST;
+ ast->sizeof_token = consumeToken();
+
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
+ consumeToken();
+ node = ast;
+ return true;
+ } else {
+ rewind(lparen_token);
+ }
+ }
+
+ parseUnaryExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+
+ default:
+ break;
+ } // switch
+
+ if (LA() == T_NEW || (LA(1) == T_COLON_COLON &&
+ LA(2) == T_NEW))
+ return parseNewExpression(node);
+ else if (LA() == T_DELETE || (LA(1) == T_COLON_COLON &&
+ LA(2) == T_DELETE))
+ return parseDeleteExpression(node);
+ else
+ return parsePostfixExpression(node);
+}
+
+bool Parser::parseNewExpression(ExpressionAST *&node)
+{
+ if (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW)) {
+ NewExpressionAST *ast = new (_pool) NewExpressionAST;
+
+ if (LA() == T_COLON_COLON)
+ ast->scope_token = consumeToken();
+
+ ast->new_token = consumeToken();
+
+ if (LA() == T_LPAREN) {
+ consumeToken();
+ parseExpression(ast->expression);
+ if (LA() == T_RPAREN)
+ consumeToken();
+ }
+
+ if (LA() == T_LPAREN) {
+ consumeToken();
+ parseTypeId(ast->type_id);
+ if (LA() == T_RPAREN)
+ consumeToken();
+ } else {
+ parseNewTypeId(ast->new_type_id);
+ }
+
+ parseNewInitializer(ast->new_initializer);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseNewTypeId(NewTypeIdAST *&node)
+{
+ SpecifierAST *typeSpec = 0;
+ if (! parseTypeSpecifier(typeSpec))
+ return false;
+
+ NewTypeIdAST *ast = new (_pool) NewTypeIdAST;
+ ast->type_specifier = typeSpec;
+ parseNewDeclarator(ast->new_declarator);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseNewDeclarator(NewDeclaratorAST *&node)
+{
+ NewDeclaratorAST *ast = new (_pool) NewDeclaratorAST;
+
+ PtrOperatorAST **ptr_operators_tail = &ast->ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ while (LA() == T_LBRACKET) { // ### create the AST
+ consumeToken();
+ ExpressionAST *expression = 0;
+ parseExpression(expression);
+ unsigned rbracket_token = 0;
+ match(T_RBRACKET, &rbracket_token);
+ }
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseNewInitializer(NewInitializerAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionAST *expression = 0;
+ if (LA() == T_RPAREN || parseExpression(expression)) {
+ NewInitializerAST *ast = new (_pool) NewInitializerAST;
+ ast->lparen_token = lparen_token;
+ ast->expression = expression;
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseDeleteExpression(ExpressionAST *&node)
+{
+ if (LA() == T_DELETE || (LA() == T_COLON_COLON && LA(2) == T_DELETE)) {
+ DeleteExpressionAST *ast = new (_pool) DeleteExpressionAST;
+
+ if (LA() == T_COLON_COLON)
+ ast->scope_token = consumeToken();
+
+ ast->delete_token = consumeToken();
+
+ if (LA() == T_LBRACKET) {
+ ast->lbracket_token = consumeToken();
+ match(T_RBRACKET, &ast->rbracket_token);
+ }
+
+ parseCastExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseCastExpression(ExpressionAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionAST *type_id = 0;
+ if (parseTypeId(type_id) && LA() == T_RPAREN) {
+ unsigned rparen_token = consumeToken();
+ ExpressionAST *expression = 0;
+ if (parseCastExpression(expression)) {
+ CastExpressionAST *ast = new (_pool) CastExpressionAST;
+ ast->lparen_token = lparen_token;
+ ast->type_id = type_id;
+ ast->rparen_token = rparen_token;
+ ast->expression = expression;
+ node = ast;
+ return true;
+ }
+ }
+ rewind(lparen_token);
+ }
+ return parseUnaryExpression(node);
+}
+
+bool Parser::parsePmExpression(ExpressionAST *&node)
+{
+ if (! parseCastExpression(node))
+ return false;
+
+ while (LA() == T_ARROW_STAR || LA() == T_DOT_STAR) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseCastExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
+{
+ if (! parsePmExpression(node))
+ return false;
+
+ while (LA() == T_STAR || LA() == T_SLASH || LA() == T_PERCENT) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parsePmExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseAdditiveExpression(ExpressionAST *&node)
+{
+ if (! parseMultiplicativeExpression(node))
+ return false;
+
+ while (LA() == T_PLUS || LA() == T_MINUS) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseMultiplicativeExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseShiftExpression(ExpressionAST *&node)
+{
+ if (! parseAdditiveExpression(node))
+ return false;
+
+ while (LA() == T_LESS_LESS || LA() == T_GREATER_GREATER) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAdditiveExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseRelationalExpression(ExpressionAST *&node)
+{
+ if (! parseShiftExpression(node))
+ return false;
+
+ while (LA() == T_LESS || (LA() == T_GREATER && ! _templateArguments) ||
+ LA() == T_LESS_EQUAL || LA() == T_GREATER_EQUAL) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseShiftExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseEqualityExpression(ExpressionAST *&node)
+{
+ if (! parseRelationalExpression(node))
+ return false;
+
+ while (LA() == T_EQUAL_EQUAL || LA() == T_EXCLAIM_EQUAL) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseRelationalExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseAndExpression(ExpressionAST *&node)
+{
+ if (! parseEqualityExpression(node))
+ return false;
+
+ while (LA() == T_AMPER) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseEqualityExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseExclusiveOrExpression(ExpressionAST *&node)
+{
+ if (! parseAndExpression(node))
+ return false;
+
+ while (LA() == T_CARET) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAndExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseInclusiveOrExpression(ExpressionAST *&node)
+{
+ if (! parseExclusiveOrExpression(node))
+ return false;
+
+ while (LA() == T_PIPE) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseExclusiveOrExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseLogicalAndExpression(ExpressionAST *&node)
+{
+ if (! parseInclusiveOrExpression(node))
+ return false;
+
+ while (LA() == T_AMPER_AMPER) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseInclusiveOrExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseLogicalOrExpression(ExpressionAST *&node)
+{
+ if (! parseLogicalAndExpression(node))
+ return false;
+
+ while (LA() == T_PIPE_PIPE) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseLogicalAndExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseConditionalExpression(ExpressionAST *&node)
+{
+ if (! parseLogicalOrExpression(node))
+ return false;
+
+ if (LA() != T_QUESTION)
+ return true;
+
+ ConditionalExpressionAST *ast = new (_pool) ConditionalExpressionAST;
+ ast->condition = node;
+ ast->question_token = consumeToken();
+ parseAssignmentExpression(ast->left_expression);
+ match(T_COLON, &ast->colon_token);
+ parseAssignmentExpression(ast->right_expression);
+ node = ast;
+ return true;
+}
+
+bool Parser::lookAtAssignmentOperator() const
+{
+ switch (LA()) {
+ case T_EQUAL:
+ case T_AMPER_EQUAL:
+ case T_CARET_EQUAL:
+ case T_SLASH_EQUAL:
+ case T_GREATER_GREATER_EQUAL:
+ case T_LESS_LESS_EQUAL:
+ case T_MINUS_EQUAL:
+ case T_PERCENT_EQUAL:
+ case T_PIPE_EQUAL:
+ case T_PLUS_EQUAL:
+ case T_STAR_EQUAL:
+ case T_TILDE_EQUAL:
+ return true;
+ default:
+ return false;
+ } // switch
+}
+
+bool Parser::parseAssignmentExpression(ExpressionAST *&node)
+{
+ if (LA() == T_THROW)
+ return parseThrowExpression(node);
+ else if (! parseConditionalExpression(node))
+ return false;
+
+ if (lookAtAssignmentOperator()) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAssignmentExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseQtMethod(ExpressionAST *&node)
+{
+ if (LA() == T_SIGNAL || LA() == T_SLOT) {
+ QtMethodAST *ast = new (_pool) QtMethodAST;
+ ast->method_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ if (! parseDeclarator(ast->declarator))
+ _translationUnit->error(cursor(), "expected a function declarator before token `%s'",
+ tok().spell());
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseConstantExpression(ExpressionAST *&node)
+{
+ return parseConditionalExpression(node);
+}
+
+bool Parser::parseExpression(ExpressionAST *&node)
+{
+ return parseCommaExpression(node);
+}
+
+bool Parser::parseCommaExpression(ExpressionAST *&node)
+{
+ if (! parseAssignmentExpression(node))
+ return false;
+
+ while (LA() == T_COMMA) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAssignmentExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseThrowExpression(ExpressionAST *&node)
+{
+ if (LA() == T_THROW) {
+ ThrowExpressionAST *ast = new (_pool) ThrowExpressionAST;
+ ast->throw_token = consumeToken();
+ parseAssignmentExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Parser.h b/shared/cplusplus/Parser.h
new file mode 100644
index 0000000000..cddc9ec666
--- /dev/null
+++ b/shared/cplusplus/Parser.h
@@ -0,0 +1,261 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_PARSER_H
+#define CPLUSPLUS_PARSER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+#include "Token.h"
+#include "TranslationUnit.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Parser
+{
+public:
+ Parser(TranslationUnit *translationUnit);
+ ~Parser();
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ bool parseTranslationUnit(TranslationUnitAST *&node);
+
+public:
+ bool parseAccessSpecifier(SpecifierAST *&node);
+ bool parseExpressionList(ExpressionListAST *&node);
+ bool parseAbstractCoreDeclarator(DeclaratorAST *&node);
+ bool parseAbstractDeclarator(DeclaratorAST *&node);
+ bool parseEmptyDeclaration(DeclarationAST *&node);
+ bool parseAccessDeclaration(DeclarationAST *&node);
+ bool parseAdditiveExpression(ExpressionAST *&node);
+ bool parseAndExpression(ExpressionAST *&node);
+ bool parseAsmDefinition(DeclarationAST *&node);
+ bool parseAssignmentExpression(ExpressionAST *&node);
+ bool parseBaseClause(BaseSpecifierAST *&node);
+ bool parseBaseSpecifier(BaseSpecifierAST *&node);
+ bool parseBlockDeclaration(DeclarationAST *&node);
+ bool parseCppCastExpression(ExpressionAST *&node);
+ bool parseCastExpression(ExpressionAST *&node);
+ bool parseClassSpecifier(SpecifierAST *&node);
+ bool parseCommaExpression(ExpressionAST *&node);
+ bool parseCompoundStatement(StatementAST *&node);
+ bool parseBreakStatement(StatementAST *&node);
+ bool parseContinueStatement(StatementAST *&node);
+ bool parseGotoStatement(StatementAST *&node);
+ bool parseReturnStatement(StatementAST *&node);
+ bool parseCondition(ExpressionAST *&node);
+ bool parseConditionalExpression(ExpressionAST *&node);
+ bool parseConstantExpression(ExpressionAST *&node);
+ bool parseCtorInitializer(CtorInitializerAST *&node);
+ bool parseCvQualifiers(SpecifierAST *&node);
+ bool parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node);
+ bool parseDeclaration(DeclarationAST *&node);
+ bool parseSimpleDeclaration(DeclarationAST *&node, bool acceptStructDeclarator = false);
+ bool parseDeclarationStatement(StatementAST *&node);
+ bool parseCoreDeclarator(DeclaratorAST *&node);
+ bool parseDeclarator(DeclaratorAST *&node);
+ bool parseDeleteExpression(ExpressionAST *&node);
+ bool parseDoStatement(StatementAST *&node);
+ bool parseElaboratedTypeSpecifier(SpecifierAST *&node);
+ bool parseEnumSpecifier(SpecifierAST *&node);
+ bool parseEnumerator(EnumeratorAST *&node);
+ bool parseEqualityExpression(ExpressionAST *&node);
+ bool parseExceptionDeclaration(ExceptionDeclarationAST *&node);
+ bool parseExceptionSpecification(ExceptionSpecificationAST *&node);
+ bool parseExclusiveOrExpression(ExpressionAST *&node);
+ bool parseExpression(ExpressionAST *&node);
+ bool parseExpressionOrDeclarationStatement(StatementAST *&node);
+ bool parseExpressionStatement(StatementAST *&node);
+ bool parseForInitStatement(StatementAST *&node);
+ bool parseForStatement(StatementAST *&node);
+ bool parseFunctionBody(StatementAST *&node);
+ bool parseIfStatement(StatementAST *&node);
+ bool parseInclusiveOrExpression(ExpressionAST *&node);
+ bool parseInitDeclarator(DeclaratorAST *&node, bool acceptStructDeclarator);
+ bool parseInitializerList(ExpressionListAST *&node);
+ bool parseInitializer(ExpressionAST *&node);
+ bool parseInitializerClause(ExpressionAST *&node);
+ bool parseLabeledStatement(StatementAST *&node);
+ bool parseLinkageBody(DeclarationAST *&node);
+ bool parseLinkageSpecification(DeclarationAST *&node);
+ bool parseLogicalAndExpression(ExpressionAST *&node);
+ bool parseLogicalOrExpression(ExpressionAST *&node);
+ bool parseMemInitializer(MemInitializerAST *&node);
+ bool parseMemInitializerList(MemInitializerAST *&node);
+ bool parseMemberSpecification(DeclarationAST *&node);
+ bool parseMultiplicativeExpression(ExpressionAST *&node);
+ bool parseTemplateId(NameAST *&node);
+ bool parseClassOrNamespaceName(NameAST *&node);
+ bool parseName(NameAST *&node, bool acceptTemplateId = true);
+ bool parseNestedNameSpecifier(NestedNameSpecifierAST *&node, bool acceptTemplateId);
+ bool parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name, bool acceptTemplateId);
+ bool parseNamespace(DeclarationAST *&node);
+ bool parseNamespaceAliasDefinition(DeclarationAST *&node);
+ bool parseNewDeclarator(NewDeclaratorAST *&node);
+ bool parseNewExpression(ExpressionAST *&node);
+ bool parseNewInitializer(NewInitializerAST *&node);
+ bool parseNewTypeId(NewTypeIdAST *&node);
+ bool parseOperator(OperatorAST *&node);
+ bool parseConversionFunctionId(NameAST *&node);
+ bool parseOperatorFunctionId(NameAST *&node);
+ bool parseParameterDeclaration(DeclarationAST *&node);
+ bool parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node);
+ bool parseParameterDeclarationList(DeclarationAST *&node);
+ bool parsePmExpression(ExpressionAST *&node);
+ bool parseTypeidExpression(ExpressionAST *&node);
+ bool parseTypenameCallExpression(ExpressionAST *&node);
+ bool parseCorePostfixExpression(ExpressionAST *&node);
+ bool parsePostfixExpression(ExpressionAST *&node);
+ bool parsePostfixExpressionInternal(ExpressionAST *&node);
+ bool parsePrimaryExpression(ExpressionAST *&node);
+ bool parseNestedExpression(ExpressionAST *&node);
+ bool parsePtrOperator(PtrOperatorAST *&node);
+ bool parseRelationalExpression(ExpressionAST *&node);
+ bool parseShiftExpression(ExpressionAST *&node);
+ bool parseStatement(StatementAST *&node);
+ bool parseThisExpression(ExpressionAST *&node);
+ bool parseBoolLiteral(ExpressionAST *&node);
+ bool parseNumericLiteral(ExpressionAST *&node);
+ bool parseStringLiteral(ExpressionAST *&node);
+ bool parseSwitchStatement(StatementAST *&node);
+ bool parseTemplateArgument(ExpressionAST *&node);
+ bool parseTemplateArgumentList(TemplateArgumentListAST *&node);
+ bool parseTemplateDeclaration(DeclarationAST *&node);
+ bool parseTemplateParameter(DeclarationAST *&node);
+ bool parseTemplateParameterList(DeclarationAST *&node);
+ bool parseThrowExpression(ExpressionAST *&node);
+ bool parseTryBlockStatement(StatementAST *&node);
+ bool parseCatchClause(CatchClauseAST *&node);
+ bool parseTypeId(ExpressionAST *&node);
+ bool parseTypeIdList(ExpressionListAST *&node);
+ bool parseTypenameTypeParameter(DeclarationAST *&node);
+ bool parseTemplateTypeParameter(DeclarationAST *&node);
+ bool parseTypeParameter(DeclarationAST *&node);
+
+ bool parseBuiltinTypeSpecifier(SpecifierAST *&node);
+ bool parseAttributeSpecifier(SpecifierAST *&node);
+ bool parseAttributeList(AttributeAST *&node);
+
+ bool parseSimpleTypeSpecifier(SpecifierAST *&node)
+ { return parseDeclSpecifierSeq(node, true, true); }
+
+ bool parseTypeSpecifier(SpecifierAST *&node)
+ { return parseDeclSpecifierSeq(node, true); }
+
+ bool parseDeclSpecifierSeq(SpecifierAST *&node,
+ bool onlyTypeSpecifiers = false,
+ bool simplified = false);
+ bool parseUnaryExpression(ExpressionAST *&node);
+ bool parseUnqualifiedName(NameAST *&node, bool acceptTemplateId = true);
+ bool parseUsing(DeclarationAST *&node);
+ bool parseUsingDirective(DeclarationAST *&node);
+ bool parseWhileStatement(StatementAST *&node);
+
+ // Qt MOC run
+ bool parseQtMethod(ExpressionAST *&node);
+
+ bool skipUntil(int token);
+ bool skipUntilDeclaration();
+ bool skipUntilStatement();
+ bool skip(int l, int r);
+
+ bool lookAtCVQualifier() const;
+ bool lookAtFunctionSpecifier() const;
+ bool lookAtStorageClassSpecifier() const;
+ bool lookAtBuiltinTypeSpecifier() const;
+ bool lookAtClassKey() const;
+ bool lookAtAssignmentOperator() const;
+
+ void match(int kind, unsigned *token);
+
+ bool maybeFunctionCall(SimpleDeclarationAST *simpleDecl);
+
+private:
+ bool switchTemplateArguments(bool templateArguments);
+ bool blockErrors(bool block);
+
+ inline const Token &tok() const
+ { return _translationUnit->tokenAt(_tokenIndex); }
+
+ inline int LA(int n = 1) const
+ { return _translationUnit->tokenKind(_tokenIndex + n - 1); }
+
+ inline int consumeToken()
+ { return _tokenIndex++; }
+
+ inline unsigned cursor() const
+ { return _tokenIndex; }
+
+ inline void rewind(unsigned cursor)
+ { _tokenIndex = cursor; }
+
+private:
+ TranslationUnit *_translationUnit;
+ Control *_control;
+ MemoryPool *_pool;
+ unsigned _tokenIndex;
+ bool _templateArguments: 1;
+ bool _qtMocRunEnabled: 1;
+ bool _inFunctionBody: 1;
+
+private:
+ Parser(const Parser& source);
+ void operator =(const Parser& source);
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_PARSER_H
diff --git a/shared/cplusplus/Scope.cpp b/shared/cplusplus/Scope.cpp
new file mode 100644
index 0000000000..293216f129
--- /dev/null
+++ b/shared/cplusplus/Scope.cpp
@@ -0,0 +1,308 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Scope.h"
+#include "Symbols.h"
+#include "Names.h"
+#include "Literals.h"
+#include <cstdlib>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Scope::Scope(ScopedSymbol *owner)
+ : _owner(owner),
+ _symbols(0),
+ _allocatedSymbols(0),
+ _symbolCount(-1),
+ _hash(0),
+ _hashSize(0),
+ _uses(0),
+ _allocatedUses(0),
+ _useCount(-1)
+{ }
+
+Scope::~Scope()
+{
+ if (_symbols)
+ free(_symbols);
+ if (_hash)
+ free(_hash);
+ if (_uses)
+ free(_uses);
+}
+
+ScopedSymbol *Scope::owner() const
+{ return _owner; }
+
+void Scope::setOwner(ScopedSymbol *owner)
+{ _owner = owner; }
+
+Scope *Scope::enclosingScope() const
+{
+ if (! _owner)
+ return 0;
+
+ return _owner->scope();
+}
+
+Scope *Scope::enclosingNamespaceScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isNamespace())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingClassScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isClass())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingEnumScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isEnum())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingFunctionScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isFunction())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingBlockScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isBlock())
+ break;
+ }
+ return scope;
+}
+
+bool Scope::isNamespaceScope() const
+{ return dynamic_cast<const Namespace *>(_owner) != 0; }
+
+bool Scope::isClassScope() const
+{ return dynamic_cast<const Class *>(_owner) != 0; }
+
+bool Scope::isEnumScope() const
+{ return dynamic_cast<const Enum *>(_owner) != 0; }
+
+bool Scope::isBlockScope() const
+{ return dynamic_cast<const Block *>(_owner) != 0; }
+
+bool Scope::isPrototypeScope() const
+{
+ if (const Function *f = dynamic_cast<const Function *>(_owner))
+ return f->arguments() == this;
+ return false;
+}
+
+bool Scope::isFunctionScope() const
+{
+ if (const Function *f = dynamic_cast<const Function *>(_owner))
+ return f->arguments() != this;
+ return false;
+}
+
+void Scope::enterSymbol(Symbol *symbol)
+{
+ if (++_symbolCount == _allocatedSymbols) {
+ _allocatedSymbols <<= 1;
+ if (! _allocatedSymbols)
+ _allocatedSymbols = DefaultInitialSize;
+
+ _symbols = reinterpret_cast<Symbol **>(realloc(_symbols, sizeof(Symbol *) * _allocatedSymbols));
+ }
+
+ assert(! symbol->_scope || symbol->scope() == this);
+ symbol->_index = _symbolCount;
+ symbol->_scope = this;
+ _symbols[_symbolCount] = symbol;
+
+ if (_symbolCount >= _hashSize * 0.6)
+ rehash();
+ else {
+ const unsigned h = hashValue(symbol);
+ symbol->_next = _hash[h];
+ _hash[h] = symbol;
+ }
+}
+
+Symbol *Scope::lookat(Identifier *id) const
+{
+ if (! _hash)
+ return 0;
+
+ const unsigned h = id->hashCode() % _hashSize;
+ Symbol *symbol = _hash[h];
+ for (; symbol; symbol = symbol->_next) {
+ Name *identity = symbol->identity();
+ if (NameId *nameId = identity->asNameId()) {
+ if (nameId->identifier()->isEqualTo(id))
+ break;
+ } else if (TemplateNameId *t = identity->asTemplateNameId()) {
+ if (t->identifier()->isEqualTo(id))
+ break;
+ } else if (DestructorNameId *d = identity->asDestructorNameId()) {
+ if (d->identifier()->isEqualTo(id))
+ break;
+ } else if (identity->isQualifiedNameId()) {
+ assert(0);
+ }
+ }
+ return symbol;
+}
+
+Symbol *Scope::lookat(int operatorId) const
+{
+ if (! _hash)
+ return 0;
+
+ const unsigned h = operatorId % _hashSize;
+ Symbol *symbol = _hash[h];
+ for (; symbol; symbol = symbol->_next) {
+ Name *identity = symbol->identity();
+ if (OperatorNameId *op = identity->asOperatorNameId()) {
+ if (op->kind() == operatorId)
+ break;
+ }
+ }
+ return symbol;
+}
+
+void Scope::rehash()
+{
+ _hashSize <<= 1;
+
+ if (! _hashSize)
+ _hashSize = DefaultInitialSize;
+
+ _hash = reinterpret_cast<Symbol **>(realloc(_hash, sizeof(Symbol *) * _hashSize));
+ memset(_hash, 0, sizeof(Symbol *) * _hashSize);
+
+ for (int index = 0; index < _symbolCount + 1; ++index) {
+ Symbol *symbol = _symbols[index];
+ const unsigned h = hashValue(symbol);
+ symbol->_next = _hash[h];
+ _hash[h] = symbol;
+ }
+}
+
+unsigned Scope::hashValue(Symbol *symbol) const
+{
+ if (! symbol)
+ return 0;
+
+ return symbol->hashCode() % _hashSize;
+}
+
+bool Scope::isEmpty() const
+{ return _symbolCount == -1; }
+
+unsigned Scope::symbolCount() const
+{ return _symbolCount + 1; }
+
+Symbol *Scope::symbolAt(unsigned index) const
+{
+ if (! _symbols)
+ return 0;
+ return _symbols[index];
+}
+
+Scope::iterator Scope::firstSymbol() const
+{ return _symbols; }
+
+Scope::iterator Scope::lastSymbol() const
+{ return _symbols + _symbolCount + 1; }
+
+unsigned Scope::useCount() const
+{ return _useCount + 1; }
+
+Use *Scope::useAt(unsigned index) const
+{ return &_uses[index]; }
+
+void Scope::addUse(unsigned sourceOffset, Name *name)
+{
+ if (++_useCount == _allocatedUses) {
+ _allocatedUses += 4;
+ _uses = reinterpret_cast<Use *>(realloc(_uses, _allocatedUses * sizeof(Use)));
+ }
+
+ Symbol *lastVisibleSymbol;
+ if (_symbolCount == -1)
+ lastVisibleSymbol = owner();
+ else
+ lastVisibleSymbol = _symbols[_symbolCount];
+ _uses[_useCount].init(sourceOffset, name, lastVisibleSymbol);
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Scope.h b/shared/cplusplus/Scope.h
new file mode 100644
index 0000000000..b70b4b5fcc
--- /dev/null
+++ b/shared/cplusplus/Scope.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SCOPE_H
+#define CPLUSPLUS_SCOPE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Use
+{
+public:
+ inline Name *name() const
+ { return _name; }
+
+ inline unsigned sourceOffset() const
+ { return _sourceOffset; }
+
+ inline Symbol *lastVisibleSymbol() const
+ { return _lastVisibleSymbol; }
+
+private:
+ void init(unsigned sourceOffset, Name *name, Symbol *lastVisibleSymbol)
+ {
+ _sourceOffset = sourceOffset;
+ _name = name;
+ _lastVisibleSymbol = lastVisibleSymbol;
+ }
+
+ unsigned _sourceOffset;
+
+ Name *_name;
+ Symbol *_lastVisibleSymbol;
+
+ friend class Scope;
+};
+
+class CPLUSPLUS_EXPORT Scope
+{
+ Scope(const Scope &other);
+ void operator =(const Scope &other);
+
+public:
+ typedef Symbol **iterator;
+
+public:
+ /// Constructs an empty Scope.
+ Scope(ScopedSymbol *owner = 0);
+
+ /// Destroy this scope.
+ ~Scope();
+
+ /// Returns this scope's owner Symbol.
+ ScopedSymbol *owner() const;
+
+ /// Sets this scope's owner Symbol.
+ void setOwner(ScopedSymbol *owner); // ### remove me
+
+ /// Returns the enclosing scope.
+ Scope *enclosingScope() const;
+
+ /// Returns the eclosing namespace scope.
+ Scope *enclosingNamespaceScope() const;
+
+ /// Returns the enclosing class scope.
+ Scope *enclosingClassScope() const;
+
+ /// Returns the enclosing enum scope.
+ Scope *enclosingEnumScope() const;
+
+ /// Rerturns the enclosing function scope.
+ Scope *enclosingFunctionScope() const;
+
+ /// Rerturns the enclosing Block scope.
+ Scope *enclosingBlockScope() const;
+
+ /// Returns true if this scope's owner is a Namespace Symbol.
+ bool isNamespaceScope() const;
+
+ /// Returns true if this scope's owner is a Class Symbol.
+ bool isClassScope() const;
+
+ /// Returns true if this scope's owner is an Enum Symbol.
+ bool isEnumScope() const;
+
+ /// Returns true if this scope's owner is a Block Symbol.
+ bool isBlockScope() const;
+
+ /// Returns true if this scope's owner is a Function Symbol.
+ bool isFunctionScope() const;
+
+ /// Returns true if this scope's owner is a Prototype Symbol.
+ bool isPrototypeScope() const;
+
+ /// Adds a Symbol to this Scope.
+ void enterSymbol(Symbol *symbol);
+
+ /// Returns true if this Scope is empty; otherwise returns false.
+ bool isEmpty() const;
+
+ /// Returns the number of symbols is in the scope.
+ unsigned symbolCount() const;
+
+ /// Returns the Symbol at the given position.
+ Symbol *symbolAt(unsigned index) const;
+
+ /// Returns the first Symbol in the scope.
+ iterator firstSymbol() const;
+
+ /// Returns the last Symbol in the scope.
+ iterator lastSymbol() const;
+
+ Symbol *lookat(Identifier *id) const;
+ Symbol *lookat(int operatorId) const;
+
+ unsigned useCount() const;
+ Use *useAt(unsigned index) const;
+ void addUse(unsigned sourceOffset, Name *name);
+
+private:
+ /// Returns the hash value for the given Symbol.
+ unsigned hashValue(Symbol *symbol) const;
+
+ /// Updates the hash table.
+ void rehash();
+
+private:
+ enum { DefaultInitialSize = 11 };
+
+ ScopedSymbol *_owner;
+
+ Symbol **_symbols;
+ int _allocatedSymbols;
+ int _symbolCount;
+
+ Symbol **_hash;
+ int _hashSize;
+
+ Use *_uses;
+ int _allocatedUses;
+ int _useCount;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SCOPE_H
diff --git a/shared/cplusplus/Semantic.cpp b/shared/cplusplus/Semantic.cpp
new file mode 100644
index 0000000000..306a56d469
--- /dev/null
+++ b/shared/cplusplus/Semantic.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Semantic.h"
+#include "TranslationUnit.h"
+#include "Control.h"
+#include "Scope.h"
+#include "Symbols.h"
+#include "Token.h"
+#include "CheckSpecifier.h"
+#include "CheckDeclaration.h"
+#include "CheckDeclarator.h"
+#include "CheckStatement.h"
+#include "CheckExpression.h"
+#include "CheckName.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class Semantic::Data
+{
+public:
+ Data(Semantic *semantic, Control *control)
+ : semantic(semantic),
+ control(control),
+ visibility(Symbol::Public),
+ methodKey(Function::NormalMethod),
+ checkSpecifier(0),
+ checkDeclaration(0),
+ checkDeclarator(0),
+ checkExpression(0),
+ checkStatement(0),
+ checkName(0)
+ { }
+
+ ~Data()
+ {
+ delete checkSpecifier;
+ delete checkDeclaration;
+ delete checkDeclarator;
+ delete checkExpression;
+ delete checkStatement;
+ delete checkName;
+ }
+
+ Semantic *semantic;
+ Control *control;
+ int visibility;
+ int methodKey;
+ CheckSpecifier *checkSpecifier;
+ CheckDeclaration *checkDeclaration;
+ CheckDeclarator *checkDeclarator;
+ CheckExpression *checkExpression;
+ CheckStatement *checkStatement;
+ CheckName *checkName;
+};
+
+Semantic::Semantic(Control *control)
+{
+ d = new Data(this, control);
+ d->checkSpecifier = new CheckSpecifier(this);
+ d->checkDeclaration = new CheckDeclaration(this);
+ d->checkDeclarator = new CheckDeclarator(this);
+ d->checkExpression = new CheckExpression(this);
+ d->checkStatement = new CheckStatement(this);
+ d->checkName = new CheckName(this);
+}
+
+Semantic::~Semantic()
+{ delete d; }
+
+Control *Semantic::control() const
+{ return d->control; }
+
+FullySpecifiedType Semantic::check(SpecifierAST *specifier, Scope *scope)
+{ return d->checkSpecifier->check(specifier, scope); }
+
+void Semantic::check(DeclarationAST *declaration, Scope *scope, Scope *templateParameters)
+{ d->checkDeclaration->check(declaration, scope, templateParameters); }
+
+FullySpecifiedType Semantic::check(DeclaratorAST *declarator, FullySpecifiedType type,
+ Scope *scope, Name **name)
+{ return d->checkDeclarator->check(declarator, type, scope, name); }
+
+FullySpecifiedType Semantic::check(PtrOperatorAST *ptrOperators, FullySpecifiedType type,
+ Scope *scope)
+{ return d->checkDeclarator->check(ptrOperators, type, scope); }
+
+FullySpecifiedType Semantic::check(ExpressionAST *expression, Scope *scope)
+{ return d->checkExpression->check(expression, scope); }
+
+void Semantic::check(StatementAST *statement, Scope *scope)
+{ d->checkStatement->check(statement, scope); }
+
+Name *Semantic::check(NameAST *name, Scope *scope)
+{ return d->checkName->check(name, scope); }
+
+Name *Semantic::check(NestedNameSpecifierAST *name, Scope *scope)
+{ return d->checkName->check(name, scope); }
+
+int Semantic::currentVisibility() const
+{ return d->visibility; }
+
+int Semantic::switchVisibility(int visibility)
+{
+ int previousVisibility = d->visibility;
+ d->visibility = visibility;
+ return previousVisibility;
+}
+
+int Semantic::currentMethodKey() const
+{ return d->methodKey; }
+
+int Semantic::switchMethodKey(int methodKey)
+{
+ int previousMethodKey = d->methodKey;
+ d->methodKey = methodKey;
+ return previousMethodKey;
+}
+
+int Semantic::visibilityForAccessSpecifier(int tokenKind) const
+{
+ switch (tokenKind) {
+ case T_PUBLIC:
+ return Symbol::Public;
+ case T_PROTECTED:
+ return Symbol::Protected;
+ case T_PRIVATE:
+ return Symbol::Private;
+ case T_SIGNALS:
+ return Symbol::Protected;
+ default:
+ return Symbol::Public;
+ }
+}
+
+int Semantic::visibilityForClassKey(int tokenKind) const
+{
+ switch (tokenKind) {
+ case T_CLASS:
+ return Symbol::Private;
+ case T_STRUCT:
+ case T_UNION:
+ return Symbol::Public;
+ default:
+ return Symbol::Public;
+ }
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Semantic.h b/shared/cplusplus/Semantic.h
new file mode 100644
index 0000000000..dedd471ab6
--- /dev/null
+++ b/shared/cplusplus/Semantic.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SEMANTIC_H
+#define CPLUSPLUS_SEMANTIC_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Semantic
+{
+ Semantic(const Semantic &other);
+ void operator =(const Semantic &other);
+
+public:
+ Semantic(Control *control);
+ virtual ~Semantic();
+
+ Control *control() const;
+
+ FullySpecifiedType check(SpecifierAST *specifier, Scope *scope);
+
+ FullySpecifiedType check(DeclaratorAST *declarator, FullySpecifiedType type,
+ Scope *scope, Name **name = 0); // ### ugly
+
+ FullySpecifiedType check(PtrOperatorAST *ptrOperators, FullySpecifiedType type,
+ Scope *scope);
+
+ FullySpecifiedType check(ExpressionAST *expression, Scope *scope);
+
+ void check(DeclarationAST *declaration, Scope *scope, Scope *templateParameters = 0);
+
+ void check(StatementAST *statement, Scope *scope);
+
+ Name *check(NameAST *name, Scope *scope);
+
+ Name *check(NestedNameSpecifierAST *name, Scope *scope);
+
+ int currentVisibility() const;
+ int switchVisibility(int visibility);
+
+ int currentMethodKey() const;
+ int switchMethodKey(int methodKey);
+
+ int visibilityForClassKey(int tokenKind) const;
+ int visibilityForAccessSpecifier(int tokenKind) const;
+
+private:
+ class Data;
+ friend class Data;
+ Data *d;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SEMANTIC_H
diff --git a/shared/cplusplus/SemanticCheck.cpp b/shared/cplusplus/SemanticCheck.cpp
new file mode 100644
index 0000000000..65efec0f2c
--- /dev/null
+++ b/shared/cplusplus/SemanticCheck.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "SemanticCheck.h"
+#include "Semantic.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+SemanticCheck::SemanticCheck(Semantic *semantic)
+ : ASTVisitor(semantic->control()),
+ _semantic(semantic)
+{ }
+
+SemanticCheck::~SemanticCheck()
+{ }
+
+Semantic *SemanticCheck::semantic() const
+{ return _semantic; }
+
+Control *SemanticCheck::control() const
+{ return _semantic->control(); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/SemanticCheck.h b/shared/cplusplus/SemanticCheck.h
new file mode 100644
index 0000000000..a0380a905c
--- /dev/null
+++ b/shared/cplusplus/SemanticCheck.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SEMANTICCHECK_H
+#define CPLUSPLUS_SEMANTICCHECK_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTVisitor.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT SemanticCheck: public ASTVisitor
+{
+public:
+ SemanticCheck(Semantic *semantic);
+ virtual ~SemanticCheck();
+
+ Control *control() const;
+ Semantic *semantic() const;
+
+private:
+ Semantic *_semantic;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SEMANTICCHECK_H
diff --git a/shared/cplusplus/Symbol.cpp b/shared/cplusplus/Symbol.cpp
new file mode 100644
index 0000000000..e2dca2a328
--- /dev/null
+++ b/shared/cplusplus/Symbol.cpp
@@ -0,0 +1,421 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Symbol.h"
+#include "Symbols.h"
+#include "Control.h"
+#include "Names.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "MemoryPool.h"
+#include "SymbolVisitor.h"
+#include "NameVisitor.h"
+#include <cstddef>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class Symbol::HashCode: protected NameVisitor
+{
+public:
+ HashCode()
+ : _value(0)
+ { }
+
+ virtual ~HashCode()
+ { }
+
+ unsigned operator()(Name *name)
+ {
+ unsigned previousValue = switchValue(0);
+ accept(name);
+ return switchValue(previousValue);
+ }
+
+protected:
+ unsigned switchValue(unsigned value)
+ {
+ unsigned previousValue = _value;
+ _value = value;
+ return previousValue;
+ }
+
+ virtual void visit(NameId *name)
+ { _value = name->identifier()->hashCode(); }
+
+ virtual void visit(TemplateNameId *name)
+ { _value = name->identifier()->hashCode(); }
+
+ virtual void visit(DestructorNameId *name)
+ { _value = name->identifier()->hashCode(); }
+
+ virtual void visit(OperatorNameId *name)
+ { _value = unsigned(name->kind()); }
+
+ virtual void visit(ConversionNameId *)
+ { _value = 0; } // ### TODO: implement me
+
+ virtual void visit(QualifiedNameId *name)
+ { _value = operator()(name->unqualifiedNameId()); }
+
+private:
+ unsigned _value;
+};
+
+class Symbol::IdentityForName: protected NameVisitor
+{
+public:
+ IdentityForName()
+ : _identity(0)
+ { }
+
+ virtual ~IdentityForName()
+ { }
+
+ Name *operator()(Name *name)
+ {
+ Name *previousIdentity = switchIdentity(0);
+ accept(name);
+ return switchIdentity(previousIdentity);
+ }
+
+protected:
+ Name *switchIdentity(Name *identity)
+ {
+ Name *previousIdentity = _identity;
+ _identity = identity;
+ return previousIdentity;
+ }
+
+ virtual void visit(NameId *name)
+ { _identity = name; }
+
+ virtual void visit(TemplateNameId *name)
+ { _identity = name; }
+
+ virtual void visit(DestructorNameId *name)
+ { _identity = name; }
+
+ virtual void visit(OperatorNameId *name)
+ { _identity = name; }
+
+ virtual void visit(ConversionNameId *name)
+ { _identity = name; }
+
+ virtual void visit(QualifiedNameId *name)
+ { _identity = name->unqualifiedNameId(); }
+
+private:
+ Name *_identity;
+};
+
+Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : _control(translationUnit->control()),
+ _sourceLocation(sourceLocation),
+ _sourceOffset(0),
+ _name(0),
+ _hashCode(0),
+ _storage(Symbol::NoStorage),
+ _visibility(Symbol::Public),
+ _scope(0),
+ _index(0),
+ _next(0)
+{
+ if (sourceLocation)
+ _sourceOffset = translationUnit->tokenAt(sourceLocation).offset;
+
+ 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))
+ visitSymbol0(visitor);
+ visitor->postVisit(this);
+}
+
+void Symbol::visitSymbol(Symbol *symbol, SymbolVisitor *visitor)
+{
+ if (! symbol)
+ return;
+
+ symbol->visitSymbol(visitor);
+}
+
+unsigned Symbol::sourceLocation() const
+{ return _sourceLocation; }
+
+unsigned Symbol::sourceOffset() const
+{ return _sourceOffset; }
+
+unsigned Symbol::line() const
+{
+ unsigned line = 0, column = 0;
+ StringLiteral *fileId = 0;
+ translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
+ return line;
+}
+
+unsigned Symbol::column() const
+{
+#ifdef CPLUSPLUS_WITH_COLUMNS
+ unsigned line = 0, column = 0;
+ StringLiteral *fileId = 0;
+ translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
+ return column;
+#else
+ return 0;
+#endif
+}
+
+StringLiteral *Symbol::fileId() const
+{
+ unsigned line = 0, column = 0;
+ StringLiteral *fileId = 0;
+ translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
+ return fileId;
+}
+
+const char *Symbol::fileName() const
+{ return fileId()->chars(); }
+
+unsigned Symbol::fileNameLength() const
+{ return fileId()->size(); }
+
+Name *Symbol::identity() const
+{
+ IdentityForName id;
+ return id(_name);
+}
+
+Name *Symbol::name() const
+{ return _name; }
+
+void Symbol::setName(Name *name)
+{
+ _name = name;
+
+ if (! _name)
+ _hashCode = 0;
+ else {
+ IdentityForName identityForName;
+ HashCode hh;
+ _hashCode = hh(identityForName(_name));
+ }
+}
+
+Scope *Symbol::scope() const
+{ return _scope; }
+
+void Symbol::setScope(Scope *scope)
+{
+ assert(! _scope);
+ _scope = scope;
+}
+
+unsigned Symbol::index() const
+{ return _index; }
+
+Symbol *Symbol::next() const
+{ return _next; }
+
+unsigned Symbol::hashCode() const
+{ return _hashCode; }
+
+int Symbol::storage() const
+{ return _storage; }
+
+void Symbol::setStorage(int storage)
+{ _storage = storage; }
+
+int Symbol::visibility() const
+{ return _visibility; }
+
+void Symbol::setVisibility(int visibility)
+{ _visibility = visibility; }
+
+bool Symbol::isFriend() const
+{ return _storage == Friend; }
+
+bool Symbol::isRegister() const
+{ return _storage == Register; }
+
+bool Symbol::isStatic() const
+{ return _storage == Static; }
+
+bool Symbol::isExtern() const
+{ return _storage == Extern; }
+
+bool Symbol::isMutable() const
+{ return _storage == Mutable; }
+
+bool Symbol::isTypedef() const
+{ return _storage == Typedef; }
+
+bool Symbol::isPublic() const
+{ return _visibility == Public; }
+
+bool Symbol::isProtected() const
+{ return _visibility == Protected; }
+
+bool Symbol::isPrivate() const
+{ return _visibility == Private; }
+
+bool Symbol::isScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this) != 0; }
+
+bool Symbol::isEnum() const
+{ return dynamic_cast<const Enum *>(this) != 0; }
+
+bool Symbol::isFunction() const
+{ return dynamic_cast<const Function *>(this) != 0; }
+
+bool Symbol::isNamespace() const
+{ return dynamic_cast<const Namespace *>(this) != 0; }
+
+bool Symbol::isClass() const
+{ return dynamic_cast<const Class *>(this) != 0; }
+
+bool Symbol::isBlock() const
+{ return dynamic_cast<const Block *>(this) != 0; }
+
+bool Symbol::isUsingNamespaceDirective() const
+{ return dynamic_cast<const UsingNamespaceDirective *>(this) != 0; }
+
+bool Symbol::isUsingDeclaration() const
+{ return dynamic_cast<const UsingDeclaration *>(this) != 0; }
+
+bool Symbol::isDeclaration() const
+{ return dynamic_cast<const Declaration *>(this) != 0; }
+
+bool Symbol::isArgument() const
+{ return dynamic_cast<const Argument *>(this) != 0; }
+
+bool Symbol::isBaseClass() const
+{ return dynamic_cast<const BaseClass *>(this) != 0; }
+
+const ScopedSymbol *Symbol::asScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this); }
+
+const Enum *Symbol::asEnum() const
+{ return dynamic_cast<const Enum *>(this); }
+
+const Function *Symbol::asFunction() const
+{ return dynamic_cast<const Function *>(this); }
+
+const Namespace *Symbol::asNamespace() const
+{ return dynamic_cast<const Namespace *>(this); }
+
+const Class *Symbol::asClass() const
+{ return dynamic_cast<const Class *>(this); }
+
+const Block *Symbol::asBlock() const
+{ return dynamic_cast<const Block *>(this); }
+
+const UsingNamespaceDirective *Symbol::asUsingNamespaceDirective() const
+{ return dynamic_cast<const UsingNamespaceDirective *>(this); }
+
+const UsingDeclaration *Symbol::asUsingDeclaration() const
+{ return dynamic_cast<const UsingDeclaration *>(this); }
+
+const Declaration *Symbol::asDeclaration() const
+{ return dynamic_cast<const Declaration *>(this); }
+
+const Argument *Symbol::asArgument() const
+{ return dynamic_cast<const Argument *>(this); }
+
+const BaseClass *Symbol::asBaseClass() const
+{ return dynamic_cast<const BaseClass *>(this); }
+
+ScopedSymbol *Symbol::asScopedSymbol()
+{ return dynamic_cast<ScopedSymbol *>(this); }
+
+Enum *Symbol::asEnum()
+{ return dynamic_cast<Enum *>(this); }
+
+Function *Symbol::asFunction()
+{ return dynamic_cast<Function *>(this); }
+
+Namespace *Symbol::asNamespace()
+{ return dynamic_cast<Namespace *>(this); }
+
+Class *Symbol::asClass()
+{ return dynamic_cast<Class *>(this); }
+
+Block *Symbol::asBlock()
+{ return dynamic_cast<Block *>(this); }
+
+UsingNamespaceDirective *Symbol::asUsingNamespaceDirective()
+{ return dynamic_cast<UsingNamespaceDirective *>(this); }
+
+UsingDeclaration *Symbol::asUsingDeclaration()
+{ return dynamic_cast<UsingDeclaration *>(this); }
+
+Declaration *Symbol::asDeclaration()
+{ return dynamic_cast<Declaration *>(this); }
+
+Argument *Symbol::asArgument()
+{ return dynamic_cast<Argument *>(this); }
+
+BaseClass *Symbol::asBaseClass()
+{ return dynamic_cast<BaseClass *>(this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Symbol.h b/shared/cplusplus/Symbol.h
new file mode 100644
index 0000000000..95777c2c72
--- /dev/null
+++ b/shared/cplusplus/Symbol.h
@@ -0,0 +1,266 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SYMBOL_H
+#define CPLUSPLUS_SYMBOL_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Symbol
+{
+ Symbol(const Symbol &other);
+ void operator =(const Symbol &other);
+
+public:
+ /// Storage class specifier
+ enum Storage {
+ NoStorage = 0,
+ Friend,
+ Register,
+ Static,
+ Extern,
+ Mutable,
+ Typedef
+ };
+
+ /// Access specifier.
+ enum Visibility {
+ Public,
+ Protected,
+ Private
+ };
+
+public:
+ /// Constructs a Symbol with the given source location, name and translation unit.
+ Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+
+ /// 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;
+
+ /// Returns this Symbol's column number.
+ unsigned column() const;
+
+ /// Returns this Symbol's file name.
+ StringLiteral *fileId() const;
+
+ /// Returns this Symbol's file name.
+ const char *fileName() const;
+
+ /// Returns this Symbol's file name length.
+ unsigned fileNameLength() const;
+
+ /// Returns this Symbol's name.
+ Name *name() const;
+
+ /// Sets this Symbol's name.
+ void setName(Name *name); // ### dangerous
+
+ /// Returns this Symbol's storage class specifier.
+ int storage() const;
+
+ /// Sets this Symbol's storage class specifier.
+ void setStorage(int storage);
+
+ /// Returns this Symbol's visibility.
+ int visibility() const;
+
+ /// Sets this Symbol's visibility.
+ void setVisibility(int visibility);
+
+ /// Returns this Symbol's scope.
+ Scope *scope() const;
+
+ /// Returns the next chained Symbol.
+ Symbol *next() const;
+
+ /// Returns true if this Symbol has friend storage specifier.
+ bool isFriend() const;
+
+ /// Returns true if this Symbol has register storage specifier.
+ bool isRegister() const;
+
+ /// Returns true if this Symbol has static storage specifier.
+ bool isStatic() const;
+
+ /// Returns true if this Symbol has extern storage specifier.
+ bool isExtern() const;
+
+ /// Returns true if this Symbol has mutable storage specifier.
+ bool isMutable() const;
+
+ /// Returns true if this Symbol has typedef storage specifier.
+ bool isTypedef() const;
+
+ /// Returns true if this Symbol's visibility is public.
+ bool isPublic() const;
+
+ /// Returns true if this Symbol's visibility is protected.
+ bool isProtected() const;
+
+ /// Returns true if this Symbol's visibility is private.
+ bool isPrivate() const;
+
+ /// Returns true if this Symbol is a ScopedSymbol.
+ bool isScopedSymbol() const;
+
+ /// Returns true if this Symbol is an Enum.
+ bool isEnum() const;
+
+ /// Returns true if this Symbol is an Function.
+ bool isFunction() const;
+
+ /// Returns true if this Symbol is a Namespace.
+ bool isNamespace() const;
+
+ /// Returns true if this Symbol is a Class.
+ bool isClass() const;
+
+ /// Returns true if this Symbol is a Block.
+ bool isBlock() const;
+
+ /// Returns true if this Symbol is a UsingNamespaceDirective.
+ bool isUsingNamespaceDirective() const;
+
+ /// Returns true if this Symbol is a UsingDeclaration.
+ bool isUsingDeclaration() const;
+
+ /// Returns true if this Symbol is a Declaration.
+ bool isDeclaration() const;
+
+ /// Returns true if this Symbol is an Argument.
+ bool isArgument() const;
+
+ /// Returns true if this Symbol is a BaseClass.
+ bool isBaseClass() const;
+
+ const ScopedSymbol *asScopedSymbol() const;
+ const Enum *asEnum() const;
+ const Function *asFunction() const;
+ const Namespace *asNamespace() const;
+ const Class *asClass() const;
+ const Block *asBlock() const;
+ const UsingNamespaceDirective *asUsingNamespaceDirective() const;
+ const UsingDeclaration *asUsingDeclaration() const;
+ const Declaration *asDeclaration() const;
+ const Argument *asArgument() const;
+ const BaseClass *asBaseClass() const;
+
+ ScopedSymbol *asScopedSymbol();
+ Enum *asEnum();
+ Function *asFunction();
+ Namespace *asNamespace();
+ Class *asClass();
+ Block *asBlock();
+ UsingNamespaceDirective *asUsingNamespaceDirective();
+ UsingDeclaration *asUsingDeclaration();
+ Declaration *asDeclaration();
+ Argument *asArgument();
+ BaseClass *asBaseClass();
+
+ /// Returns this Symbol's type.
+ virtual FullySpecifiedType type() const = 0;
+
+ /// Returns this Symbol's hash value.
+ unsigned hashCode() const;
+
+ /// Returns this Symbol's index.
+ unsigned index() const;
+
+ Name *identity() const;
+
+ void setScope(Scope *scope); // ### make me private
+
+ void visitSymbol(SymbolVisitor *visitor);
+ static void visitSymbol(Symbol *symbol, SymbolVisitor *visitor);
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor) = 0;
+
+ TranslationUnit *translationUnit() const;
+
+private:
+ Control *_control;
+ unsigned _sourceLocation;
+ unsigned _sourceOffset;
+ Name *_name;
+ unsigned _hashCode;
+ int _storage;
+ int _visibility;
+ Scope *_scope;
+ unsigned _index;
+ Symbol *_next;
+
+ class IdentityForName;
+ class HashCode;
+
+ friend class Scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SYMBOL_H
diff --git a/shared/cplusplus/SymbolVisitor.cpp b/shared/cplusplus/SymbolVisitor.cpp
new file mode 100644
index 0000000000..39422bd810
--- /dev/null
+++ b/shared/cplusplus/SymbolVisitor.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "SymbolVisitor.h"
+#include "Symbol.h"
+
+CPLUSPLUS_USE_NAMESPACE
+
+SymbolVisitor::SymbolVisitor()
+{ }
+
+SymbolVisitor::~SymbolVisitor()
+{ }
+
+void SymbolVisitor::accept(Symbol *symbol)
+{ Symbol::visitSymbol(symbol, this); }
+
diff --git a/shared/cplusplus/SymbolVisitor.h b/shared/cplusplus/SymbolVisitor.h
new file mode 100644
index 0000000000..bf91fe7814
--- /dev/null
+++ b/shared/cplusplus/SymbolVisitor.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef SYMBOLVISITOR_H
+#define SYMBOLVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT SymbolVisitor
+{
+ SymbolVisitor(const SymbolVisitor &other);
+ void operator =(const SymbolVisitor &other);
+
+public:
+ SymbolVisitor();
+ virtual ~SymbolVisitor();
+
+ void accept(Symbol *symbol);
+
+ virtual bool preVisit(Symbol *) { return true; }
+ virtual void postVisit(Symbol *) {}
+
+ virtual bool visit(UsingNamespaceDirective *) { return true; }
+ virtual bool visit(UsingDeclaration *) { return true; }
+ virtual bool visit(Declaration *) { return true; }
+ virtual bool visit(Argument *) { return true; }
+ virtual bool visit(BaseClass *) { return true; }
+ virtual bool visit(Enum *) { return true; }
+ virtual bool visit(Function *) { return true; }
+ virtual bool visit(Namespace *) { return true; }
+ virtual bool visit(Class *) { return true; }
+ virtual bool visit(Block *) { return true; }
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // SYMBOLVISITOR_H
diff --git a/shared/cplusplus/Symbols.cpp b/shared/cplusplus/Symbols.cpp
new file mode 100644
index 0000000000..b56235aff0
--- /dev/null
+++ b/shared/cplusplus/Symbols.cpp
@@ -0,0 +1,484 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Symbols.h"
+#include "Names.h"
+#include "TypeVisitor.h"
+#include "SymbolVisitor.h"
+#include "Scope.h"
+#include <cstdlib>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+UsingNamespaceDirective::UsingNamespaceDirective(TranslationUnit *translationUnit,
+ unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name)
+{ }
+
+UsingNamespaceDirective::~UsingNamespaceDirective()
+{ }
+
+FullySpecifiedType UsingNamespaceDirective::type() const
+{ return FullySpecifiedType(); }
+
+void UsingNamespaceDirective::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+UsingDeclaration::UsingDeclaration(TranslationUnit *translationUnit,
+ unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name)
+{ }
+
+UsingDeclaration::~UsingDeclaration()
+{ }
+
+FullySpecifiedType UsingDeclaration::type() const
+{ return FullySpecifiedType(); }
+
+void UsingDeclaration::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name),
+ _templateParameters(0)
+{ }
+
+Declaration::~Declaration()
+{ delete _templateParameters; }
+
+unsigned Declaration::templateParameterCount() const
+{
+ if (! _templateParameters)
+ return 0;
+ return _templateParameters->symbolCount();
+}
+
+Symbol *Declaration::templateParameterAt(unsigned index) const
+{ return _templateParameters->symbolAt(index); }
+
+Scope *Declaration::templateParameters() const
+{ return _templateParameters; }
+
+void Declaration::setTemplateParameters(Scope *templateParameters)
+{ _templateParameters = templateParameters; }
+
+void Declaration::setType(FullySpecifiedType type)
+{ _type = type; }
+
+FullySpecifiedType Declaration::type() const
+{ return _type; }
+
+void Declaration::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Argument::Argument(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name),
+ _initializer(false)
+{ }
+
+Argument::~Argument()
+{ }
+
+bool Argument::hasInitializer() const
+{ return _initializer; }
+
+void Argument::setInitializer(bool hasInitializer)
+{ _initializer = hasInitializer; }
+
+void Argument::setType(FullySpecifiedType type)
+{ _type = type; }
+
+FullySpecifiedType Argument::type() const
+{ return _type; }
+
+void Argument::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Function::Function(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name),
+ _templateParameters(0),
+ _flags(0)
+{ _arguments = new Scope(this); }
+
+Function::~Function()
+{
+ delete _templateParameters;
+ delete _arguments;
+}
+
+bool Function::isNormal() const
+{ return _methodKey == NormalMethod; }
+
+bool Function::isSignal() const
+{ return _methodKey == SignalMethod; }
+
+bool Function::isSlot() const
+{ return _methodKey == SlotMethod; }
+
+int Function::methodKey() const
+{ return _methodKey; }
+
+void Function::setMethodKey(int key)
+{ _methodKey = key; }
+
+unsigned Function::templateParameterCount() const
+{
+ if (! _templateParameters)
+ return 0;
+ return _templateParameters->symbolCount();
+}
+
+Symbol *Function::templateParameterAt(unsigned index) const
+{ return _templateParameters->symbolAt(index); }
+
+Scope *Function::templateParameters() const
+{ return _templateParameters; }
+
+void Function::setTemplateParameters(Scope *templateParameters)
+{ _templateParameters = templateParameters; }
+
+bool Function::isEqualTo(const Type *other) const
+{
+ const Function *o = other->asFunction();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r || (l && l->isEqualTo(r))) {
+ if (_arguments->symbolCount() != o->_arguments->symbolCount())
+ return false;
+ else if (! _returnType.isEqualTo(o->_returnType))
+ return false;
+ for (unsigned i = 0; i < _arguments->symbolCount(); ++i) {
+ Symbol *l = _arguments->symbolAt(i);
+ Symbol *r = o->_arguments->symbolAt(i);
+ if (! l->type().isEqualTo(r->type()))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void Function::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType Function::type() const
+{ return FullySpecifiedType(const_cast<Function *>(this)); }
+
+FullySpecifiedType Function::returnType() const
+{ return _returnType; }
+
+void Function::setReturnType(FullySpecifiedType returnType)
+{ _returnType = returnType; }
+
+unsigned Function::argumentCount() const
+{
+ if (! _arguments)
+ return 0;
+
+ return _arguments->symbolCount();
+}
+
+Symbol *Function::argumentAt(unsigned index) const
+{ return _arguments->symbolAt(index); }
+
+Scope *Function::arguments() const
+{ return _arguments; }
+
+bool Function::isVariadic() const
+{ return _isVariadic; }
+
+void Function::setVariadic(bool isVariadic)
+{ _isVariadic = isVariadic; }
+
+bool Function::isConst() const
+{ return _isConst; }
+
+void Function::setConst(bool isConst)
+{ _isConst = isConst; }
+
+bool Function::isVolatile() const
+{ return _isVolatile; }
+
+void Function::setVolatile(bool isVolatile)
+{ _isVolatile = isVolatile; }
+
+bool Function::isPureVirtual() const
+{ return _isPureVirtual; }
+
+void Function::setPureVirtual(bool isPureVirtual)
+{ _isPureVirtual = isPureVirtual; }
+
+void Function::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < _arguments->symbolCount(); ++i) {
+ visitSymbol(_arguments->symbolAt(i), visitor);
+ }
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+ScopedSymbol::ScopedSymbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name)
+{ _members = new Scope(this); }
+
+ScopedSymbol::~ScopedSymbol()
+{ delete _members; }
+
+unsigned ScopedSymbol::memberCount() const
+{
+ if (! _members)
+ return 0;
+ return _members->symbolCount();
+}
+
+Symbol *ScopedSymbol::memberAt(unsigned index) const
+{
+ if (! _members)
+ return 0;
+ return _members->symbolAt(index);
+}
+
+Scope *ScopedSymbol::members() const
+{ return _members; }
+
+void ScopedSymbol::addMember(Symbol *member)
+{ _members->enterSymbol(member); }
+
+Block::Block(TranslationUnit *translationUnit, unsigned sourceLocation)
+ : ScopedSymbol(translationUnit, sourceLocation, /*name = */ 0)
+{ }
+
+Block::~Block()
+{ }
+
+FullySpecifiedType Block::type() const
+{ return FullySpecifiedType(); }
+
+void Block::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Enum::Enum(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name)
+{ }
+
+Enum::~Enum()
+{ }
+
+FullySpecifiedType Enum::type() const
+{ return FullySpecifiedType(const_cast<Enum *>(this)); }
+
+bool Enum::isEqualTo(const Type *other) const
+{
+ const Enum *o = other->asEnum();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r)
+ return true;
+ else if (! l)
+ return false;
+ return l->isEqualTo(r);
+}
+
+void Enum::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+void Enum::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+Namespace::Namespace(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name)
+{ }
+
+Namespace::~Namespace()
+{ }
+
+bool Namespace::isEqualTo(const Type *other) const
+{
+ const Namespace *o = other->asNamespace();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r || (l && l->isEqualTo(r)))
+ return true;
+ return false;
+}
+
+void Namespace::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+void Namespace::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+FullySpecifiedType Namespace::type() const
+{ return FullySpecifiedType(const_cast<Namespace *>(this)); }
+
+BaseClass::BaseClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name),
+ _isVirtual(false)
+{ }
+
+BaseClass::~BaseClass()
+{ }
+
+FullySpecifiedType BaseClass::type() const
+{ return FullySpecifiedType(); }
+
+bool BaseClass::isVirtual() const
+{ return _isVirtual; }
+
+void BaseClass::setVirtual(bool isVirtual)
+{ _isVirtual = isVirtual; }
+
+void BaseClass::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Class::Class(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name),
+ _key(ClassKey),
+ _templateParameters(0)
+{ }
+
+Class::~Class()
+{ delete _templateParameters; }
+
+bool Class::isClass() const
+{ return _key == ClassKey; }
+
+bool Class::isStruct() const
+{ return _key == StructKey; }
+
+bool Class::isUnion() const
+{ return _key == UnionKey; }
+
+Class::Key Class::classKey() const
+{ return _key; }
+
+void Class::setClassKey(Key key)
+{ _key = key; }
+
+unsigned Class::templateParameterCount() const
+{
+ if (! _templateParameters)
+ return 0;
+ return _templateParameters->symbolCount();
+}
+
+Symbol *Class::templateParameterAt(unsigned index) const
+{ return _templateParameters->symbolAt(index); }
+
+Scope *Class::templateParameters() const
+{ return _templateParameters; }
+
+void Class::setTemplateParameters(Scope *templateParameters)
+{ _templateParameters = templateParameters; }
+
+void Class::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+unsigned Class::baseClassCount() const
+{ return _baseClasses.count(); }
+
+BaseClass *Class::baseClassAt(unsigned index) const
+{ return _baseClasses.at(index); }
+
+void Class::addBaseClass(BaseClass *baseClass)
+{ _baseClasses.push_back(baseClass); }
+
+FullySpecifiedType Class::type() const
+{ return FullySpecifiedType(const_cast<Class *>(this)); }
+
+bool Class::isEqualTo(const Type *other) const
+{
+ const Class *o = other->asClass();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r || (l && l->isEqualTo(r)))
+ return true;
+ else
+ return false;
+}
+
+void Class::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < _baseClasses.size(); ++i) {
+ visitSymbol(_baseClasses.at(i), visitor);
+ }
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Symbols.h b/shared/cplusplus/Symbols.h
new file mode 100644
index 0000000000..fe373b3412
--- /dev/null
+++ b/shared/cplusplus/Symbols.h
@@ -0,0 +1,338 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SYMBOLS_H
+#define CPLUSPLUS_SYMBOLS_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Symbol.h"
+#include "Type.h"
+#include "FullySpecifiedType.h"
+#include "Array.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT UsingNamespaceDirective: public Symbol
+{
+public:
+ UsingNamespaceDirective(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~UsingNamespaceDirective();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UsingDeclaration: public Symbol
+{
+public:
+ UsingDeclaration(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~UsingDeclaration();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT Declaration: public Symbol
+{
+public:
+ Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Declaration();
+
+ unsigned templateParameterCount() const;
+ Symbol *templateParameterAt(unsigned index) const;
+
+ Scope *templateParameters() const;
+ void setTemplateParameters(Scope *templateParameters);
+
+ void setType(FullySpecifiedType type);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ FullySpecifiedType _type;
+ Scope *_templateParameters;
+};
+
+class CPLUSPLUS_EXPORT Argument: public Symbol
+{
+public:
+ Argument(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Argument();
+
+ void setType(FullySpecifiedType type);
+
+ bool hasInitializer() const;
+ void setInitializer(bool hasInitializer);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ FullySpecifiedType _type;
+ bool _initializer: 1;
+};
+
+class CPLUSPLUS_EXPORT ScopedSymbol: public Symbol
+{
+public:
+ ScopedSymbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~ScopedSymbol();
+
+ unsigned memberCount() const;
+ Symbol *memberAt(unsigned index) const;
+ Scope *members() const;
+ void addMember(Symbol *member);
+
+private:
+ Scope *_members;
+};
+
+class CPLUSPLUS_EXPORT Block: public ScopedSymbol
+{
+public:
+ Block(TranslationUnit *translationUnit, unsigned sourceLocation);
+ virtual ~Block();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT Enum: public ScopedSymbol, public Type
+{
+public:
+ Enum(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Enum();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT Function: public ScopedSymbol, public Type
+{
+public:
+ enum MethodKey {
+ NormalMethod,
+ SlotMethod,
+ SignalMethod
+ };
+
+public:
+ Function(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Function();
+
+ bool isNormal() const;
+ bool isSignal() const;
+ bool isSlot() const;
+ int methodKey() const;
+ void setMethodKey(int key);
+
+ unsigned templateParameterCount() const;
+ Symbol *templateParameterAt(unsigned index) const;
+
+ Scope *templateParameters() const;
+ void setTemplateParameters(Scope *templateParameters);
+
+ FullySpecifiedType returnType() const;
+ void setReturnType(FullySpecifiedType returnType);
+
+ unsigned argumentCount() const;
+ Symbol *argumentAt(unsigned index) const;
+ Scope *arguments() const;
+
+ bool isVariadic() const;
+ void setVariadic(bool isVariadic);
+
+ bool isConst() const;
+ void setConst(bool isConst);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isPureVirtual() const;
+ void setPureVirtual(bool isPureVirtual);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Name *_name;
+ Scope *_templateParameters;
+ FullySpecifiedType _returnType;
+ union {
+ unsigned _flags;
+
+ struct {
+ unsigned _isVariadic: 1;
+ unsigned _isPureVirtual: 1;
+ unsigned _isConst: 1;
+ unsigned _isVolatile: 1;
+ unsigned _methodKey: 3;
+ };
+ };
+ Scope *_arguments;
+};
+
+class CPLUSPLUS_EXPORT Namespace: public ScopedSymbol, public Type
+{
+public:
+ Namespace(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Namespace();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BaseClass: public Symbol
+{
+public:
+ BaseClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~BaseClass();
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ bool _isVirtual;
+};
+
+class CPLUSPLUS_EXPORT Class: public ScopedSymbol, public Type
+{
+public:
+ Class(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Class();
+
+ enum Key {
+ ClassKey,
+ StructKey,
+ UnionKey
+ };
+
+ bool isClass() const;
+ bool isStruct() const;
+ bool isUnion() const;
+ Key classKey() const;
+ void setClassKey(Key key);
+
+ unsigned templateParameterCount() const;
+ Symbol *templateParameterAt(unsigned index) const;
+
+ Scope *templateParameters() const;
+ void setTemplateParameters(Scope *templateParameters);
+
+ unsigned baseClassCount() const;
+ BaseClass *baseClassAt(unsigned index) const;
+ void addBaseClass(BaseClass *baseClass);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Key _key;
+ Scope *_templateParameters;
+ Array<BaseClass *> _baseClasses;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SYMBOLS_H
diff --git a/shared/cplusplus/Token.cpp b/shared/cplusplus/Token.cpp
new file mode 100644
index 0000000000..755df25e58
--- /dev/null
+++ b/shared/cplusplus/Token.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Token.h"
+#include "Literals.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+static const char *token_names[] = {
+ (""), ("<error>"),
+
+ ("<comment>"),
+
+ ("<identifier>"), ("<int literal>"), ("<float literal>"), ("<char literal>"),
+ ("<wide char literal>"), ("<string literal>"), ("<wide char literal>"),
+ ("<angle string literal>"),
+
+ ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"),
+ (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"),
+ ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="),
+ ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"),
+ ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"),
+ ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
+
+ ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"),
+ ("class"), ("const"), ("const_cast"), ("continue"), ("default"),
+ ("delete"), ("do"), ("double"), ("dynamic_cast"), ("else"), ("enum"),
+ ("explicit"), ("export"), ("extern"), ("false"), ("float"), ("for"),
+ ("friend"), ("goto"), ("if"), ("inline"), ("int"), ("long"),
+ ("mutable"), ("namespace"), ("new"), ("operator"), ("private"),
+ ("protected"), ("public"), ("register"), ("reinterpret_cast"),
+ ("return"), ("short"), ("signed"), ("sizeof"), ("static"),
+ ("static_cast"), ("struct"), ("switch"), ("template"), ("this"),
+ ("throw"), ("true"), ("try"), ("typedef"), ("typeid"), ("typename"),
+ ("union"), ("unsigned"), ("using"), ("virtual"), ("void"),
+ ("volatile"), ("wchar_t"), ("while"),
+
+ ("__attribute__"), ("__typeof__"),
+
+ ("SIGNAL"), ("SLOT"), ("Q_SIGNALS"), ("Q_SLOTS")
+};
+
+Token::Token() :
+ flags(0), offset(0), ptr(0)
+{
+}
+
+Token::~Token()
+{
+}
+
+void Token::reset()
+{
+ flags = 0;
+ offset = 0;
+ ptr = 0;
+}
+
+const char *Token::name(int kind)
+{ return token_names[kind]; }
+
+const char *Token::spell() const
+{
+ switch (kind) {
+ case T_IDENTIFIER:
+ return identifier->chars();
+
+ case T_INT_LITERAL:
+ case T_FLOAT_LITERAL:
+ case T_CHAR_LITERAL:
+ case T_STRING_LITERAL:
+ case T_ANGLE_STRING_LITERAL:
+ case T_WIDE_CHAR_LITERAL:
+ case T_WIDE_STRING_LITERAL:
+ return literal->chars();
+
+ default:
+ return token_names[kind];
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Token.h b/shared/cplusplus/Token.h
new file mode 100644
index 0000000000..4ceaaf0196
--- /dev/null
+++ b/shared/cplusplus/Token.h
@@ -0,0 +1,290 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TOKEN_H
+#define CPLUSPLUS_TOKEN_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+enum Kind {
+ T_EOF_SYMBOL = 0,
+ T_ERROR,
+
+ T_COMMENT,
+ T_IDENTIFIER,
+
+ T_FIRST_LITERAL,
+ T_INT_LITERAL = T_FIRST_LITERAL,
+ T_FLOAT_LITERAL,
+ T_CHAR_LITERAL,
+ T_WIDE_CHAR_LITERAL,
+ T_STRING_LITERAL,
+ T_WIDE_STRING_LITERAL,
+ T_ANGLE_STRING_LITERAL,
+ T_LAST_LITERAL = T_ANGLE_STRING_LITERAL,
+
+ T_FIRST_OPERATOR,
+ T_AMPER = T_FIRST_OPERATOR,
+ T_AMPER_AMPER,
+ T_AMPER_EQUAL,
+ T_ARROW,
+ T_ARROW_STAR,
+ T_CARET,
+ T_CARET_EQUAL,
+ T_COLON,
+ T_COLON_COLON,
+ T_COMMA,
+ T_SLASH,
+ T_SLASH_EQUAL,
+ T_DOT,
+ T_DOT_DOT_DOT,
+ T_DOT_STAR,
+ T_EQUAL,
+ T_EQUAL_EQUAL,
+ T_EXCLAIM,
+ T_EXCLAIM_EQUAL,
+ T_GREATER,
+ T_GREATER_EQUAL,
+ T_GREATER_GREATER,
+ T_GREATER_GREATER_EQUAL,
+ T_LBRACE,
+ T_LBRACKET,
+ T_LESS,
+ T_LESS_EQUAL,
+ T_LESS_LESS,
+ T_LESS_LESS_EQUAL,
+ T_LPAREN,
+ T_MINUS,
+ T_MINUS_EQUAL,
+ T_MINUS_MINUS,
+ T_PERCENT,
+ T_PERCENT_EQUAL,
+ T_PIPE,
+ T_PIPE_EQUAL,
+ T_PIPE_PIPE,
+ T_PLUS,
+ T_PLUS_EQUAL,
+ T_PLUS_PLUS,
+ T_POUND,
+ T_POUND_POUND,
+ T_QUESTION,
+ T_RBRACE,
+ T_RBRACKET,
+ T_RPAREN,
+ T_SEMICOLON,
+ T_STAR,
+ T_STAR_EQUAL,
+ T_TILDE,
+ T_TILDE_EQUAL,
+ T_LAST_OPERATOR = T_TILDE_EQUAL,
+
+ T_FIRST_KEYWORD,
+ T_ASM = T_FIRST_KEYWORD,
+ T_AUTO,
+ T_BOOL,
+ T_BREAK,
+ T_CASE,
+ T_CATCH,
+ T_CHAR,
+ T_CLASS,
+ T_CONST,
+ T_CONST_CAST,
+ T_CONTINUE,
+ T_DEFAULT,
+ T_DELETE,
+ T_DO,
+ T_DOUBLE,
+ T_DYNAMIC_CAST,
+ T_ELSE,
+ T_ENUM,
+ T_EXPLICIT,
+ T_EXPORT,
+ T_EXTERN,
+ T_FALSE,
+ T_FLOAT,
+ T_FOR,
+ T_FRIEND,
+ T_GOTO,
+ T_IF,
+ T_INLINE,
+ T_INT,
+ T_LONG,
+ T_MUTABLE,
+ T_NAMESPACE,
+ T_NEW,
+ T_OPERATOR,
+ T_PRIVATE,
+ T_PROTECTED,
+ T_PUBLIC,
+ T_REGISTER,
+ T_REINTERPRET_CAST,
+ T_RETURN,
+ T_SHORT,
+ T_SIGNED,
+ T_SIZEOF,
+ T_STATIC,
+ T_STATIC_CAST,
+ T_STRUCT,
+ T_SWITCH,
+ T_TEMPLATE,
+ T_THIS,
+ T_THROW,
+ T_TRUE,
+ T_TRY,
+ T_TYPEDEF,
+ T_TYPEID,
+ T_TYPENAME,
+ T_UNION,
+ T_UNSIGNED,
+ T_USING,
+ T_VIRTUAL,
+ T_VOID,
+ T_VOLATILE,
+ T_WCHAR_T,
+ T_WHILE,
+
+ T___ATTRIBUTE__,
+ T___TYPEOF__,
+
+ T_FIRST_QT_KEYWORD,
+
+ // Qt keywords
+ T_SIGNAL = T_FIRST_QT_KEYWORD,
+ T_SLOT,
+ T_SIGNALS,
+ T_SLOTS,
+
+ T_LAST_KEYWORD = T_SLOTS,
+
+ // ### aliases
+ T___ASM = T_ASM,
+ T___ASM__ = T_ASM,
+
+ T_TYPEOF = T___TYPEOF__,
+ T___TYPEOF = T___TYPEOF__,
+
+ T___INLINE = T_INLINE,
+ T___INLINE__ = T_INLINE,
+
+ T___CONST = T_CONST,
+ T___CONST__ = T_CONST,
+
+ T___VOLATILE = T_VOLATILE,
+ T___VOLATILE__ = T_VOLATILE,
+
+ T___ATTRIBUTE = T___ATTRIBUTE__
+};
+
+class CPLUSPLUS_EXPORT Token
+{
+public:
+ Token();
+ ~Token();
+
+ inline bool is(unsigned k) const { return kind == k; }
+ inline bool isNot(unsigned k) const { return kind != k; }
+ const char *spell() const;
+ void reset();
+
+ inline unsigned begin() const
+ { return offset; }
+
+ inline unsigned end() const
+ { return offset + length; }
+
+ inline bool isLiteral() const
+ { return kind >= T_FIRST_LITERAL && kind <= T_LAST_LITERAL; }
+
+ inline bool isOperator() const
+ { return kind >= T_FIRST_OPERATOR && kind <= T_LAST_OPERATOR; }
+
+ inline bool isKeyword() const
+ { return kind >= T_FIRST_KEYWORD && kind < T_FIRST_QT_KEYWORD; }
+
+ static const char *name(int kind);
+
+public:
+ union {
+ unsigned flags;
+
+ struct {
+ unsigned kind : 8;
+ unsigned newline : 1;
+ unsigned whitespace : 1;
+ unsigned joined : 1;
+ unsigned expanded : 1;
+ unsigned pad : 4;
+ unsigned length : 16;
+ };
+ };
+
+ unsigned offset;
+
+ union {
+ void *ptr;
+ Literal *literal;
+ NumericLiteral *number;
+ StringLiteral *string;
+ Identifier *identifier;
+ unsigned close_brace;
+ unsigned lineno;
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TOKEN_H
diff --git a/shared/cplusplus/TranslationUnit.cpp b/shared/cplusplus/TranslationUnit.cpp
new file mode 100644
index 0000000000..06a7a3af4e
--- /dev/null
+++ b/shared/cplusplus/TranslationUnit.cpp
@@ -0,0 +1,434 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "TranslationUnit.h"
+#include "Control.h"
+#include "Parser.h"
+#include "Lexer.h"
+#include "MemoryPool.h"
+#include "AST.h"
+#include "Literals.h"
+#include "DiagnosticClient.h"
+#include <stack>
+#include <cstdlib>
+#include <cstdarg>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+TranslationUnit::TranslationUnit(Control *control, StringLiteral *fileId)
+ : _control(control),
+ _fileId(fileId),
+ _firstSourceChar(0),
+ _lastSourceChar(0),
+ _pool(0),
+ _ast(0),
+ _flags(0)
+{
+ _tokens = new Array<Token, 8>();
+ _previousTranslationUnit = control->switchTranslationUnit(this);
+ _pool = new MemoryPool();
+}
+
+TranslationUnit::~TranslationUnit()
+{
+ (void) _control->switchTranslationUnit(_previousTranslationUnit);
+ delete _tokens;
+ delete _pool;
+}
+
+bool TranslationUnit::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void TranslationUnit::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+Control *TranslationUnit::control() const
+{ return _control; }
+
+StringLiteral *TranslationUnit::fileId() const
+{ return _fileId; }
+
+const char *TranslationUnit::fileName() const
+{ return _fileId->chars(); }
+
+unsigned TranslationUnit::fileNameLength() const
+{ return _fileId->size(); }
+
+const char *TranslationUnit::firstSourceChar() const
+{ return _firstSourceChar; }
+
+const char *TranslationUnit::lastSourceChar() const
+{ return _lastSourceChar; }
+
+unsigned TranslationUnit::sourceLength() const
+{ return _lastSourceChar - _firstSourceChar; }
+
+void TranslationUnit::setSource(const char *source, unsigned size)
+{
+ _firstSourceChar = source;
+ _lastSourceChar = source + size;
+}
+
+unsigned TranslationUnit::tokenCount() const
+{ return _tokens->size(); }
+
+const Token &TranslationUnit::tokenAt(unsigned index) const
+{ return _tokens->at(index); }
+
+int TranslationUnit::tokenKind(unsigned index) const
+{ return _tokens->at(index).kind; }
+
+Identifier *TranslationUnit::identifier(unsigned index) const
+{ return _tokens->at(index).identifier; }
+
+Literal *TranslationUnit::literal(unsigned index) const
+{ return _tokens->at(index).literal; }
+
+StringLiteral *TranslationUnit::stringLiteral(unsigned index) const
+{ return _tokens->at(index).string; }
+
+NumericLiteral *TranslationUnit::numericLiteral(unsigned index) const
+{ return _tokens->at(index).number; }
+
+unsigned TranslationUnit::matchingBrace(unsigned index) const
+{ return _tokens->at(index).close_brace; }
+
+MemoryPool *TranslationUnit::memoryPool() const
+{ return _pool; }
+
+TranslationUnitAST *TranslationUnit::ast() const
+{ return _ast; }
+
+bool TranslationUnit::isTokenized() const
+{ return _tokenized; }
+
+bool TranslationUnit::isParsed() const
+{ return _parsed; }
+
+void TranslationUnit::tokenize()
+{
+ if (isTokenized())
+ return;
+
+ _tokenized = true;
+
+ Lexer lex(this);
+ lex.setQtMocRunEnabled(_qtMocRunEnabled);
+
+ std::stack<unsigned> braces;
+ _tokens->push_back(Token()); // the first token needs to be invalid!
+
+ pushLineOffset(0);
+ pushPreprocessorLine(0, 1, fileId());
+
+ Identifier *lineId = control()->findOrInsertIdentifier("line");
+
+ Token tk;
+ do {
+ lex(&tk);
+
+ _Lrecognize:
+ if (tk.is(T_POUND)) {
+ unsigned offset = tk.offset;
+ lex(&tk);
+ if (! tk.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
+ lex(&tk);
+ if (! tk.newline && tk.is(T_INT_LITERAL)) {
+ unsigned line = (unsigned) strtoul(tk.spell(), 0, 0);
+ lex(&tk);
+ if (! tk.newline && tk.is(T_STRING_LITERAL)) {
+ StringLiteral *fileName = control()->findOrInsertFileName(tk.string->chars(),
+ tk.string->size());
+ pushPreprocessorLine(offset, line, fileName);
+ lex(&tk);
+ }
+ }
+ while (tk.isNot(T_EOF_SYMBOL) && ! tk.newline)
+ lex(&tk);
+ goto _Lrecognize;
+ } else if (tk.kind == T_LBRACE) {
+ braces.push(_tokens->size());
+ } else if (tk.kind == T_RBRACE && ! braces.empty()) {
+ const unsigned open_brace_index = braces.top();
+ braces.pop();
+ (*_tokens)[open_brace_index].close_brace = _tokens->size();
+ }
+ _tokens->push_back(tk);
+ } while (tk.kind);
+
+ for (; ! braces.empty(); braces.pop()) {
+ unsigned open_brace_index = braces.top();
+ (*_tokens)[open_brace_index].close_brace = _tokens->size();
+ }
+}
+
+bool TranslationUnit::skipFunctionBody() const
+{ return _skipFunctionBody; }
+
+void TranslationUnit::setSkipFunctionBody(bool skipFunctionBody)
+{ _skipFunctionBody = skipFunctionBody; }
+
+void TranslationUnit::parse()
+{
+ if (isParsed())
+ return;
+
+ if (! isTokenized())
+ tokenize();
+
+ Parser parser(this);
+ parser.setQtMocRunEnabled(_qtMocRunEnabled);
+ parser.parseTranslationUnit(_ast);
+}
+
+void TranslationUnit::pushLineOffset(unsigned offset)
+{ _lineOffsets.push_back(offset); }
+
+void TranslationUnit::pushPreprocessorLine(unsigned offset,
+ unsigned line,
+ StringLiteral *fileName)
+{ _ppLines.push_back(PPLine(offset, line, fileName)); }
+
+unsigned TranslationUnit::findLineNumber(unsigned offset) const
+{
+ std::vector<unsigned>::const_iterator it =
+ std::lower_bound(_lineOffsets.begin(), _lineOffsets.end(), offset);
+
+ if (it != _lineOffsets.begin())
+ --it;
+
+ return it - _lineOffsets.begin();
+}
+
+TranslationUnit::PPLine TranslationUnit::findPreprocessorLine(unsigned offset) const
+{
+ std::vector<PPLine>::const_iterator it =
+ std::lower_bound(_ppLines.begin(), _ppLines.end(), PPLine(offset));
+
+ if (it != _ppLines.begin())
+ --it;
+
+ return *it;
+}
+
+unsigned TranslationUnit::findColumnNumber(unsigned offset, unsigned lineNumber) const
+{
+ if (! offset)
+ return 0;
+
+ return offset - _lineOffsets[lineNumber];
+}
+
+void TranslationUnit::getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{ return getPosition(tokenAt(index).offset, line, column, fileName); }
+
+void TranslationUnit::getPosition(unsigned tokenOffset,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{
+ unsigned lineNumber = findLineNumber(tokenOffset);
+ unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber);
+ const PPLine ppLine = findPreprocessorLine(tokenOffset);
+
+ lineNumber -= findLineNumber(ppLine.offset) + 1;
+ lineNumber += ppLine.line;
+
+ if (line)
+ *line = lineNumber;
+
+ if (column)
+ *column = columnNumber;
+
+ if (fileName)
+ *fileName = ppLine.fileName;
+}
+
+bool TranslationUnit::blockErrors(bool block)
+{
+ bool previous = _blockErrors;
+ _blockErrors = block;
+ return previous;
+}
+
+void TranslationUnit::warning(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Warning, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "warning: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+}
+
+void TranslationUnit::error(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Error, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "error: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+}
+
+void TranslationUnit::fatal(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Fatal, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "fatal: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out)
+{
+ unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)];
+ for (const char *cp = _firstSourceChar + lineOffset + 1; *cp && *cp != '\n'; ++cp) {
+ fputc(*cp, out);
+ }
+ fputc('\n', out);
+
+ const char *end = _firstSourceChar + lineOffset + 1 + column - 1;
+ for (const char *cp = _firstSourceChar + lineOffset + 1; cp != end; ++cp) {
+ if (*cp != '\t')
+ fputc(' ', out);
+ else
+ fputc('\t', out);
+ }
+ fputc('^', out);
+ fputc('\n', out);
+}
+
+void TranslationUnit::resetAST()
+{
+ delete _pool;
+ _pool = 0;
+}
+
+void TranslationUnit::release()
+{
+ resetAST();
+ delete _tokens;
+ _tokens = 0;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/TranslationUnit.h b/shared/cplusplus/TranslationUnit.h
new file mode 100644
index 0000000000..07929534d3
--- /dev/null
+++ b/shared/cplusplus/TranslationUnit.h
@@ -0,0 +1,189 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TRANSLATIONUNIT_H
+#define CPLUSPLUS_TRANSLATIONUNIT_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+#include "Token.h"
+#include "Array.h"
+#include <cstdio>
+#include <vector> // ### remove me
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT TranslationUnit
+{
+ TranslationUnit(const TranslationUnit &other);
+ void operator =(const TranslationUnit &other);
+
+public:
+ TranslationUnit(Control *control, StringLiteral *fileId);
+ ~TranslationUnit();
+
+ Control *control() const;
+
+ StringLiteral *fileId() const;
+ const char *fileName() const;
+ unsigned fileNameLength() const;
+
+ const char *firstSourceChar() const;
+ const char *lastSourceChar() const;
+ unsigned sourceLength() const;
+
+ void setSource(const char *source, unsigned size);
+
+ unsigned tokenCount() const;
+ const Token &tokenAt(unsigned index) const;
+ int tokenKind(unsigned index) const;
+
+ unsigned matchingBrace(unsigned index) const;
+ Identifier *identifier(unsigned index) const;
+ Literal *literal(unsigned index) const;
+ StringLiteral *stringLiteral(unsigned index) const;
+ NumericLiteral *numericLiteral(unsigned index) const;
+
+ MemoryPool *memoryPool() const;
+ TranslationUnitAST *ast() const;
+
+ bool blockErrors(bool block);
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ void warning(unsigned index, const char *fmt, ...);
+ void error(unsigned index, const char *fmt, ...);
+ void fatal(unsigned index, const char *fmt, ...);
+
+ bool isTokenized() const;
+ void tokenize();
+
+ bool skipFunctionBody() const;
+ void setSkipFunctionBody(bool skipFunctionBody);
+
+ bool isParsed() const;
+ void parse();
+
+ void resetAST();
+ void release();
+
+ void getPosition(unsigned offset,
+ unsigned *line,
+ unsigned *column = 0,
+ StringLiteral **fileName = 0) const;
+
+ void getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column = 0,
+ StringLiteral **fileName = 0) const;
+
+ void pushLineOffset(unsigned offset);
+ void pushPreprocessorLine(unsigned offset,
+ unsigned line,
+ StringLiteral *fileName);
+
+public:
+ struct PPLine {
+ unsigned offset;
+ unsigned line;
+ StringLiteral *fileName;
+
+ PPLine(unsigned offset = 0,
+ unsigned line = 0,
+ StringLiteral *fileName = 0)
+ : offset(offset), line(line), fileName(fileName)
+ { }
+
+ bool operator == (const PPLine &other) const
+ { return offset == other.offset; }
+
+ bool operator != (const PPLine &other) const
+ { return offset != other.offset; }
+
+ bool operator < (const PPLine &other) const
+ { return offset < other.offset; }
+ };
+
+private:
+ unsigned findLineNumber(unsigned offset) const;
+ unsigned findColumnNumber(unsigned offset, unsigned lineNumber) const;
+ PPLine findPreprocessorLine(unsigned offset) const;
+ void showErrorLine(unsigned index, unsigned column, FILE *out);
+
+ Control *_control;
+ StringLiteral *_fileId;
+ const char *_firstSourceChar;
+ const char *_lastSourceChar;
+ Array<Token, 8> *_tokens;
+ std::vector<unsigned> _lineOffsets;
+ std::vector<PPLine> _ppLines;
+ MemoryPool *_pool;
+ TranslationUnitAST *_ast;
+ TranslationUnit *_previousTranslationUnit;
+ union {
+ unsigned _flags;
+ struct {
+ unsigned _tokenized: 1;
+ unsigned _parsed: 1;
+ unsigned _blockErrors: 1;
+ unsigned _skipFunctionBody: 1;
+ unsigned _qtMocRunEnabled: 1;
+ };
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TRANSLATIONUNIT_H
diff --git a/shared/cplusplus/Type.cpp b/shared/cplusplus/Type.cpp
new file mode 100644
index 0000000000..7948dbe94a
--- /dev/null
+++ b/shared/cplusplus/Type.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Type.h"
+#include "TypeVisitor.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Type::Type()
+{ }
+
+Type::~Type()
+{ }
+
+bool Type::isVoidType() const
+{ return dynamic_cast<const VoidType *>(this) != 0; }
+
+bool Type::isIntegerType() const
+{ return dynamic_cast<const IntegerType *>(this) != 0; }
+
+bool Type::isFloatType() const
+{ return dynamic_cast<const FloatType *>(this) != 0; }
+
+bool Type::isPointerType() const
+{ return dynamic_cast<const PointerType *>(this) != 0; }
+
+bool Type::isPointerToMemberType() const
+{ return dynamic_cast<const PointerToMemberType *>(this) != 0; }
+
+bool Type::isReferenceType() const
+{ return dynamic_cast<const ReferenceType *>(this) != 0; }
+
+bool Type::isArrayType() const
+{ return dynamic_cast<const ArrayType *>(this) != 0; }
+
+bool Type::isNamedType() const
+{ return dynamic_cast<const NamedType *>(this) != 0; }
+
+bool Type::isFunction() const
+{ return dynamic_cast<const Function *>(this) != 0; }
+
+bool Type::isNamespace() const
+{ return dynamic_cast<const Namespace *>(this) != 0; }
+
+bool Type::isClass() const
+{ return dynamic_cast<const Class *>(this) != 0; }
+
+bool Type::isEnum() const
+{ return dynamic_cast<const Enum *>(this) != 0; }
+
+bool Type::isScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this) != 0; }
+
+const VoidType *Type::asVoidType() const
+{ return dynamic_cast<const VoidType *>(this); }
+
+const IntegerType *Type::asIntegerType() const
+{ return dynamic_cast<const IntegerType *>(this); }
+
+const FloatType *Type::asFloatType() const
+{ return dynamic_cast<const FloatType *>(this); }
+
+const PointerType *Type::asPointerType() const
+{ return dynamic_cast<const PointerType *>(this); }
+
+const PointerToMemberType *Type::asPointerToMemberType() const
+{ return dynamic_cast<const PointerToMemberType *>(this); }
+
+const ReferenceType *Type::asReferenceType() const
+{ return dynamic_cast<const ReferenceType *>(this); }
+
+const ArrayType *Type::asArrayType() const
+{ return dynamic_cast<const ArrayType *>(this); }
+
+const NamedType *Type::asNamedType() const
+{ return dynamic_cast<const NamedType *>(this); }
+
+const Function *Type::asFunction() const
+{ return dynamic_cast<const Function *>(this); }
+
+const Namespace *Type::asNamespace() const
+{ return dynamic_cast<const Namespace *>(this); }
+
+const Class *Type::asClass() const
+{ return dynamic_cast<const Class *>(this); }
+
+const Enum *Type::asEnum() const
+{ return dynamic_cast<const Enum *>(this); }
+
+const ScopedSymbol *Type::asScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this); }
+
+VoidType *Type::asVoidType()
+{ return dynamic_cast<VoidType *>(this); }
+
+IntegerType *Type::asIntegerType()
+{ return dynamic_cast<IntegerType *>(this); }
+
+FloatType *Type::asFloatType()
+{ return dynamic_cast<FloatType *>(this); }
+
+PointerType *Type::asPointerType()
+{ return dynamic_cast<PointerType *>(this); }
+
+PointerToMemberType *Type::asPointerToMemberType()
+{ return dynamic_cast<PointerToMemberType *>(this); }
+
+ReferenceType *Type::asReferenceType()
+{ return dynamic_cast<ReferenceType *>(this); }
+
+ArrayType *Type::asArrayType()
+{ return dynamic_cast<ArrayType *>(this); }
+
+NamedType *Type::asNamedType()
+{ return dynamic_cast<NamedType *>(this); }
+
+Function *Type::asFunction()
+{ return dynamic_cast<Function *>(this); }
+
+Namespace *Type::asNamespace()
+{ return dynamic_cast<Namespace *>(this); }
+
+Class *Type::asClass()
+{ return dynamic_cast<Class *>(this); }
+
+Enum *Type::asEnum()
+{ return dynamic_cast<Enum *>(this); }
+
+ScopedSymbol *Type::asScopedSymbol()
+{ return dynamic_cast<ScopedSymbol *>(this); }
+
+void Type::accept(TypeVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ accept0(visitor);
+ visitor->postVisit(this);
+}
+
+void Type::accept(Type *type, TypeVisitor *visitor)
+{
+ if (! type)
+ return;
+
+ type->accept(visitor);
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Type.h b/shared/cplusplus/Type.h
new file mode 100644
index 0000000000..250b0ef1d6
--- /dev/null
+++ b/shared/cplusplus/Type.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TYPE_H
+#define CPLUSPLUS_TYPE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Type
+{
+ Type(const Type &other);
+ void operator =(const Type &other);
+
+public:
+ Type();
+ virtual ~Type();
+
+ bool isVoidType() const;
+ bool isIntegerType() const;
+ bool isFloatType() const;
+ bool isPointerType() const;
+ bool isPointerToMemberType() const;
+ bool isReferenceType() const;
+ bool isArrayType() const;
+ bool isNamedType() const;
+ bool isFunction() const;
+ bool isNamespace() const;
+ bool isClass() const;
+ bool isEnum() const;
+ bool isScopedSymbol() const;
+
+ const VoidType *asVoidType() const;
+ const IntegerType *asIntegerType() const;
+ const FloatType *asFloatType() const;
+ const PointerType *asPointerType() const;
+ const PointerToMemberType *asPointerToMemberType() const;
+ const ReferenceType *asReferenceType() const;
+ const ArrayType *asArrayType() const;
+ const NamedType *asNamedType() const;
+ const Function *asFunction() const;
+ const Namespace *asNamespace() const;
+ const Class *asClass() const;
+ const Enum *asEnum() const;
+ const ScopedSymbol *asScopedSymbol() const;
+
+ VoidType *asVoidType();
+ IntegerType *asIntegerType();
+ FloatType *asFloatType();
+ PointerType *asPointerType();
+ PointerToMemberType *asPointerToMemberType();
+ ReferenceType *asReferenceType();
+ ArrayType *asArrayType();
+ NamedType *asNamedType();
+ Function *asFunction();
+ Namespace *asNamespace();
+ Class *asClass();
+ Enum *asEnum();
+ ScopedSymbol *asScopedSymbol();
+
+ void accept(TypeVisitor *visitor);
+ static void accept(Type *type, TypeVisitor *visitor);
+
+ virtual bool isEqualTo(const Type *other) const = 0;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor) = 0;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TYPE_H
diff --git a/shared/cplusplus/TypeVisitor.cpp b/shared/cplusplus/TypeVisitor.cpp
new file mode 100644
index 0000000000..34fe26c929
--- /dev/null
+++ b/shared/cplusplus/TypeVisitor.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "TypeVisitor.h"
+#include "Type.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+TypeVisitor::TypeVisitor()
+{ }
+
+TypeVisitor::~TypeVisitor()
+{ }
+
+void TypeVisitor::accept(Type *type)
+{ Type::accept(type, this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/TypeVisitor.h b/shared/cplusplus/TypeVisitor.h
new file mode 100644
index 0000000000..de638b2e33
--- /dev/null
+++ b/shared/cplusplus/TypeVisitor.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TYPEVISITOR_H
+#define CPLUSPLUS_TYPEVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT TypeVisitor
+{
+ TypeVisitor(const TypeVisitor &other);
+ void operator =(const TypeVisitor &other);
+
+public:
+ TypeVisitor();
+ virtual ~TypeVisitor();
+
+ void accept(Type *type);
+
+ virtual bool preVisit(Type *) { return true; }
+ virtual void postVisit(Type *) {}
+
+ virtual void visit(VoidType *) {}
+ virtual void visit(IntegerType *) {}
+ virtual void visit(FloatType *) {}
+ virtual void visit(PointerToMemberType *) {}
+ virtual void visit(PointerType *) {}
+ virtual void visit(ReferenceType *) {}
+ virtual void visit(ArrayType *) {}
+ virtual void visit(NamedType *) {}
+ virtual void visit(Function *) {}
+ virtual void visit(Namespace *) {}
+ virtual void visit(Class *) {}
+ virtual void visit(Enum *) {}
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TYPEVISITOR_H
diff --git a/shared/cplusplus/cplusplus.pri b/shared/cplusplus/cplusplus.pri
new file mode 100644
index 0000000000..2b3bb6804d
--- /dev/null
+++ b/shared/cplusplus/cplusplus.pri
@@ -0,0 +1,73 @@
+
+DEPENDPATH += $$PWD
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/AST.h \
+ $$PWD/ASTVisitor.h \
+ $$PWD/ASTfwd.h \
+ $$PWD/Array.h \
+ $$PWD/CPlusPlusForwardDeclarations.h \
+ $$PWD/CheckDeclaration.h \
+ $$PWD/CheckDeclarator.h \
+ $$PWD/CheckExpression.h \
+ $$PWD/CheckName.h \
+ $$PWD/CheckSpecifier.h \
+ $$PWD/CheckStatement.h \
+ $$PWD/Control.h \
+ $$PWD/CoreTypes.h \
+ $$PWD/DiagnosticClient.h \
+ $$PWD/FullySpecifiedType.h \
+ $$PWD/Lexer.h \
+ $$PWD/LiteralTable.h \
+ $$PWD/Literals.h \
+ $$PWD/MemoryPool.h \
+ $$PWD/Name.h \
+ $$PWD/NameVisitor.h \
+ $$PWD/Names.h \
+ $$PWD/Parser.h \
+ $$PWD/Scope.h \
+ $$PWD/Semantic.h \
+ $$PWD/SemanticCheck.h \
+ $$PWD/Symbol.h \
+ $$PWD/Symbols.h \
+ $$PWD/SymbolVisitor.h \
+ $$PWD/Token.h \
+ $$PWD/TranslationUnit.h \
+ $$PWD/Type.h \
+ $$PWD/TypeVisitor.h
+
+SOURCES += \
+ $$PWD/AST.cpp \
+ $$PWD/ASTVisitor.cpp \
+ $$PWD/Array.cpp \
+ $$PWD/CheckDeclaration.cpp \
+ $$PWD/CheckDeclarator.cpp \
+ $$PWD/CheckExpression.cpp \
+ $$PWD/CheckName.cpp \
+ $$PWD/CheckSpecifier.cpp \
+ $$PWD/CheckStatement.cpp \
+ $$PWD/Control.cpp \
+ $$PWD/CoreTypes.cpp \
+ $$PWD/DiagnosticClient.cpp \
+ $$PWD/FullySpecifiedType.cpp \
+ $$PWD/Keywords.cpp \
+ $$PWD/Lexer.cpp \
+ $$PWD/LiteralTable.cpp \
+ $$PWD/Literals.cpp \
+ $$PWD/MemoryPool.cpp \
+ $$PWD/Name.cpp \
+ $$PWD/NameVisitor.cpp \
+ $$PWD/Names.cpp \
+ $$PWD/Parser.cpp \
+ $$PWD/Scope.cpp \
+ $$PWD/Semantic.cpp \
+ $$PWD/SemanticCheck.cpp \
+ $$PWD/Symbol.cpp \
+ $$PWD/Symbols.cpp \
+ $$PWD/SymbolVisitor.cpp \
+ $$PWD/Token.cpp \
+ $$PWD/TranslationUnit.cpp \
+ $$PWD/Type.cpp \
+ $$PWD/TypeVisitor.cpp
+
diff --git a/shared/designerintegrationv2/README.txt b/shared/designerintegrationv2/README.txt
new file mode 100644
index 0000000000..f5351eaa64
--- /dev/null
+++ b/shared/designerintegrationv2/README.txt
@@ -0,0 +1,10 @@
+This is a new Designer integration, started on 28.02.2008.
+
+The reason for it is the introduction of layout caching
+in Qt 4.4, which unearthed a lot of mainwindow-size related
+bugs in Designer and all integrations.
+
+The goal of it is to have a closed layout chain from
+integration top level to form window.
+
+Friedemann
diff --git a/shared/designerintegrationv2/designerintegration.pri b/shared/designerintegrationv2/designerintegration.pri
new file mode 100644
index 0000000000..f3a02f6eba
--- /dev/null
+++ b/shared/designerintegrationv2/designerintegration.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH *= $$PWD $$PWD/..
+
+SOURCES += $$PWD/widgethost.cpp \
+ $$PWD/sizehandlerect.cpp \
+ $$PWD/formresizer.cpp
+
+HEADERS += $$PWD/widgethost.h \
+ $$PWD/sizehandlerect.h \
+ $$PWD/formresizer.h \
+ $$PWD/widgethostconstants.h \
+ $$PWD/../namespace_global.h
diff --git a/shared/designerintegrationv2/formresizer.cpp b/shared/designerintegrationv2/formresizer.cpp
new file mode 100644
index 0000000000..1f3815efe5
--- /dev/null
+++ b/shared/designerintegrationv2/formresizer.cpp
@@ -0,0 +1,194 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formresizer.h"
+#include "sizehandlerect.h"
+#include "widgethostconstants.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPalette>
+#include <QtGui/QLayout>
+#include <QtGui/QFrame>
+#include <QtGui/QResizeEvent>
+#include <QtCore/QDebug>
+
+enum { debugFormResizer=0 };
+
+using namespace SharedTools::Internal;
+
+FormResizer::FormResizer(QWidget *parent) :
+ QWidget(parent),
+ m_frame(new QFrame),
+ m_formWindow(0)
+{
+ // Make the resize grip of a mainwindow form find us as resizable window.
+ setWindowFlags(windowFlags() | Qt::SubWindow);
+ setBackgroundRole(QPalette::Base);
+
+ QVBoxLayout *handleLayout = new QVBoxLayout(this);
+ handleLayout->setMargin(SELECTION_MARGIN);
+ handleLayout->addWidget(m_frame);
+
+ m_frame->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ QVBoxLayout *layout = new QVBoxLayout(m_frame);
+ layout->setMargin(0);
+ // handles
+ m_handles.reserve(SizeHandleRect::Left);
+ for (int i = SizeHandleRect::LeftTop; i <= SizeHandleRect::Left; ++i) {
+ SizeHandleRect *shr = new SizeHandleRect(this, static_cast<SizeHandleRect::Direction>(i), this);
+ connect(shr, SIGNAL(mouseButtonReleased(QRect,QRect)), this, SIGNAL(formWindowSizeChanged(QRect,QRect)));
+ m_handles.push_back(shr);
+ }
+ setState(SelectionHandleActive);
+ updateGeometry();
+}
+
+void FormResizer::updateGeometry()
+{
+ const QRect &geom = m_frame->geometry();
+
+ if (debugFormResizer)
+ qDebug() << "FormResizer::updateGeometry() " << size() << " frame " << geom;
+
+ const int w = SELECTION_HANDLE_SIZE;
+ const int h = SELECTION_HANDLE_SIZE;
+
+ const Handles::iterator hend = m_handles.end();
+ for (Handles::iterator it = m_handles.begin(); it != hend; ++it) {
+ SizeHandleRect *hndl = *it;;
+ switch (hndl->dir()) {
+ case SizeHandleRect::LeftTop:
+ hndl->move(geom.x() - w / 2, geom.y() - h / 2);
+ break;
+ case SizeHandleRect::Top:
+ hndl->move(geom.x() + geom.width() / 2 - w / 2, geom.y() - h / 2);
+ break;
+ case SizeHandleRect::RightTop:
+ hndl->move(geom.x() + geom.width() - w / 2, geom.y() - h / 2);
+ break;
+ case SizeHandleRect::Right:
+ hndl->move(geom.x() + geom.width() - w / 2, geom.y() + geom.height() / 2 - h / 2);
+ break;
+ case SizeHandleRect::RightBottom:
+ hndl->move(geom.x() + geom.width() - w / 2, geom.y() + geom.height() - h / 2);
+ break;
+ case SizeHandleRect::Bottom:
+ hndl->move(geom.x() + geom.width() / 2 - w / 2, geom.y() + geom.height() - h / 2);
+ break;
+ case SizeHandleRect::LeftBottom:
+ hndl->move(geom.x() - w / 2, geom.y() + geom.height() - h / 2);
+ break;
+ case SizeHandleRect::Left:
+ hndl->move(geom.x() - w / 2, geom.y() + geom.height() / 2 - h / 2);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void FormResizer::update()
+{
+ const Handles::iterator hend = m_handles.end();
+ for (Handles::iterator it = m_handles.begin(); it != hend; ++it) {
+ (*it)->update();
+ }
+}
+
+void FormResizer::setState(SelectionHandleState st)
+{
+ if (debugFormResizer)
+ qDebug() << "FormResizer::setState " << st;
+
+ const Handles::iterator hend = m_handles.end();
+ for (Handles::iterator it = m_handles.begin(); it != hend; ++it)
+ (*it)->setState(st);
+}
+
+void FormResizer::setFormWindow(QDesignerFormWindowInterface *fw)
+{
+ if (debugFormResizer)
+ qDebug() << "FormResizer::setFormWindow " << fw;
+ QVBoxLayout *layout = qobject_cast<QVBoxLayout *>(m_frame->layout());
+ Q_ASSERT(layout);
+ if (layout->count())
+ delete layout->takeAt(0);
+ m_formWindow = fw;
+
+ if (m_formWindow)
+ layout->addWidget(m_formWindow);
+ mainContainerChanged();
+ connect(fw, SIGNAL(mainContainerChanged(QWidget*)), this, SLOT(mainContainerChanged()));
+}
+
+void FormResizer::resizeEvent(QResizeEvent *event)
+{
+ if (debugFormResizer)
+ qDebug() << ">FormResizer::resizeEvent" << event->size();
+ updateGeometry();
+ QWidget::resizeEvent(event);
+ if (debugFormResizer)
+ qDebug() << "<FormResizer::resizeEvent";
+}
+
+QSize FormResizer::decorationSize() const
+{
+ const int margin = 2 * SELECTION_MARGIN + 2 * m_frame->lineWidth();
+ return QSize(margin, margin);
+}
+
+QWidget *FormResizer::mainContainer()
+{
+ if (m_formWindow)
+ return m_formWindow->mainContainer();
+ return 0;
+}
+
+void FormResizer::mainContainerChanged()
+{
+ const QSize maxWidgetSize = QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ if (const QWidget *mc = mainContainer()) {
+ // Set Maximum size which is not handled via a hint (as opposed to minimum size)
+ const QSize maxWidgetSize = QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ const QSize formMaxSize = mc->maximumSize();
+ QSize newMaxSize = maxWidgetSize;
+ if (formMaxSize != maxWidgetSize)
+ newMaxSize = formMaxSize + decorationSize();
+ if (debugFormResizer)
+ qDebug() << "FormResizer::mainContainerChanged" << mc << " Size " << mc->size()<< newMaxSize;
+ setMaximumSize(newMaxSize);
+ resize(decorationSize() + mc->size());
+ } else {
+ setMaximumSize(maxWidgetSize);
+ }
+}
diff --git a/shared/designerintegrationv2/formresizer.h b/shared/designerintegrationv2/formresizer.h
new file mode 100644
index 0000000000..fcf6e0d1c5
--- /dev/null
+++ b/shared/designerintegrationv2/formresizer.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMRESIZER_H
+#define FORMRESIZER_H
+
+#include "namespace_global.h"
+
+#include "widgethostconstants.h"
+
+#include <QtGui/QWidget>
+#include <QtCore/QVector>
+
+QT_FORWARD_DECLARE_CLASS(QDesignerFormWindowInterface)
+QT_FORWARD_DECLARE_CLASS(QFrame)
+
+namespace SharedTools {
+namespace Internal {
+
+class SizeHandleRect;
+
+/* A window to embed a form window interface as follows:
+ *
+ * Widget
+ * |
+ * +---+----+
+ * | |
+ * | |
+ * Handles QVBoxLayout [margin: SELECTION_MARGIN]
+ * |
+ * Frame [margin: lineWidth]
+ * |
+ * QVBoxLayout
+ * |
+ * QDesignerFormWindowInterface
+ *
+ * Can be embedded into a QScrollArea. */
+
+class FormResizer : public QWidget
+{
+ Q_OBJECT
+public:
+
+ FormResizer(QWidget *parent = 0);
+
+ void updateGeometry();
+ void setState(SelectionHandleState st);
+ void update();
+
+ void setFormWindow(QDesignerFormWindowInterface *fw);
+
+signals:
+ void formWindowSizeChanged(const QRect &oldGeo, const QRect &newGeo);
+
+protected:
+ virtual void resizeEvent(QResizeEvent *event);
+
+private slots:
+ void mainContainerChanged();
+
+private:
+ QSize decorationSize() const;
+ QWidget *mainContainer();
+
+ QFrame *m_frame;
+ typedef QVector<SizeHandleRect*> Handles;
+ Handles m_handles;
+ QDesignerFormWindowInterface * m_formWindow;
+};
+
+}
+} // namespace SharedTools
+
+#endif // FORMRESIZER_H
diff --git a/shared/designerintegrationv2/sizehandlerect.cpp b/shared/designerintegrationv2/sizehandlerect.cpp
new file mode 100644
index 0000000000..459db47cc3
--- /dev/null
+++ b/shared/designerintegrationv2/sizehandlerect.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "sizehandlerect.h"
+#include "widgethostconstants.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtGui/QMouseEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QFrame>
+#include <QtCore/QDebug>
+
+enum { debugSizeHandle = 0 };
+
+using namespace SharedTools::Internal;
+
+SizeHandleRect::SizeHandleRect(QWidget *parent, Direction d, QWidget *resizable) :
+ QWidget(parent),
+ m_dir(d),
+ m_resizable(resizable),
+ m_state(SelectionHandleOff)
+{
+ setBackgroundRole(QPalette::Text);
+ setAutoFillBackground(true);
+
+ setFixedSize(SELECTION_HANDLE_SIZE, SELECTION_HANDLE_SIZE);
+ setMouseTracking(false);
+ updateCursor();
+}
+
+void SizeHandleRect::updateCursor()
+{
+ switch (m_dir) {
+ case Right:
+ case RightTop:
+ setCursor(Qt::SizeHorCursor);
+ return;
+ case RightBottom:
+ setCursor(Qt::SizeFDiagCursor);
+ return;
+ case LeftBottom:
+ case Bottom:
+ setCursor(Qt::SizeVerCursor);
+ return;
+ default:
+ break;
+ }
+
+ setCursor(Qt::ArrowCursor);
+}
+
+void SizeHandleRect::paintEvent(QPaintEvent *)
+{
+ switch (m_state) {
+ case SelectionHandleOff:
+ break;
+ case SelectionHandleInactive: {
+ QPainter p(this);
+ p.setPen(Qt::red);
+ p.drawRect(0, 0, width() - 1, height() - 1);
+ }
+ break;
+ case SelectionHandleActive: {
+ QPainter p(this);
+ p.setPen(Qt::blue);
+ p.drawRect(0, 0, width() - 1, height() - 1);
+ }
+ break;
+ }
+}
+
+void SizeHandleRect::mousePressEvent(QMouseEvent *e)
+{
+ e->accept();
+
+ if (e->button() != Qt::LeftButton)
+ return;
+
+ m_startSize = m_curSize = m_resizable->size();
+ m_startPos = m_curPos = m_resizable->mapFromGlobal(e->globalPos());
+ if (debugSizeHandle)
+ qDebug() << "SizeHandleRect::mousePressEvent" << m_startSize << m_startPos << m_curPos;
+
+}
+
+void SizeHandleRect::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!(e->buttons() & Qt::LeftButton))
+ return;
+
+ // Try resize with delta against start position.
+ // We don't take little deltas in consecutive move events as this
+ // causes the handle and the mouse cursor to become out of sync
+ // once a min/maxSize limit is hit. When the cursor reenters the valid
+ // areas, it will now snap to it.
+ m_curPos = m_resizable->mapFromGlobal(e->globalPos());
+ QSize delta = QSize(m_curPos.x() - m_startPos.x(), m_curPos.y() - m_startPos.y());
+ switch (m_dir) {
+ case Right:
+ case RightTop: // Only width
+ delta.setHeight(0);
+ break;
+ case RightBottom: // All dimensions
+ break;
+ case LeftBottom:
+ case Bottom: // Only height
+ delta.setWidth(0);
+ break;
+ default:
+ delta = QSize(0, 0);
+ break;
+ }
+ if (delta != QSize(0, 0))
+ tryResize(delta);
+}
+
+void SizeHandleRect::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() != Qt::LeftButton)
+ return;
+
+ e->accept();
+ if (m_startSize != m_curSize) {
+ const QRect startRect = QRect(0, 0, m_startPos.x(), m_startPos.y());
+ const QRect newRect = QRect(0, 0, m_curPos.x(), m_curPos.y());
+ if (debugSizeHandle)
+ qDebug() << "SizeHandleRect::mouseReleaseEvent" << startRect << newRect;
+ emit mouseButtonReleased(startRect, newRect);
+ }
+}
+
+void SizeHandleRect::tryResize(const QSize &delta)
+{
+ // Try resize with delta against start position
+ QSize newSize = m_startSize + delta;
+ newSize = newSize.expandedTo(m_resizable->minimumSizeHint());
+ newSize = newSize.expandedTo(m_resizable->minimumSize());
+ newSize = newSize.boundedTo(m_resizable->maximumSize());
+ if (newSize == m_resizable->size())
+ return;
+ if (debugSizeHandle)
+ qDebug() << "SizeHandleRect::tryResize by (" << m_startSize << '+' << delta << ')' << newSize;
+ m_resizable->resize(newSize);
+ m_curSize = m_resizable->size();
+}
+
+void SizeHandleRect::setState(SelectionHandleState st)
+{
+ if (st == m_state)
+ return;
+ switch (st) {
+ case SelectionHandleOff:
+ hide();
+ break;
+ case SelectionHandleInactive:
+ case SelectionHandleActive:
+ show();
+ raise();
+ break;
+ }
+ m_state = st;
+}
diff --git a/shared/designerintegrationv2/sizehandlerect.h b/shared/designerintegrationv2/sizehandlerect.h
new file mode 100644
index 0000000000..8e03f869c0
--- /dev/null
+++ b/shared/designerintegrationv2/sizehandlerect.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SIZEHANDLERECT_H
+#define SIZEHANDLERECT_H
+
+#include "namespace_global.h"
+
+#include "widgethostconstants.h"
+
+#include <QtGui/QWidget>
+#include <QtCore/QPoint>
+
+namespace SharedTools {
+namespace Internal {
+
+class SizeHandleRect : public QWidget
+{
+ Q_OBJECT
+public:
+ enum Direction { LeftTop, Top, RightTop, Right, RightBottom, Bottom, LeftBottom, Left };
+
+ SizeHandleRect(QWidget *parent, Direction d, QWidget *resizable);
+
+ Direction dir() const { return m_dir; }
+ void updateCursor();
+ void setState(SelectionHandleState st);
+
+signals:
+
+ void mouseButtonReleased(const QRect &, const QRect &);
+
+protected:
+ void paintEvent(QPaintEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+private:
+ void tryResize(const QSize &delta);
+
+private:
+ const Direction m_dir;
+ QPoint m_startPos;
+ QPoint m_curPos;
+ QSize m_startSize;
+ QSize m_curSize;
+ QWidget *m_resizable;
+ SelectionHandleState m_state;
+};
+
+}
+} // namespace SharedTools
+
+
+#endif // SIZEHANDLERECT_H
+
diff --git a/shared/designerintegrationv2/widgethost.cpp b/shared/designerintegrationv2/widgethost.cpp
new file mode 100644
index 0000000000..d7e09b4d54
--- /dev/null
+++ b/shared/designerintegrationv2/widgethost.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "widgethost.h"
+#include "formresizer.h"
+#include "widgethostconstants.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+
+#include <QtGui/QPalette>
+#include <QtGui/QLayout>
+#include <QtGui/QFrame>
+#include <QtGui/QResizeEvent>
+#include <QtCore/QDebug>
+
+using namespace SharedTools;
+
+// ---------- WidgetHost
+WidgetHost::WidgetHost(QWidget *parent, QDesignerFormWindowInterface *formWindow) :
+ QScrollArea(parent),
+ m_formWindow(0),
+ m_formResizer(new Internal::FormResizer)
+{
+ setWidget(m_formResizer);
+ // Re-set flag (gets cleared by QScrollArea): Make the resize grip of a mainwindow form find the resizer as resizable window.
+ m_formResizer->setWindowFlags(m_formResizer->windowFlags() | Qt::SubWindow);
+ setFormWindow(formWindow);
+}
+
+WidgetHost::~WidgetHost()
+{
+ if (m_formWindow)
+ delete m_formWindow;
+}
+
+void WidgetHost::setFormWindow(QDesignerFormWindowInterface *fw)
+{
+ m_formWindow = fw;
+ if (!fw)
+ return;
+
+ m_formResizer->setFormWindow(fw);
+
+ setBackgroundRole(QPalette::Base);
+ m_formWindow->setAutoFillBackground(true);
+ m_formWindow->setBackgroundRole(QPalette::Background);
+
+ connect(m_formResizer, SIGNAL(formWindowSizeChanged(QRect, QRect)),
+ this, SLOT(fwSizeWasChanged(QRect, QRect)));
+}
+
+QSize WidgetHost::formWindowSize() const
+{
+ if (!m_formWindow || !m_formWindow->mainContainer())
+ return QSize();
+ return m_formWindow->mainContainer()->size();
+}
+
+void WidgetHost::fwSizeWasChanged(const QRect &, const QRect &)
+{
+ // newGeo is the mouse coordinates, thus moving the Right will actually emit wrong height
+ emit formWindowSizeChanged(formWindowSize().width(), formWindowSize().height());
+}
+
+void WidgetHost::updateFormWindowSelectionHandles(bool active)
+{
+ Internal::SelectionHandleState state = Internal::SelectionHandleOff;
+ const QDesignerFormWindowCursorInterface *cursor = m_formWindow->cursor();
+ if (cursor->isWidgetSelected(m_formWindow->mainContainer()))
+ state = active ? Internal::SelectionHandleActive : Internal::SelectionHandleInactive;
+
+ m_formResizer->setState(state);
+}
+
+QWidget *WidgetHost::integrationContainer() const
+{
+ return m_formResizer;
+}
diff --git a/shared/designerintegrationv2/widgethost.h b/shared/designerintegrationv2/widgethost.h
new file mode 100644
index 0000000000..392b1c26db
--- /dev/null
+++ b/shared/designerintegrationv2/widgethost.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WIDGETHOST_H
+#define WIDGETHOST_H
+
+#include "namespace_global.h"
+
+#include <QtGui/QScrollArea>
+
+QT_FORWARD_DECLARE_CLASS(QDesignerFormWindowInterface)
+
+namespace SharedTools {
+
+namespace Internal {
+ class FormResizer;
+}
+
+/* A scroll area that embeds a Designer form window */
+
+class WidgetHost : public QScrollArea
+{
+ Q_OBJECT
+public:
+ WidgetHost(QWidget *parent = 0, QDesignerFormWindowInterface *formWindow = 0);
+ virtual ~WidgetHost();
+ // Show handles if active and main container is selected.
+ void updateFormWindowSelectionHandles(bool active);
+
+ inline QDesignerFormWindowInterface *formWindow() const { return m_formWindow; }
+
+ QWidget *integrationContainer() const;
+
+protected:
+ void setFormWindow(QDesignerFormWindowInterface *fw);
+
+signals:
+ void formWindowSizeChanged(int, int);
+
+private slots:
+ void fwSizeWasChanged(const QRect &, const QRect &);
+
+private:
+ QSize formWindowSize() const;
+
+ QDesignerFormWindowInterface *m_formWindow;
+ Internal::FormResizer *m_formResizer;
+ QSize m_oldFakeWidgetSize;
+};
+
+} // namespace SharedTools
+
+#endif // WIDGETHOST_H
+
diff --git a/shared/designerintegrationv2/widgethostconstants.h b/shared/designerintegrationv2/widgethostconstants.h
new file mode 100644
index 0000000000..6555c7f494
--- /dev/null
+++ b/shared/designerintegrationv2/widgethostconstants.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WIDGETHOST_CONSTANTS_H
+#define WIDGETHOST_CONSTANTS_H
+
+namespace SharedTools {
+ namespace Internal {
+ enum { SELECTION_HANDLE_SIZE = 6, SELECTION_MARGIN = 10 };
+ enum SelectionHandleState { SelectionHandleOff, SelectionHandleInactive, SelectionHandleActive };
+ }
+}
+
+#endif //WIDGETHOST_CONSTANTS_H
+
diff --git a/shared/help/bookmarkdialog.ui b/shared/help/bookmarkdialog.ui
new file mode 100644
index 0000000000..7a878f9656
--- /dev/null
+++ b/shared/help/bookmarkdialog.ui
@@ -0,0 +1,146 @@
+<ui version="4.0" >
+ <class>BookmarkDialog</class>
+ <widget class="QDialog" name="BookmarkDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>450</width>
+ <height>135</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Bookmark</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3" >
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Bookmark:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Add in Folder:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLineEdit" name="bookmarkEdit" />
+ </item>
+ <item>
+ <widget class="QComboBox" name="bookmarkFolders" />
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3" >
+ <item>
+ <widget class="QToolButton" name="toolButton" >
+ <property name="minimumSize" >
+ <size>
+ <width>25</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>+</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="treeView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Ignored" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4" >
+ <item>
+ <widget class="QPushButton" name="newFolderButton" >
+ <property name="text" >
+ <string>New Folder</string>
+ </property>
+ </widget>
+ </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>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>BookmarkDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>BookmarkDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/shared/help/bookmarkmanager.cpp b/shared/help/bookmarkmanager.cpp
new file mode 100644
index 0000000000..bc87e1c111
--- /dev/null
+++ b/shared/help/bookmarkmanager.cpp
@@ -0,0 +1,866 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "bookmarkmanager.h"
+#include "centralwidget.h"
+
+#include <QtGui/QMenu>
+#include <QtGui/QIcon>
+#include <QtGui/QStyle>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtCore/QEvent>
+#include <QtGui/QComboBox>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMessageBox>
+#include <QtGui/QHeaderView>
+#include <QtGui/QToolButton>
+#include <QtGui/QPushButton>
+#include <QtGui/QApplication>
+#include <QtHelp/QHelpEngineCore>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QSortFilterProxyModel>
+
+QT_BEGIN_NAMESPACE
+
+BookmarkDialog::BookmarkDialog(BookmarkManager *manager, const QString &title,
+ const QString &url, QWidget *parent)
+ : QDialog(parent)
+ , m_url(url)
+ , m_title(title)
+ , bookmarkManager(manager)
+{
+ installEventFilter(this);
+
+ ui.setupUi(this);
+ ui.bookmarkEdit->setText(title);
+ ui.newFolderButton->setVisible(false);
+ ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ proxyModel = new QSortFilterProxyModel(this);
+ proxyModel->setFilterKeyColumn(0);
+ proxyModel->setDynamicSortFilter(true);
+ proxyModel->setFilterRole(Qt::UserRole + 10);
+ proxyModel->setSourceModel(bookmarkManager->treeBookmarkModel());
+ proxyModel->setFilterRegExp(QRegExp(QLatin1String("Folder"),
+ Qt::CaseSensitive, QRegExp::FixedString));
+ ui.treeView->setModel(proxyModel);
+
+ ui.treeView->expandAll();
+ ui.treeView->setVisible(false);
+ ui.treeView->header()->setVisible(false);
+ ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(addAccepted()));
+ connect(ui.newFolderButton, SIGNAL(clicked()), this, SLOT(addNewFolder()));
+ connect(ui.toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked()));
+ connect(ui.bookmarkEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(textChanged(const QString&)));
+
+ connect(bookmarkManager->treeBookmarkModel(), SIGNAL(itemChanged(QStandardItem*)),
+ this, SLOT(itemChanged(QStandardItem*)));
+
+ connect(ui.bookmarkFolders, SIGNAL(currentIndexChanged(const QString&)), this,
+ SLOT(selectBookmarkFolder(const QString&)));
+
+ connect(ui.treeView, SIGNAL(customContextMenuRequested(const QPoint&)), this,
+ SLOT(customContextMenuRequested(const QPoint&)));
+
+ connect(ui.treeView->selectionModel(),
+ SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
+ this, SLOT(currentChanged(const QModelIndex&, const QModelIndex&)));
+}
+
+BookmarkDialog::~BookmarkDialog()
+{
+}
+
+void BookmarkDialog::addAccepted()
+{
+ const QItemSelection selection = ui.treeView->selectionModel()->selection();
+ const QModelIndexList list = selection.indexes();
+
+ QModelIndex index;
+ if (!list.isEmpty())
+ index = proxyModel->mapToSource(list.at(0));
+
+ bookmarkManager->addNewBookmark(index, ui.bookmarkEdit->text(), m_url);
+ accept();
+}
+
+void BookmarkDialog::addNewFolder()
+{
+ const QItemSelection selection = ui.treeView->selectionModel()->selection();
+ const QModelIndexList list = selection.indexes();
+
+ QModelIndex index;
+ if (!list.isEmpty())
+ index = list.at(0);
+
+ QModelIndex newFolder =
+ bookmarkManager->addNewFolder(proxyModel->mapToSource(index));
+ if (newFolder.isValid()) {
+ ui.treeView->expand(index);
+ const QModelIndex &index = proxyModel->mapFromSource(newFolder);
+ ui.treeView->selectionModel()->setCurrentIndex(index,
+ QItemSelectionModel::ClearAndSelect);
+
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ const QString name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ }
+ ui.treeView->setFocus();
+}
+
+void BookmarkDialog::toolButtonClicked()
+{
+ bool visible = !ui.treeView->isVisible();
+ ui.treeView->setVisible(visible);
+ ui.newFolderButton->setVisible(visible);
+
+ if (visible) {
+ resize(QSize(width(), 400));
+ ui.toolButton->setText(QLatin1String("-"));
+ } else {
+ resize(width(), minimumHeight());
+ ui.toolButton->setText(QLatin1String("+"));
+ }
+}
+
+void BookmarkDialog::itemChanged(QStandardItem *item)
+{
+ if (renameItem != item) {
+ renameItem = item;
+ oldText = item->text();
+ return;
+ }
+
+ if (item->text() != oldText) {
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ QString name = tr("Bookmarks");
+ const QModelIndex& index = ui.treeView->currentIndex();
+ if (index.isValid())
+ name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ }
+}
+
+void BookmarkDialog::textChanged(const QString& string)
+{
+ ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!string.isEmpty());
+}
+
+void BookmarkDialog::selectBookmarkFolder(const QString &folderName)
+{
+ if (folderName.isEmpty())
+ return;
+
+ if (folderName == tr("Bookmarks")) {
+ ui.treeView->clearSelection();
+ return;
+ }
+
+ QStandardItemModel *model = bookmarkManager->treeBookmarkModel();
+ QList<QStandardItem*> list = model->findItems(folderName,
+ Qt::MatchCaseSensitive | Qt::MatchRecursive, 0);
+ if (!list.isEmpty()) {
+ QModelIndex index = model->indexFromItem(list.at(0));
+ ui.treeView->selectionModel()->setCurrentIndex(
+ proxyModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
+ }
+}
+
+void BookmarkDialog::customContextMenuRequested(const QPoint &point)
+{
+ QModelIndex index = ui.treeView->indexAt(point);
+ if (!index.isValid())
+ return;
+
+ QMenu menu(QLatin1String(""), this);
+
+ QAction *removeItem = menu.addAction(tr("Delete Folder"));
+ QAction *renameItem = menu.addAction(tr("Rename Folder"));
+
+ QAction *picked_action = menu.exec(ui.treeView->mapToGlobal(point));
+ if (!picked_action)
+ return;
+
+ if (picked_action == removeItem) {
+ bookmarkManager->removeBookmarkItem(ui.treeView,
+ proxyModel->mapToSource(index));
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ QString name = tr("Bookmarks");
+ index = ui.treeView->currentIndex();
+ if (index.isValid())
+ name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ }
+ else if (picked_action == renameItem) {
+ QStandardItem *item = bookmarkManager->treeBookmarkModel()->
+ itemFromIndex(proxyModel->mapToSource(index));
+ if (item) {
+ item->setEditable(true);
+ ui.treeView->edit(index);
+ item->setEditable(false);
+ }
+ }
+}
+
+void BookmarkDialog::currentChanged(const QModelIndex& current,
+ const QModelIndex& previous)
+{
+ Q_UNUSED(previous)
+
+ if (!current.isValid()) {
+ ui.bookmarkFolders->setCurrentIndex(
+ ui.bookmarkFolders->findText(tr("Bookmarks")));
+ return;
+ }
+
+ ui.bookmarkFolders->setCurrentIndex(
+ ui.bookmarkFolders->findText(current.data().toString()));
+}
+
+bool BookmarkDialog::eventFilter(QObject *object, QEvent *e)
+{
+ if (object == this && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+
+ QModelIndex index = ui.treeView->currentIndex();
+ switch (ke->key()) {
+ case Qt::Key_F2: {
+ const QModelIndex& source = proxyModel->mapToSource(index);
+ QStandardItem *item =
+ bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item) {
+ item->setEditable(true);
+ ui.treeView->edit(index);
+ item->setEditable(false);
+ }
+ } break;
+
+ case Qt::Key_Delete: {
+ bookmarkManager->removeBookmarkItem(ui.treeView,
+ proxyModel->mapToSource(index));
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ QString name = tr("Bookmarks");
+ index = ui.treeView->currentIndex();
+ if (index.isValid())
+ name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ } break;
+
+ default:
+ break;
+ }
+ }
+ return QObject::eventFilter(object, e);
+}
+
+
+
+
+BookmarkWidget::BookmarkWidget(BookmarkManager *manager, QWidget *parent,
+ bool showButtons)
+ : QWidget(parent)
+ , addButton(0)
+ , removeButton(0)
+ , bookmarkManager(manager)
+{
+ setup(showButtons);
+ installEventFilter(this);
+}
+
+BookmarkWidget::~BookmarkWidget()
+{
+}
+
+void BookmarkWidget::removeClicked()
+{
+ const QModelIndex& index = treeView->currentIndex();
+ if (searchField->text().isEmpty()) {
+ bookmarkManager->removeBookmarkItem(treeView,
+ filterBookmarkModel->mapToSource(index));
+ }
+}
+
+void BookmarkWidget::filterChanged()
+{
+ bool searchBookmarks = searchField->text().isEmpty();
+ if (!searchBookmarks) {
+ regExp.setPattern(searchField->text());
+ filterBookmarkModel->setSourceModel(bookmarkManager->listBookmarkModel());
+ } else {
+ regExp.setPattern(QLatin1String(""));
+ filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel());
+ }
+
+ if (addButton)
+ addButton->setEnabled(searchBookmarks);
+
+ if (removeButton)
+ removeButton->setEnabled(searchBookmarks);
+
+ filterBookmarkModel->setFilterRegExp(regExp);
+
+ QModelIndex index = treeView->indexAt(QPoint(1, 1));
+ if (index.isValid())
+ treeView->setCurrentIndex(index);
+
+ if (searchBookmarks)
+ expandItems();
+}
+
+void BookmarkWidget::expand(const QModelIndex& index)
+{
+ const QModelIndex& source = filterBookmarkModel->mapToSource(index);
+ QStandardItem *item = bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item)
+ item->setData(treeView->isExpanded(index), Qt::UserRole + 11);
+}
+
+void BookmarkWidget::activated(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return;
+
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (data != QLatin1String("Folder"))
+ emit requestShowLink(data);
+}
+
+void BookmarkWidget::customContextMenuRequested(const QPoint &point)
+{
+ QModelIndex index = treeView->indexAt(point);
+ if (!index.isValid())
+ return;
+
+ QAction *showItem = 0;
+ QAction *removeItem = 0;
+ QAction *renameItem = 0;
+ QAction *showItemNewTab = 0;
+
+ QMenu menu(QLatin1String(""), this);
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (data == QLatin1String("Folder")) {
+ removeItem = menu.addAction(tr("Delete Folder"));
+ renameItem = menu.addAction(tr("Rename Folder"));
+ } else {
+ showItem = menu.addAction(tr("Show Bookmark"));
+ showItemNewTab = menu.addAction(tr("Show Bookmark in New Tab"));
+ if (searchField->text().isEmpty()) {
+ menu.addSeparator();
+ removeItem = menu.addAction(tr("Delete Bookmark"));
+ renameItem = menu.addAction(tr("Rename Bookmark"));
+ }
+ }
+
+ QAction *picked_action = menu.exec(treeView->mapToGlobal(point));
+ if (!picked_action)
+ return;
+
+ if (picked_action == showItem) {
+ emit requestShowLink(data);
+ }
+ else if (picked_action == showItemNewTab) {
+ CentralWidget::instance()->setSourceInNewTab(data);
+ }
+ else if (picked_action == removeItem) {
+ bookmarkManager->removeBookmarkItem(treeView,
+ filterBookmarkModel->mapToSource(index));
+ }
+ else if (picked_action == renameItem) {
+ const QModelIndex& source = filterBookmarkModel->mapToSource(index);
+ QStandardItem *item =
+ bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item) {
+ item->setEditable(true);
+ treeView->edit(index);
+ item->setEditable(false);
+ }
+ }
+}
+
+void BookmarkWidget::setup(bool showButtons)
+{
+ regExp.setPatternSyntax(QRegExp::FixedString);
+ regExp.setCaseSensitivity(Qt::CaseInsensitive);
+
+ QLayout *vlayout = new QVBoxLayout(this);
+ vlayout->setMargin(4);
+
+ QLabel *label = new QLabel(tr("Filter:"), this);
+ vlayout->addWidget(label);
+
+ searchField = new QLineEdit(this);
+ vlayout->addWidget(searchField);
+ connect(searchField, SIGNAL(textChanged(const QString &)), this,
+ SLOT(filterChanged()));
+
+ treeView = new TreeView(this);
+ vlayout->addWidget(treeView);
+
+ QString system = QLatin1String("win");
+#ifdef Q_OS_MAC
+ system = QLatin1String("mac");
+#endif
+
+ if (showButtons) {
+ QLayout *hlayout = new QHBoxLayout();
+ vlayout->addItem(hlayout);
+
+ hlayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding));
+
+ addButton = new QToolButton(this);
+ addButton->setText(tr("Add"));
+ addButton->setIcon(QIcon(QString::fromUtf8(
+ ":/trolltech/assistant/images/%1/addtab.png").arg(system)));
+ addButton->setAutoRaise(true);
+ addButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ hlayout->addWidget(addButton);
+ connect(addButton, SIGNAL(clicked()), this, SIGNAL(addBookmark()));
+
+ removeButton = new QToolButton(this);
+ removeButton->setText(tr("Remove"));
+ removeButton->setIcon(QIcon(QString::fromUtf8(
+ ":/trolltech/assistant/images/%1/closetab.png").arg(system)));
+ removeButton->setAutoRaise(true);
+ removeButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ hlayout->addWidget(removeButton);
+ connect(removeButton, SIGNAL(clicked()), this, SLOT(removeClicked()));
+ }
+
+ filterBookmarkModel = new QSortFilterProxyModel(this);
+ treeView->setModel(filterBookmarkModel);
+
+ treeView->setDragEnabled(true);
+ treeView->setAcceptDrops(true);
+ treeView->setAutoExpandDelay(1000);
+ treeView->setDropIndicatorShown(true);
+ treeView->header()->setVisible(false);
+ treeView->viewport()->installEventFilter(this);
+ treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(treeView, SIGNAL(expanded(const QModelIndex&)), this,
+ SLOT(expand(const QModelIndex&)));
+
+ connect(treeView, SIGNAL(collapsed(const QModelIndex&)), this,
+ SLOT(expand(const QModelIndex&)));
+
+ connect(treeView, SIGNAL(activated(const QModelIndex&)), this,
+ SLOT(activated(const QModelIndex&)));
+
+ connect(treeView, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(customContextMenuRequested(const QPoint&)));
+
+ filterBookmarkModel->setFilterKeyColumn(0);
+ filterBookmarkModel->setDynamicSortFilter(true);
+ filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel());
+
+ expandItems();
+}
+
+void BookmarkWidget::expandItems()
+{
+ QStandardItemModel *model = bookmarkManager->treeBookmarkModel();
+ QList<QStandardItem*>list = model->findItems(QLatin1String("*"),
+ Qt::MatchWildcard | Qt::MatchRecursive, 0);
+ foreach (const QStandardItem* item, list) {
+ const QModelIndex& index = model->indexFromItem(item);
+ treeView->setExpanded(filterBookmarkModel->mapFromSource(index),
+ item->data(Qt::UserRole + 11).toBool());
+ }
+}
+
+void BookmarkWidget::focusInEvent(QFocusEvent *e)
+{
+ if (e->reason() != Qt::MouseFocusReason) {
+ searchField->selectAll();
+ searchField->setFocus();
+
+ QModelIndex index = treeView->indexAt(QPoint(1, 1));
+ if (index.isValid())
+ treeView->setCurrentIndex(index);
+
+ }
+}
+
+bool BookmarkWidget::eventFilter(QObject *object, QEvent *e)
+{
+ if (object == this && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ QModelIndex index = treeView->currentIndex();
+ switch (ke->key()) {
+ if (index.isValid() && searchField->text().isEmpty()) {
+ case Qt::Key_F2: {
+ const QModelIndex& source = filterBookmarkModel->mapToSource(index);
+ QStandardItem *item =
+ bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item) {
+ item->setEditable(true);
+ treeView->edit(index);
+ item->setEditable(false);
+ }
+ } break;
+
+ case Qt::Key_Delete: {
+ bookmarkManager->removeBookmarkItem(treeView,
+ filterBookmarkModel->mapToSource(index));
+ } break;
+ }
+
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ treeView->subclassKeyPressEvent(ke);
+ break;
+
+ case Qt::Key_Enter: {
+ case Qt::Key_Return:
+ index = treeView->selectionModel()->currentIndex();
+ if (index.isValid()) {
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (!data.isEmpty() && data != QLatin1String("Folder"))
+ emit requestShowLink(data);
+ }
+ } break;
+
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (object == treeView->viewport() && e->type() == QEvent::MouseButtonRelease) {
+ const QModelIndex& index = treeView->currentIndex();
+ QMouseEvent *me = static_cast<QMouseEvent*>(e);
+ if (index.isValid() && (me->button() == Qt::MidButton)) {
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (!data.isEmpty() && data != QLatin1String("Folder"))
+ CentralWidget::instance()->setSourceInNewTab(data);
+ }
+ }
+ return QWidget::eventFilter(object, e);
+}
+
+
+
+
+BookmarkModel::BookmarkModel(int rows, int columns, QObject * parent)
+ : QStandardItemModel(rows, columns, parent)
+{
+}
+
+BookmarkModel::~BookmarkModel()
+{
+}
+
+Qt::DropActions BookmarkModel::supportedDropActions() const
+{
+ return Qt::MoveAction;
+}
+
+Qt::ItemFlags BookmarkModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags defaultFlags = QStandardItemModel::flags(index);
+ if (index.data(Qt::UserRole + 10).toString() == QLatin1String("Folder"))
+ return (Qt::ItemIsDropEnabled | defaultFlags) &~ Qt::ItemIsDragEnabled;
+
+ return (Qt::ItemIsDragEnabled | defaultFlags) &~ Qt::ItemIsDropEnabled;
+}
+
+
+
+
+BookmarkManager::BookmarkManager(QHelpEngineCore* _helpEngine)
+ : treeModel(new BookmarkModel(0, 1, this))
+ , listModel(new BookmarkModel(0, 1, this))
+ , helpEngine(_helpEngine)
+{
+ folderIcon = QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon);
+ treeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Bookmark"));
+ listModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Bookmark"));
+
+ connect(treeModel, SIGNAL(itemChanged(QStandardItem*)), this,
+ SLOT(itemChanged(QStandardItem*)));
+}
+
+BookmarkManager::~BookmarkManager()
+{
+ treeModel->clear();
+ listModel->clear();
+}
+
+BookmarkModel* BookmarkManager::treeBookmarkModel()
+{
+ return treeModel;
+}
+
+BookmarkModel* BookmarkManager::listBookmarkModel()
+{
+ return listModel;
+}
+
+void BookmarkManager::saveBookmarks()
+{
+ qint32 depth = 0;
+ QByteArray bookmarks;
+ QDataStream stream(&bookmarks, QIODevice::WriteOnly);
+ QStandardItem *root = treeModel->invisibleRootItem();
+
+ for (int i = 0; i < root->rowCount(); ++i) {
+ const QStandardItem *item = root->child(i);
+ stream << depth; // root
+ stream << item->data(Qt::DisplayRole).toString();
+ stream << item->data(Qt::UserRole + 10).toString();
+ stream << item->data(Qt::UserRole + 11).toBool();
+
+ if (item->rowCount() > 0) {
+ readBookmarksRecursive(item, stream, (depth +1));
+ }
+ }
+ helpEngine->setCustomValue(QLatin1String("Bookmarks"), bookmarks);
+}
+
+QStringList BookmarkManager::bookmarkFolders() const
+{
+ QStringList folders(tr("Bookmarks"));
+
+ QList<QStandardItem*>list = treeModel->findItems(QLatin1String("*"),
+ Qt::MatchWildcard | Qt::MatchRecursive, 0);
+
+ QString data;
+ foreach (const QStandardItem *item, list) {
+ data = item->data(Qt::UserRole + 10).toString();
+ if (data == QLatin1String("Folder"))
+ folders << item->data(Qt::DisplayRole).toString();
+ }
+ return folders;
+}
+
+QModelIndex BookmarkManager::addNewFolder(const QModelIndex& index)
+{
+ QStandardItem *item = new QStandardItem(uniqueFolderName());
+ item->setEditable(false);
+ item->setData(false, Qt::UserRole + 11);
+ item->setData(QLatin1String("Folder"), Qt::UserRole + 10);
+ item->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon));
+
+ if (index.isValid()) {
+ treeModel->itemFromIndex(index)->appendRow(item);
+ } else {
+ treeModel->appendRow(item);
+ }
+ return treeModel->indexFromItem(item);
+}
+
+void BookmarkManager::removeBookmarkItem(QTreeView *treeView, const QModelIndex& index)
+{
+ QStandardItem *item = treeModel->itemFromIndex(index);
+ if (item) {
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (data == QLatin1String("Folder") && item->rowCount() > 0) {
+ int value = QMessageBox::question(treeView, tr("Remove"),
+ tr("You are going to delete a Folder, this will also<br>"
+ "remove it's content. Are you sure to continue?"),
+ QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
+
+ if (value == QMessageBox::Cancel)
+ return;
+ }
+
+ if (data != QLatin1String("Folder")) {
+ QList<QStandardItem*>itemList = listModel->findItems(item->text());
+ foreach (const QStandardItem *i, itemList) {
+ if (i->data(Qt::UserRole + 10) == data) {
+ listModel->removeRow(i->row());
+ break;
+ }
+ }
+ } else {
+ removeBookmarkFolderItems(item);
+ }
+ treeModel->removeRow(item->row(), index.parent());
+ }
+}
+
+void BookmarkManager::showBookmarkDialog(QWidget* parent, const QString &name,
+ const QString &url)
+{
+ BookmarkDialog dialog(this, name, url, parent);
+ dialog.exec();
+}
+
+void BookmarkManager::addNewBookmark(const QModelIndex& index,
+ const QString &name, const QString &url)
+{
+ QStandardItem *item = new QStandardItem(name);
+ item->setEditable(false);
+ item->setData(false, Qt::UserRole + 11);
+ item->setData(url, Qt::UserRole + 10);
+
+ if (index.isValid()) {
+ treeModel->itemFromIndex(index)->appendRow(item);
+ listModel->appendRow(item->clone());
+ } else {
+ treeModel->appendRow(item);
+ listModel->appendRow(item->clone());
+ }
+}
+
+void BookmarkManager::itemChanged(QStandardItem *item)
+{
+ if (renameItem != item) {
+ renameItem = item;
+ oldText = item->text();
+ return;
+ }
+
+ if (item->text() != oldText) {
+ if (item->data(Qt::UserRole + 10).toString() != QLatin1String("Folder")) {
+ QList<QStandardItem*>itemList = listModel->findItems(oldText);
+ if (itemList.count() > 0)
+ itemList.at(0)->setText(item->text());
+ }
+ }
+}
+
+void BookmarkManager::setupBookmarkModels()
+{
+ treeModel->clear();
+ listModel->clear();
+
+ qint32 depth;
+ bool expanded;
+ QString name, type;
+ QList<int> lastDepths;
+ QList<QStandardItem*> parents;
+
+ QByteArray ba = helpEngine->customValue(QLatin1String("Bookmarks")).toByteArray();
+ QDataStream stream(ba);
+ while (!stream.atEnd()) {
+ stream >> depth >> name >> type >> expanded;
+
+ QStandardItem *item = new QStandardItem(name);
+ item->setEditable(false);
+ item->setData(type, Qt::UserRole + 10);
+ item->setData(expanded, Qt::UserRole + 11);
+ if (depth == 0) {
+ parents.clear(); lastDepths.clear();
+ treeModel->appendRow(item);
+ parents << item; lastDepths << depth;
+ } else {
+ if (depth <= lastDepths.last()) {
+ while (depth <= lastDepths.last() && parents.count() > 0) {
+ parents.pop_back(); lastDepths.pop_back();
+ }
+ }
+ parents.last()->appendRow(item);
+ if (type == QLatin1String("Folder")) {
+ parents << item; lastDepths << depth;
+ }
+ }
+
+ if (type == QLatin1String("Folder"))
+ item->setIcon(folderIcon);
+ else
+ listModel->appendRow(item->clone());
+ }
+}
+
+QString BookmarkManager::uniqueFolderName() const
+{
+ QString folderName = tr("New Folder");
+ QList<QStandardItem*> list = treeModel->findItems(folderName,
+ Qt::MatchContains | Qt::MatchRecursive, 0);
+ if (!list.isEmpty()) {
+ QStringList names;
+ foreach (const QStandardItem *item, list)
+ names << item->text();
+
+ for (int i = 1; i <= names.count(); ++i) {
+ folderName = (tr("New Folder") + QLatin1String(" %1")).arg(i);
+ if (!names.contains(folderName))
+ break;
+ }
+ }
+ return folderName;
+}
+
+void BookmarkManager::removeBookmarkFolderItems(QStandardItem *item)
+{
+ for (int j = 0; j < item->rowCount(); ++j) {
+ QStandardItem *child = item->child(j);
+ if (child->rowCount() > 0)
+ removeBookmarkFolderItems(child);
+
+ QString data = child->data(Qt::UserRole + 10).toString();
+ QList<QStandardItem*>itemList = listModel->findItems(child->text());
+ foreach (const QStandardItem *i, itemList) {
+ if (i->data(Qt::UserRole + 10) == data) {
+ listModel->removeRow(i->row());
+ break;
+ }
+ }
+ }
+}
+
+void BookmarkManager::readBookmarksRecursive(const QStandardItem *item,
+ QDataStream &stream,
+ const qint32 depth) const
+{
+ for (int j = 0; j < item->rowCount(); ++j) {
+ const QStandardItem *child = item->child(j);
+ stream << depth;
+ stream << child->data(Qt::DisplayRole).toString();
+ stream << child->data(Qt::UserRole + 10).toString();
+ stream << child->data(Qt::UserRole + 11).toBool();
+
+ if (child->rowCount() > 0)
+ readBookmarksRecursive(child, stream, (depth +1));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/shared/help/bookmarkmanager.h b/shared/help/bookmarkmanager.h
new file mode 100644
index 0000000000..b5c68021f1
--- /dev/null
+++ b/shared/help/bookmarkmanager.h
@@ -0,0 +1,197 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef BOOKMARKMANAGER_H
+#define BOOKMARKMANAGER_H
+
+#include "ui_bookmarkdialog.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QByteArray>
+#include <QtCore/QDataStream>
+
+#include <QtGui/QIcon>
+#include <QtGui/QDialog>
+#include <QtGui/QWidget>
+#include <QtGui/QTreeView>
+#include <QtGui/QStandardItemModel>
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+class QLineEdit;
+class QTreeView;
+class QToolButton;
+class QStandardItem;
+class QHelpEngineCore;
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+
+class BookmarkManager;
+
+class BookmarkDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ BookmarkDialog(BookmarkManager *manager, const QString &title,
+ const QString &url, QWidget *parent = 0);
+ ~BookmarkDialog();
+
+private slots:
+ void addAccepted();
+ void addNewFolder();
+ void toolButtonClicked();
+ void itemChanged(QStandardItem *item);
+ void textChanged(const QString& string);
+ void selectBookmarkFolder(const QString &folderName);
+ void customContextMenuRequested(const QPoint &point);
+ void currentChanged(const QModelIndex& current, const QModelIndex& previous);
+
+private:
+ bool eventFilter(QObject *object, QEvent *e);
+
+private:
+ QString m_url;
+ QString m_title;
+
+ QString oldText;
+ QStandardItem *renameItem;
+
+ Ui::BookmarkDialog ui;
+ BookmarkManager *bookmarkManager;
+ QSortFilterProxyModel *proxyModel;
+};
+
+class TreeView : public QTreeView {
+ Q_OBJECT
+public:
+ TreeView(QWidget* parent = 0) : QTreeView(parent) {}
+ void subclassKeyPressEvent(QKeyEvent* event)
+ {
+ QTreeView::keyPressEvent(event);
+ }
+};
+
+class BookmarkWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ BookmarkWidget(BookmarkManager *manager, QWidget *parent = 0,
+ bool showButtons = true);
+ ~BookmarkWidget();
+
+signals:
+ void addBookmark();
+ void requestShowLink(const QUrl &url);
+ void escapePressed();
+
+private slots:
+ void removeClicked();
+ void filterChanged();
+ void expand(const QModelIndex& index);
+ void activated(const QModelIndex &index);
+ void customContextMenuRequested(const QPoint &point);
+
+private:
+ void setup(bool showButtons);
+ void expandItems();
+ void focusInEvent(QFocusEvent *e);
+ bool eventFilter(QObject *object, QEvent *event);
+
+private:
+ QRegExp regExp;
+ TreeView *treeView;
+ QLineEdit *searchField;
+ QToolButton *addButton;
+ QToolButton *removeButton;
+ BookmarkManager *bookmarkManager;
+ QSortFilterProxyModel* filterBookmarkModel;
+};
+
+class BookmarkModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ BookmarkModel(int rows, int columns, QObject *parent = 0);
+ ~BookmarkModel();
+
+ Qt::DropActions supportedDropActions() const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+};
+
+class BookmarkManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ BookmarkManager(QHelpEngineCore* helpEngine);
+ ~BookmarkManager();
+
+ BookmarkModel* treeBookmarkModel();
+ BookmarkModel* listBookmarkModel();
+
+ void saveBookmarks();
+ QStringList bookmarkFolders() const;
+ QModelIndex addNewFolder(const QModelIndex& index);
+ void removeBookmarkItem(QTreeView *treeView, const QModelIndex& index);
+ void showBookmarkDialog(QWidget* parent, const QString &name, const QString &url);
+ void addNewBookmark(const QModelIndex& index, const QString &name, const QString &url);
+ void setupBookmarkModels();
+
+private slots:
+ void itemChanged(QStandardItem *item);
+
+private:
+ QString uniqueFolderName() const;
+ void removeBookmarkFolderItems(QStandardItem *item);
+ void readBookmarksRecursive(const QStandardItem *item, QDataStream &stream,
+ const qint32 depth) const;
+
+private:
+ QString oldText;
+ QIcon folderIcon;
+
+ BookmarkModel *treeModel;
+ BookmarkModel *listModel;
+ QStandardItem *renameItem;
+ QHelpEngineCore *helpEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/shared/help/contentwindow.cpp b/shared/help/contentwindow.cpp
new file mode 100644
index 0000000000..d67ac7c803
--- /dev/null
+++ b/shared/help/contentwindow.cpp
@@ -0,0 +1,165 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "contentwindow.h"
+#include "centralwidget.h"
+
+#include <QtGui/QLayout>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QMenu>
+
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpContentWidget>
+
+QT_BEGIN_NAMESPACE
+
+ContentWindow::ContentWindow(QHelpEngine *helpEngine)
+ : m_helpEngine(helpEngine)
+ , m_contentWidget(0)
+ , m_expandDepth(-2)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ m_contentWidget = m_helpEngine->contentWidget();
+ connect(m_contentWidget, SIGNAL(linkActivated(const QUrl&)),
+ this, SIGNAL(linkActivated(const QUrl&)));
+ layout->setMargin(4);
+ layout->addWidget(m_contentWidget);
+
+ m_contentWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(m_contentWidget, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(showContextMenu(const QPoint&)));
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ connect(contentModel, SIGNAL(contentsCreated()),
+ this, SLOT(expandTOC()));
+
+ m_contentWidget->viewport()->installEventFilter(this);
+}
+
+ContentWindow::~ContentWindow()
+{
+}
+
+bool ContentWindow::syncToContent(const QUrl& url)
+{
+ QModelIndex idx = m_contentWidget->indexOf(url);
+ if (!idx.isValid())
+ return false;
+ m_contentWidget->setCurrentIndex(idx);
+ return true;
+}
+
+void ContentWindow::expandTOC()
+{
+ if (m_expandDepth > -2) {
+ expandToDepth(m_expandDepth);
+ m_expandDepth = -2;
+ }
+}
+
+void ContentWindow::expandToDepth(int depth)
+{
+ m_expandDepth = depth;
+ if (depth == -1)
+ m_contentWidget->expandAll();
+ else
+ m_contentWidget->expandToDepth(depth);
+}
+
+void ContentWindow::focusInEvent(QFocusEvent *e)
+{
+ if (e->reason() != Qt::MouseFocusReason)
+ m_contentWidget->setFocus();
+}
+
+void ContentWindow::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Escape)
+ emit escapePressed();
+}
+
+bool ContentWindow::eventFilter(QObject* o, QEvent *e)
+{
+ if (m_contentWidget && o == m_contentWidget->viewport() && e->type()
+ == QEvent::MouseButtonRelease) {
+ QMouseEvent *me = static_cast<QMouseEvent*>(e);
+ if (m_contentWidget->indexAt(me->pos()).isValid()
+ && me->button() == Qt::LeftButton) {
+ itemClicked(m_contentWidget->currentIndex());
+ } else if (m_contentWidget->indexAt(me->pos()).isValid()
+ && me->button() == Qt::MidButton) {
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ QHelpContentItem *itm =
+ contentModel->contentItemAt(m_contentWidget->currentIndex());
+ CentralWidget::instance()->setSourceInNewTab(itm->url());
+ }
+ }
+ return QWidget::eventFilter(o,e);
+}
+
+void ContentWindow::showContextMenu(const QPoint &pos)
+{
+ if (!m_contentWidget->indexAt(pos).isValid())
+ return;
+
+ QMenu menu;
+ QAction *curTab = menu.addAction(tr("Open Link"));
+ QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
+ menu.move(m_contentWidget->mapToGlobal(pos));
+
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ QHelpContentItem *itm =
+ contentModel->contentItemAt(m_contentWidget->currentIndex());
+
+ QAction *action = menu.exec();
+ if (curTab == action)
+ emit linkActivated(itm->url());
+ else if (newTab == action)
+ CentralWidget::instance()->setSourceInNewTab(itm->url());
+}
+
+void ContentWindow::itemClicked(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return;
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ QHelpContentItem *itm =
+ contentModel->contentItemAt(index);
+ if (itm)
+ emit linkActivated(itm->url());
+}
+
+QT_END_NAMESPACE
diff --git a/shared/help/contentwindow.h b/shared/help/contentwindow.h
new file mode 100644
index 0000000000..c3abb8084b
--- /dev/null
+++ b/shared/help/contentwindow.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef CONTENTWINDOW_H
+#define CONTENTWINDOW_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QModelIndex>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QHelpEngine;
+class QHelpContentWidget;
+
+class ContentWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ContentWindow(QHelpEngine *helpEngine);
+ ~ContentWindow();
+
+ bool syncToContent(const QUrl &url);
+ void expandToDepth(int depth);
+
+signals:
+ void linkActivated(const QUrl &link);
+ void escapePressed();
+
+private slots:
+ void showContextMenu(const QPoint &pos);
+ void expandTOC();
+ void itemClicked(const QModelIndex &index);
+
+private:
+ void focusInEvent(QFocusEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ bool eventFilter(QObject* o, QEvent *e);
+
+ QHelpEngine *m_helpEngine;
+ QHelpContentWidget *m_contentWidget;
+ int m_expandDepth;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/shared/help/filternamedialog.cpp b/shared/help/filternamedialog.cpp
new file mode 100644
index 0000000000..c6d9f3e78d
--- /dev/null
+++ b/shared/help/filternamedialog.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtGui/QPushButton>
+
+#include "filternamedialog.h"
+
+QT_BEGIN_NAMESPACE
+
+FilterNameDialog::FilterNameDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Ok),
+ SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel),
+ SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_ui.lineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(updateOkButton()));
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true);
+
+}
+
+QString FilterNameDialog::filterName() const
+{
+ return m_ui.lineEdit->text();
+}
+
+void FilterNameDialog::updateOkButton()
+{
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)
+ ->setDisabled(m_ui.lineEdit->text().isEmpty());
+}
+
+QT_END_NAMESPACE
diff --git a/shared/help/filternamedialog.h b/shared/help/filternamedialog.h
new file mode 100644
index 0000000000..8fb02c921a
--- /dev/null
+++ b/shared/help/filternamedialog.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef FILTERNAMEDIALOG_H
+#define FILTERNAMEDIALOG_H
+
+#include <QtGui/QDialog>
+#include "ui_filternamedialog.h"
+
+QT_BEGIN_NAMESPACE
+
+class FilterNameDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ FilterNameDialog(QWidget *parent = 0);
+ QString filterName() const;
+
+private slots:
+ void updateOkButton();
+
+private:
+ Ui::FilterNameDialogClass m_ui;
+};
+
+QT_END_NAMESPACE
+
+#endif // FILTERNAMEDIALOG_H
diff --git a/shared/help/filternamedialog.ui b/shared/help/filternamedialog.ui
new file mode 100644
index 0000000000..755a934799
--- /dev/null
+++ b/shared/help/filternamedialog.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>FilterNameDialogClass</class>
+ <widget class="QDialog" name="FilterNameDialogClass" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>312</width>
+ <height>95</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Filter Name</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Filter Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLineEdit" name="lineEdit" />
+ </item>
+ <item row="1" column="0" colspan="3" >
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <resources/>
+ <connections/>
+</ui>
diff --git a/shared/help/help.pri b/shared/help/help.pri
new file mode 100644
index 0000000000..9503d08593
--- /dev/null
+++ b/shared/help/help.pri
@@ -0,0 +1,25 @@
+VPATH += $$PWD
+
+INCLUDEPATH *= $$PWD $$PWD/..
+
+# Input
+HEADERS += \
+ $$PWD/filternamedialog.h \
+ $$PWD/topicchooser.h \
+ $$PWD/helpviewer.h \
+ $$PWD/contentwindow.h \
+ $$PWD/bookmarkmanager.h \
+ $$PWD/../namespace_global.h
+
+SOURCES += \
+ $$PWD/filternamedialog.cpp \
+ $$PWD/topicchooser.cpp \
+ $$PWD/helpviewer.cpp \
+ $$PWD/indexwindow.cpp \
+ $$PWD/contentwindow.cpp \
+ $$PWD/bookmarkmanager.cpp
+
+FORMS += \
+ $$PWD/filternamedialog.ui \
+ $$PWD/topicchooser.ui \
+ $$PWD/bookmarkdialog.ui
diff --git a/shared/help/helpviewer.cpp b/shared/help/helpviewer.cpp
new file mode 100644
index 0000000000..660d35b411
--- /dev/null
+++ b/shared/help/helpviewer.cpp
@@ -0,0 +1,483 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "helpviewer.h"
+#include "centralwidget.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QEvent>
+#include <QtCore/QVariant>
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+
+#include <QtGui/QMenu>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+#include <QtGui/QApplication>
+#include <QtGui/QMessageBox>
+#include <QtGui/QDesktopServices>
+
+#include <QtHelp/QHelpEngine>
+
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(USE_WEBKIT)
+
+class HelpNetworkReply : public QNetworkReply
+{
+public:
+ HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData);
+
+ virtual void abort();
+
+ virtual qint64 bytesAvailable() const { return data.length() + QNetworkReply::bytesAvailable(); }
+
+protected:
+ virtual qint64 readData(char *data, qint64 maxlen);
+
+private:
+ QByteArray data;
+ qint64 origLen;
+};
+
+HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData)
+ : data(fileData), origLen(fileData.length())
+{
+ setRequest(request);
+ setOpenMode(QIODevice::ReadOnly);
+
+ setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("text/html"));
+ setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(fileData.length()));
+ QTimer::singleShot(0, this, SIGNAL(metaDataChanged()));
+ QTimer::singleShot(0, this, SIGNAL(readyRead()));
+}
+
+void HelpNetworkReply::abort()
+{
+ // nothing to do
+}
+
+qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen)
+{
+ qint64 len = qMin(qint64(data.length()), maxlen);
+ if (len) {
+ qMemCopy(buffer, data.constData(), len);
+ data.remove(0, len);
+ }
+ if (!data.length())
+ QTimer::singleShot(0, this, SIGNAL(finished()));
+ return len;
+}
+
+class HelpNetworkAccessManager : public QNetworkAccessManager
+{
+public:
+ HelpNetworkAccessManager(QHelpEngine *engine, QObject *parent);
+
+protected:
+ virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
+ QIODevice *outgoingData = 0);
+
+private:
+ QHelpEngine *helpEngine;
+};
+
+HelpNetworkAccessManager::HelpNetworkAccessManager(QHelpEngine *engine, QObject *parent)
+ : QNetworkAccessManager(parent), helpEngine(engine)
+{
+}
+
+QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request,
+ QIODevice *outgoingData)
+{
+ const QString scheme = request.url().scheme();
+ if (scheme == QLatin1String("qthelp") || scheme == QLatin1String("about")) {
+ return new HelpNetworkReply(request, helpEngine->fileData(request.url()));
+ }
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+}
+
+class HelpPage : public QWebPage
+{
+public:
+ HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent);
+
+protected:
+ virtual QWebPage *createWindow(QWebPage::WebWindowType);
+
+ virtual bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type);
+
+private:
+ CentralWidget *centralWidget;
+ QHelpEngine *helpEngine;
+};
+
+HelpPage::HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent)
+ : QWebPage(parent), centralWidget(central), helpEngine(engine)
+{
+}
+
+QWebPage *HelpPage::createWindow(QWebPage::WebWindowType)
+{
+ return centralWidget->newEmptyTab()->page();
+}
+
+static bool isLocalUrl(const QUrl &url)
+{
+ const QString scheme = url.scheme();
+ if (scheme.isEmpty()
+ || scheme == QLatin1String("file")
+ || scheme == QLatin1String("qrc")
+ || scheme == QLatin1String("data")
+ || scheme == QLatin1String("qthelp")
+ || scheme == QLatin1String("about"))
+ return true;
+ return false;
+}
+
+bool HelpPage::acceptNavigationRequest(QWebFrame *, const QNetworkRequest &request, QWebPage::NavigationType)
+{
+ const QUrl url = request.url();
+ if (isLocalUrl(url)) {
+ if (url.path().endsWith(QLatin1String("pdf"))) {
+ QString fileName = url.toString();
+ fileName = QDir::tempPath() + QDir::separator() + fileName.right
+ (fileName.length() - fileName.lastIndexOf(QChar('/')));
+
+ QFile tmpFile(QDir::cleanPath(fileName));
+ if (tmpFile.open(QIODevice::ReadWrite)) {
+ tmpFile.write(helpEngine->fileData(url));
+ tmpFile.close();
+ }
+ QDesktopServices::openUrl(QUrl(tmpFile.fileName()));
+ return false;
+ } else
+ return true;
+ } else {
+ QDesktopServices::openUrl(url);
+ return false;
+ }
+}
+
+HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent)
+ : QWebView(parent), helpEngine(engine), parentWidget(parent)
+{
+ setPage(new HelpPage(parent, helpEngine, this));
+
+ page()->setNetworkAccessManager(new HelpNetworkAccessManager(engine, this));
+
+ QAction* action = pageAction(QWebPage::OpenLinkInNewWindow);
+ if (parent)
+ action->setText(tr("Open Link in New Tab"));
+ else
+ action->setVisible(false);
+
+ pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false);
+ pageAction(QWebPage::DownloadImageToDisk)->setVisible(false);
+ pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false);
+
+ connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this, SLOT(actionChanged()));
+ connect(pageAction(QWebPage::Back), SIGNAL(changed()), this, SLOT(actionChanged()));
+ connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, SLOT(actionChanged()));
+ connect(page(), SIGNAL(linkHovered(const QString &, const QString &, const QString &)), this, SIGNAL(highlighted(const QString &)));
+ connect(this, SIGNAL(urlChanged(const QUrl &)), this, SIGNAL(sourceChanged(const QUrl &)));
+}
+
+void HelpViewer::setSource(const QUrl &url)
+{
+ if (!homeUrl.isValid())
+ homeUrl = url;
+ load(url);
+}
+
+void HelpViewer::resetZoom()
+{
+ setTextSizeMultiplier(1.0);
+}
+
+void HelpViewer::zoomIn(qreal range)
+{
+ setTextSizeMultiplier(textSizeMultiplier() + range/10);
+}
+
+void HelpViewer::zoomOut(qreal range)
+{
+ setTextSizeMultiplier(qMax(0.,textSizeMultiplier() - range/10));
+}
+
+void HelpViewer::home()
+{
+ if (homeUrl.isValid())
+ setSource(homeUrl);
+}
+
+void HelpViewer::wheelEvent(QWheelEvent *e)
+{
+ if (e->modifiers() & Qt::ControlModifier) {
+ const int delta = e->delta();
+ qDebug() << delta;
+ if (delta > 0)
+ zoomIn(delta/120);
+ else if (delta < 0)
+ zoomOut(-delta/120);
+ e->accept();
+ return;
+ }
+ QWebView::wheelEvent(e);
+}
+
+void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::XButton1) {
+ triggerPageAction(QWebPage::Back);
+ return;
+ }
+
+ if (e->button() == Qt::XButton2) {
+ triggerPageAction(QWebPage::Forward);
+ return;
+ }
+
+ QWebView::mouseReleaseEvent(e);
+}
+
+void HelpViewer::actionChanged()
+{
+ QAction *a = qobject_cast<QAction *>(sender());
+ if (a == pageAction(QWebPage::Copy))
+ emit copyAvailable(a->isEnabled());
+ else if (a == pageAction(QWebPage::Back))
+ emit backwardAvailable(a->isEnabled());
+ else if (a == pageAction(QWebPage::Forward))
+ emit forwardAvailable(a->isEnabled());
+}
+
+#else // !defined(USE_WEBKIT)
+
+HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent)
+ : QTextBrowser(parent)
+ , zoomCount(0)
+ , controlPressed(false)
+ , lastAnchor(QString())
+ , helpEngine(engine)
+ , parentWidget(parent)
+{
+ document()->setDocumentMargin(8);
+}
+
+void HelpViewer::setSource(const QUrl &url)
+{
+ bool help = url.toString() == QLatin1String("help");
+ if (url.isValid() && !help) {
+ bool isPdf = url.path().endsWith(QLatin1String("pdf"));
+ if (url.scheme() == QLatin1String("http")
+ || url.scheme() == QLatin1String("ftp")
+ || url.scheme() == QLatin1String("mailto") || isPdf) {
+ bool launched = false;
+ if (isPdf && url.scheme() == QLatin1String("qthelp")) {
+ QString fileName = url.toString();
+ fileName = QDir::tempPath() + QDir::separator() + fileName.right
+ (fileName.length() - fileName.lastIndexOf(QChar('/')));
+
+ QFile tmpFile(QDir::cleanPath(fileName));
+ if (tmpFile.open(QIODevice::ReadWrite)) {
+ tmpFile.write(helpEngine->fileData(url));
+ tmpFile.close();
+ }
+ launched = QDesktopServices::openUrl(QUrl(tmpFile.fileName()));
+ } else {
+ launched = QDesktopServices::openUrl(url);
+ }
+
+ if (!launched) {
+ QMessageBox::information(this, tr("Help"),
+ tr("Unable to launch external application.\n"), tr("OK"));
+ }
+ return;
+ } else {
+ QUrl u = helpEngine->findFile(url);
+ if (u.isValid()) {
+ QTextBrowser::setSource(u);
+ return;
+ }
+ }
+ }
+
+ if (help) {
+ QTextBrowser::setSource(QUrl(QLatin1String("qthelp://com.trolltech.com."
+ "assistantinternal_1.0.0/assistant/assistant.html")));
+ } else {
+ QTextBrowser::setSource(url);
+ setHtml(tr("<title>Error 404...</title><div align=\"center\"><br><br>"
+ "<h1>The page could not be found</h1><br><h3>'%1'</h3></div>")
+ .arg(url.toString()));
+ emit sourceChanged(url);
+ }
+}
+
+void HelpViewer::resetZoom()
+{
+ if (zoomCount == 0)
+ return;
+
+ QTextBrowser::zoomOut(zoomCount);
+ zoomCount = 0;
+}
+
+void HelpViewer::zoomIn(int range)
+{
+ if (zoomCount == 10)
+ return;
+
+ QTextBrowser::zoomIn(range);
+ zoomCount++;
+}
+
+void HelpViewer::zoomOut(int range)
+{
+ if (zoomCount == -5)
+ return;
+
+ QTextBrowser::zoomOut(range);
+ zoomCount--;
+}
+
+QVariant HelpViewer::loadResource(int type, const QUrl &name)
+{
+ QByteArray ba;
+ if (type < 4) {
+ ba = helpEngine->fileData(name);
+ if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
+ QImage image;
+ image.loadFromData(ba, "svg");
+ if (!image.isNull())
+ return image;
+ }
+ }
+ return ba;
+}
+
+void HelpViewer::openLinkInNewTab()
+{
+ if(lastAnchor.isEmpty())
+ return;
+
+ parentWidget->setSourceInNewTab(QUrl(lastAnchor));
+ lastAnchor.clear();
+}
+
+void HelpViewer::openLinkInNewTab(const QString &link)
+{
+ lastAnchor = link;
+ openLinkInNewTab();
+}
+
+bool HelpViewer::hasAnchorAt(const QPoint& pos)
+{
+ lastAnchor = anchorAt(pos);
+ if (lastAnchor.isEmpty())
+ return false;
+
+ lastAnchor = source().resolved(lastAnchor).toString();
+ if (lastAnchor.at(0) == QLatin1Char('#')) {
+ QString src = source().toString();
+ int hsh = src.indexOf(QLatin1Char('#'));
+ lastAnchor = (hsh>=0 ? src.left(hsh) : src) + lastAnchor;
+ }
+
+ return true;
+}
+
+void HelpViewer::contextMenuEvent(QContextMenuEvent *e)
+{
+ QMenu menu(QLatin1String(""), 0);
+
+ QUrl link;
+ QAction *copyAnchorAction = 0;
+ if (hasAnchorAt(e->pos())) {
+ link = anchorAt(e->pos());
+ if (link.isRelative())
+ link = source().resolved(link);
+ copyAnchorAction = menu.addAction(tr("Copy &Link Location"));
+ copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid());
+
+ menu.addAction(tr("Open Link in New Tab\tCtrl+LMB"), this, SLOT(openLinkInNewTab()));
+ menu.addSeparator();
+ }
+ menu.addActions(parentWidget->globalActions());
+ QAction *action = menu.exec(e->globalPos());
+ if (action == copyAnchorAction)
+ QApplication::clipboard()->setText(link.toString());
+}
+
+void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::XButton1) {
+ QTextBrowser::backward();
+ return;
+ }
+
+ if (e->button() == Qt::XButton2) {
+ QTextBrowser::forward();
+ return;
+ }
+
+ controlPressed = e->modifiers() & Qt::ControlModifier;
+ if ((controlPressed && hasAnchorAt(e->pos())) ||
+ (e->button() == Qt::MidButton && hasAnchorAt(e->pos()))) {
+ openLinkInNewTab();
+ return;
+ }
+
+ QTextBrowser::mouseReleaseEvent(e);
+}
+
+void HelpViewer::keyPressEvent(QKeyEvent *e)
+{
+ if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier)
+ || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) {
+ QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier,
+ e->text(), e->isAutoRepeat(), e->count());
+ e = event;
+ }
+ QTextBrowser::keyPressEvent(e);
+}
+
+#endif // !defined(USE_WEBKIT)
+
+QT_END_NAMESPACE
diff --git a/shared/help/helpviewer.h b/shared/help/helpviewer.h
new file mode 100644
index 0000000000..3156f196d0
--- /dev/null
+++ b/shared/help/helpviewer.h
@@ -0,0 +1,154 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef HELPVIEWER_H
+#define HELPVIEWER_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QVariant>
+#include <QtGui/QTextBrowser>
+#include <QtGui/QAction>
+
+#if defined(USE_WEBKIT)
+#include <QWebView>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QHelpEngine;
+class CentralWidget;
+
+class QPoint;
+class QString;
+class QKeyEvent;
+class QMouseEvent;
+class QContextMenuEvent;
+
+#if defined(USE_WEBKIT)
+
+class HelpViewer : public QWebView
+{
+ Q_OBJECT
+
+public:
+ HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent);
+ void setSource(const QUrl &url);
+
+ inline QUrl source() const
+ { return url(); }
+
+ inline QString documentTitle() const
+ { return title(); }
+
+ inline bool hasSelection() const
+ { return !selectedText().isEmpty(); } // ### this is suboptimal
+
+ void resetZoom();
+ void zoomIn(qreal range = 1);
+ void zoomOut(qreal range = 1);
+
+ inline void copy()
+ { return triggerPageAction(QWebPage::Copy); }
+
+ inline bool isForwardAvailable() const
+ { return pageAction(QWebPage::Forward)->isEnabled(); }
+ inline bool isBackwardAvailable() const
+ { return pageAction(QWebPage::Back)->isEnabled(); }
+
+public Q_SLOTS:
+ void home();
+ void backward() { back(); }
+
+Q_SIGNALS:
+ void copyAvailable(bool enabled);
+ void forwardAvailable(bool enabled);
+ void backwardAvailable(bool enabled);
+ void highlighted(const QString &);
+ void sourceChanged(const QUrl &);
+
+protected:
+ virtual void wheelEvent(QWheelEvent *);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+private Q_SLOTS:
+ void actionChanged();
+
+private:
+ QHelpEngine *helpEngine;
+ CentralWidget* parentWidget;
+ QUrl homeUrl;
+};
+
+#else
+
+class HelpViewer : public QTextBrowser
+{
+ Q_OBJECT
+
+public:
+ HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent);
+ void setSource(const QUrl &url);
+
+ void resetZoom();
+ void zoomIn(int range = 1);
+ void zoomOut(int range = 1);
+ int zoom() const { return zoomCount; }
+ void setZoom(int zoom) { zoomCount = zoom; }
+
+ inline bool hasSelection() const
+ { return textCursor().hasSelection(); }
+
+private:
+ QVariant loadResource(int type, const QUrl &name);
+ void openLinkInNewTab(const QString &link);
+ bool hasAnchorAt(const QPoint& pos);
+ void contextMenuEvent(QContextMenuEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+
+private slots:
+ void openLinkInNewTab();
+
+private:
+ int zoomCount;
+ bool controlPressed;
+ QString lastAnchor;
+ QHelpEngine *helpEngine;
+ CentralWidget* parentWidget;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/shared/help/indexwindow.cpp b/shared/help/indexwindow.cpp
new file mode 100644
index 0000000000..fdc919c5be
--- /dev/null
+++ b/shared/help/indexwindow.cpp
@@ -0,0 +1,209 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "indexwindow.h"
+#include "centralwidget.h"
+#include "topicchooser.h"
+
+#include <QtGui/QLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QListWidgetItem>
+
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpIndexWidget>
+
+QT_BEGIN_NAMESPACE
+
+IndexWindow::IndexWindow(QHelpEngine *helpEngine, QWidget *parent)
+ : QWidget(parent)
+ , m_searchLineEdit(0)
+ , m_indexWidget(0)
+ , m_helpEngine(helpEngine)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ QLabel *l = new QLabel(tr("&Look for:"));
+ layout->addWidget(l);
+
+ m_searchLineEdit = new QLineEdit();
+ l->setBuddy(m_searchLineEdit);
+ connect(m_searchLineEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(filterIndices(const QString&)));
+ m_searchLineEdit->installEventFilter(this);
+ layout->setMargin(4);
+ layout->addWidget(m_searchLineEdit);
+
+ m_indexWidget = m_helpEngine->indexWidget();
+ m_indexWidget->installEventFilter(this);
+ connect(m_helpEngine->indexModel(), SIGNAL(indexCreationStarted()),
+ this, SLOT(disableSearchLineEdit()));
+ connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()),
+ this, SLOT(enableSearchLineEdit()));
+ connect(m_indexWidget, SIGNAL(linkActivated(const QUrl&, const QString&)),
+ this, SIGNAL(linkActivated(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linksActivated(const QMap<QString, QUrl>&,
+ const QString&)), this, SIGNAL(linksActivated(const QMap<QString, QUrl>&,
+ const QString&)));
+ connect(m_searchLineEdit, SIGNAL(returnPressed()),
+ m_indexWidget, SLOT(activateCurrentItem()));
+ layout->addWidget(m_indexWidget);
+
+ m_indexWidget->viewport()->installEventFilter(this);
+}
+
+IndexWindow::~IndexWindow()
+{
+}
+
+void IndexWindow::filterIndices(const QString &filter)
+{
+ if (filter.contains(QLatin1Char('*')))
+ m_indexWidget->filterIndices(filter, filter);
+ else
+ m_indexWidget->filterIndices(filter, QString());
+}
+
+bool IndexWindow::eventFilter(QObject *obj, QEvent *e)
+{
+ if (obj == m_searchLineEdit && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ QModelIndex idx = m_indexWidget->currentIndex();
+ switch (ke->key()) {
+ case Qt::Key_Up:
+ idx = m_indexWidget->model()->index(idx.row()-1,
+ idx.column(), idx.parent());
+ if (idx.isValid())
+ m_indexWidget->setCurrentIndex(idx);
+ break;
+ case Qt::Key_Down:
+ idx = m_indexWidget->model()->index(idx.row()+1,
+ idx.column(), idx.parent());
+ if (idx.isValid())
+ m_indexWidget->setCurrentIndex(idx);
+ break;
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+ default:
+ ;
+ }
+ } else if (obj == m_indexWidget && e->type() == QEvent::ContextMenu) {
+ QContextMenuEvent *ctxtEvent = static_cast<QContextMenuEvent*>(e);
+ QModelIndex idx = m_indexWidget->indexAt(ctxtEvent->pos());
+ if (idx.isValid()) {
+ QMenu menu;
+ QAction *curTab = menu.addAction(tr("Open Link"));
+ QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
+ menu.move(m_indexWidget->mapToGlobal(ctxtEvent->pos()));
+
+ QAction *action = menu.exec();
+ if (curTab == action)
+ m_indexWidget->activateCurrentItem();
+ else if (newTab == action) {
+ QHelpIndexModel *model =
+ qobject_cast<QHelpIndexModel*>(m_indexWidget->model());
+ QString keyword = model->data(idx, Qt::DisplayRole).toString();
+ if (model) {
+ QMap<QString, QUrl> links = model->linksForKeyword(keyword);
+ if (links.count() == 1) {
+ CentralWidget::instance()->
+ setSourceInNewTab(links.constBegin().value());
+ } else {
+ TopicChooser tc(this, keyword, links);
+ if (tc.exec() == QDialog::Accepted) {
+ CentralWidget::instance()->setSourceInNewTab(tc.link());
+ }
+ }
+ }
+ }
+ }
+ } else if (m_indexWidget && obj == m_indexWidget->viewport()
+ && e->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
+ QModelIndex idx = m_indexWidget->indexAt(mouseEvent->pos());
+ if (idx.isValid() && mouseEvent->button()==Qt::MidButton) {
+ QHelpIndexModel *model =
+ qobject_cast<QHelpIndexModel*>(m_indexWidget->model());
+ QString keyword = model->data(idx, Qt::DisplayRole).toString();
+ if (model) {
+ QMap<QString, QUrl> links = model->linksForKeyword(keyword);
+ if (links.count() > 1) {
+ TopicChooser tc(this, keyword, links);
+ if (tc.exec() == QDialog::Accepted) {
+ CentralWidget::instance()->setSourceInNewTab(tc.link());
+ }
+ } else {
+ CentralWidget::instance()->
+ setSourceInNewTab(links.constBegin().value());
+ }
+ }
+ }
+ }
+#ifdef Q_OS_MAC
+ else if (obj == m_indexWidget && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter)
+ m_indexWidget->activateCurrentItem();
+ }
+#endif
+ return QWidget::eventFilter(obj, e);
+}
+
+void IndexWindow::enableSearchLineEdit()
+{
+ m_searchLineEdit->setDisabled(false);
+ filterIndices(m_searchLineEdit->text());
+}
+
+void IndexWindow::disableSearchLineEdit()
+{
+ m_searchLineEdit->setDisabled(true);
+}
+
+void IndexWindow::setSearchLineEditText(const QString &text)
+{
+ m_searchLineEdit->setText(text);
+}
+
+void IndexWindow::focusInEvent(QFocusEvent *e)
+{
+ if (e->reason() != Qt::MouseFocusReason) {
+ m_searchLineEdit->selectAll();
+ m_searchLineEdit->setFocus();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/shared/help/indexwindow.h b/shared/help/indexwindow.h
new file mode 100644
index 0000000000..9554979e77
--- /dev/null
+++ b/shared/help/indexwindow.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INDEXWINDOW
+#define INDEXWINDOW
+
+#include <QtCore/QUrl>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QLineEdit;
+class QHelpIndexWidget;
+class QHelpEngine;
+
+class IndexWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0);
+ ~IndexWindow();
+
+ void setSearchLineEditText(const QString &text);
+
+signals:
+ void linkActivated(const QUrl &link);
+ void linksActivated(const QMap<QString, QUrl> &links,
+ const QString &keyword);
+ void escapePressed();
+
+private slots:
+ void filterIndices(const QString &filter);
+ void enableSearchLineEdit();
+ void disableSearchLineEdit();
+
+private:
+ bool eventFilter(QObject *obj, QEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ QLineEdit *m_searchLineEdit;
+ QHelpIndexWidget *m_indexWidget;
+ QHelpEngine *m_helpEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/shared/help/topicchooser.cpp b/shared/help/topicchooser.cpp
new file mode 100644
index 0000000000..eeb17dc1f5
--- /dev/null
+++ b/shared/help/topicchooser.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtCore/QMap>
+#include <QtCore/QUrl>
+
+#include "topicchooser.h"
+
+QT_BEGIN_NAMESPACE
+
+TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
+ const QMap<QString, QUrl> &links)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ ui.label->setText(tr("Choose a topic for <b>%1</b>:").arg(keyword));
+
+ m_links = links;
+ QMap<QString, QUrl>::const_iterator it = m_links.constBegin();
+ for (; it != m_links.constEnd(); ++it)
+ ui.listWidget->addItem(it.key());
+
+ if (ui.listWidget->count() != 0)
+ ui.listWidget->setCurrentRow(0);
+ ui.listWidget->setFocus();
+
+ connect(ui.buttonDisplay, SIGNAL(clicked()),
+ this, SLOT(accept()));
+ connect(ui.buttonCancel, SIGNAL(clicked()),
+ this, SLOT(reject()));
+ connect(ui.listWidget, SIGNAL(itemActivated(QListWidgetItem*)),
+ this, SLOT(accept()));
+}
+
+QUrl TopicChooser::link() const
+{
+ QListWidgetItem *item = ui.listWidget->currentItem();
+ if (!item)
+ return QUrl();
+
+ QString title = item->text();
+ if (title.isEmpty() || !m_links.contains(title))
+ return QUrl();
+
+ return m_links.value(title);
+}
+
+QT_END_NAMESPACE
diff --git a/shared/help/topicchooser.h b/shared/help/topicchooser.h
new file mode 100644
index 0000000000..45b65d2399
--- /dev/null
+++ b/shared/help/topicchooser.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef TOPICCHOOSER_H
+#define TOPICCHOOSER_H
+
+#include <QUrl>
+#include <QMap>
+#include <QString>
+
+#include <QtGui/QDialog>
+#include "ui_topicchooser.h"
+
+QT_BEGIN_NAMESPACE
+
+class TopicChooser : public QDialog
+{
+ Q_OBJECT
+
+public:
+ TopicChooser(QWidget *parent, const QString &keyword,
+ const QMap<QString, QUrl> &links);
+
+ QUrl link() const;
+
+private:
+ Ui::TopicChooser ui;
+ QMap<QString, QUrl> m_links;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/shared/help/topicchooser.ui b/shared/help/topicchooser.ui
new file mode 100644
index 0000000000..d4c90bb4b3
--- /dev/null
+++ b/shared/help/topicchooser.ui
@@ -0,0 +1,116 @@
+<UI version="4.0" stdsetdef="1" >
+ <class>TopicChooser</class>
+ <widget class="QDialog" name="TopicChooser" >
+ <property name="objectName" >
+ <string notr="true">TopicChooser</string>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>391</width>
+ <height>223</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Choose Topic</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="objectName" >
+ <string notr="true">unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>11</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="objectName" >
+ <string notr="true">label</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Topics</string>
+ </property>
+ <property name="buddy" stdset="0" >
+ <cstring>listWidget</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="listWidget" >
+ <property name="objectName" >
+ <string notr="true">listWidget</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Layout16" >
+ <property name="objectName" >
+ <string notr="true">Layout16</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="objectName" >
+ <string notr="true">unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer name="Horizontal Spacing2" >
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDisplay" >
+ <property name="objectName" >
+ <string notr="true">buttonDisplay</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Display</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="objectName" >
+ <string notr="true">buttonCancel</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Close</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+</UI>
diff --git a/shared/indenter/README b/shared/indenter/README
new file mode 100644
index 0000000000..deaac0168b
--- /dev/null
+++ b/shared/indenter/README
@@ -0,0 +1,9 @@
+C++ / Qt Script indenter based on:
+
+research/qsa/quickport/src/neweditor/yyindent.cpp
+
+Known issues:
+- Using an indentation different from 4 makes it goof up.
+
+History:
+- 070510: Split off the test application and made it work with Qt 4.
diff --git a/shared/indenter/constants.cpp b/shared/indenter/constants.cpp
new file mode 100644
index 0000000000..8ff9612ca3
--- /dev/null
+++ b/shared/indenter/constants.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "indenter.h"
+
+using namespace SharedTools::IndenterInternal;
+
+// --- Constants
+Constants::Constants() :
+ m_slashAster(QLatin1String("/*")),
+ m_asterSlash(QLatin1String("*/")),
+ m_slashSlash(QLatin1String("//")),
+ m_else(QLatin1String("else")),
+ m_qobject(QLatin1String("Q_OBJECT")),
+ m_operators(QLatin1String("!=<>")),
+ m_bracesSemicolon(QLatin1String("{};")),
+ m_3dots(QLatin1String("...")),
+
+ m_literal(QLatin1String("([\"'])(?:\\\\.|[^\\\\])*\\1")),
+ m_label(QLatin1String("^\\s*((?:case\\b([^:]|::)+|[a-zA-Z_0-9]+)(?:\\s+slots|\\s+Q_SLOTS)?:)(?!:)")),
+ m_inlineCComment(QLatin1String("/\\*.*\\*/")),
+ m_braceX(QLatin1String("^\\s*\\}\\s*(?:else|catch)\\b")),
+ m_iflikeKeyword(QLatin1String("\\b(?:catch|do|for|if|while|foreach)\\b")),
+ m_caseLabel(QLatin1String("\\s*(?:case\\b(?:[^:]|::)+"
+ "|(?:public|protected|private|signals|Q_SIGNALS|default)(?:\\s+slots|\\s+Q_SLOTS)?\\s*"
+ ")?:.*"))
+{
+ m_literal.setMinimal( true );
+ m_inlineCComment.setMinimal( true );
+ Q_ASSERT(m_literal.isValid());
+ Q_ASSERT(m_label.isValid());
+ Q_ASSERT(m_inlineCComment.isValid());
+ Q_ASSERT(m_braceX.isValid());
+ Q_ASSERT(m_iflikeKeyword.isValid());
+ Q_ASSERT(m_caseLabel.isValid());
+}
diff --git a/shared/indenter/indenter.h b/shared/indenter/indenter.h
new file mode 100644
index 0000000000..4e2226245c
--- /dev/null
+++ b/shared/indenter/indenter.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INDENTER_H
+#define INDENTER_H
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+namespace SharedTools {
+namespace IndenterInternal {
+/* String constants and regexps required by the indenter. Separate for code cleanliness*/
+struct Constants {
+ Constants();
+ const QString m_slashAster;
+ const QString m_asterSlash;
+ const QString m_slashSlash;
+ const QString m_else;
+ const QString m_qobject;
+ const QString m_operators;
+ const QString m_bracesSemicolon;
+ const QString m_3dots;
+
+ QRegExp m_literal;
+ QRegExp m_label;
+ QRegExp m_inlineCComment;
+ QRegExp m_braceX;
+ QRegExp m_iflikeKeyword;
+ QRegExp m_caseLabel;
+};
+
+/* The "linizer" is a group of functions and variables to iterate
+ * through the source code of the program to indent. The program is
+ * given as a list of strings, with the bottom line being the line to
+ * indent. The actual program might contain extra lines, but those are
+ * uninteresting and not passed over to us. */
+template <class Iterator>
+struct LinizerState {
+
+ QString line;
+ int braceDepth;
+ bool leftBraceFollows;
+
+ Iterator iter;
+ bool inCComment;
+ bool pendingRightBrace;
+};
+}
+
+/* Indenter singleton as a template of a bidirectional input iterator
+ * of a sequence of code lines represented as QString.
+ * When setting the parameters, be careful to
+ * specify the correct template parameters (best use a typedef). */
+template <class Iterator>
+class Indenter {
+ Indenter(const Indenter&);
+ Indenter &operator=(const Indenter&);
+ Indenter();
+
+public:
+
+ ~Indenter();
+
+ static Indenter &instance();
+
+ void setIndentSize(int size);
+ void setTabSize(int size );
+
+ /* Return indentation for the last line of the sequence
+ * based on the previous lines. */
+ int indentForBottomLine(const Iterator &current,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedIn);
+
+ // Helpers.
+ static bool isOnlyWhiteSpace( const QString& t);
+ static QChar firstNonWhiteSpace( const QString& t );
+
+private:
+ int columnForIndex( const QString& t, int index ) const;
+ int indentOfLine( const QString& t ) const;
+ QString trimmedCodeLine( const QString& t );
+ bool readLine();
+ void startLinizer();
+ bool bottomLineStartsInCComment();
+ int indentWhenBottomLineStartsInCComment() const;
+ bool matchBracelessControlStatement();
+ bool isUnfinishedLine();
+ bool isContinuationLine();
+ int indentForContinuationLine();
+ int indentForStandaloneLine();
+
+ IndenterInternal::Constants m_constants;
+ int ppHardwareTabSize;
+ int ppIndentSize;
+ int ppContinuationIndentSize;
+
+ Iterator yyProgramBegin;
+ Iterator yyProgramEnd;
+
+ typedef typename IndenterInternal::LinizerState<Iterator> LinizerState;
+
+ LinizerState *yyLinizerState ;
+
+ // shorthands
+ const QString *yyLine;
+ const int *yyBraceDepth;
+ const bool *yyLeftBraceFollows;
+};
+}
+
+#include "indenter_impl.h"
+
+#endif
diff --git a/shared/indenter/indenter.pri b/shared/indenter/indenter.pri
new file mode 100644
index 0000000000..3d1d4bbb1d
--- /dev/null
+++ b/shared/indenter/indenter.pri
@@ -0,0 +1,5 @@
+INCLUDEPATH *= $$PWD
+
+SOURCES += $$PWD/constants.cpp
+HEADERS += $$PWD/indenter.h \
+ $$PWD/indenter_impl.h
diff --git a/shared/indenter/indenter_impl.h b/shared/indenter/indenter_impl.h
new file mode 100644
index 0000000000..c60c380a55
--- /dev/null
+++ b/shared/indenter/indenter_impl.h
@@ -0,0 +1,1123 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INDENTER_C
+#define INDENTER_C
+
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/*
+ This file is a self-contained interactive indenter for C++ and Qt
+ Script.
+
+ The general problem of indenting a C++ program is ill posed. On the
+ one hand, an indenter has to analyze programs written in a
+ free-form formal language that is best described in terms of
+ tokens, not characters, not lines. On the other hand, indentation
+ applies to lines and white space characters matter, and otherwise
+ the programs to indent are formally invalid in general, as they are
+ being edited.
+
+ The approach taken here works line by line. We receive a program
+ consisting of N lines or more, and we want to compute the
+ indentation appropriate for the Nth line. Lines beyond the Nth
+ lines are of no concern to us, so for simplicity we pretend the
+ program has exactly N lines and we call the Nth line the "bottom
+ line". Typically, we have to indent the bottom line when it's still
+ empty, so we concentrate our analysis on the N - 1 lines that
+ precede.
+
+ By inspecting the (N - 1)-th line, the (N - 2)-th line, ...
+ backwards, we determine the kind of the bottom line and indent it
+ accordingly.
+
+ * The bottom line is a comment line. See
+ bottomLineStartsInCComment() and
+ indentWhenBottomLineStartsInCComment().
+ * The bottom line is a continuation line. See isContinuationLine()
+ and indentForContinuationLine().
+ * The bottom line is a standalone line. See
+ indentForStandaloneLine().
+
+ Certain tokens that influence the indentation, notably braces, are
+ looked for in the lines. This is done by simple string comparison,
+ without a real tokenizer. Confusing constructs such as comments and
+ string literals are removed beforehand.
+*/
+
+namespace SharedTools {
+
+/* qmake ignore Q_OBJECT */
+
+/*
+ The indenter avoids getting stuck in almost infinite loops by
+ imposing arbitrary limits on the number of lines it analyzes when
+ looking for a construct.
+
+ For example, the indenter never considers more than BigRoof lines
+ backwards when looking for the start of a C-style comment.
+*/
+namespace {
+ enum { SmallRoof = 40, BigRoof = 400 };
+
+/*
+ The indenter supports a few parameters:
+
+ * ppHardwareTabSize is the size of a '\t' in your favorite editor.
+ * ppIndentSize is the size of an indentation, or software tab
+ size.
+ * ppContinuationIndentSize is the extra indent for a continuation
+ line, when there is nothing to align against on the previous
+ line.
+ * ppCommentOffset is the indentation within a C-style comment,
+ when it cannot be picked up.
+*/
+
+
+ enum { ppCommentOffset = 2 };
+}
+
+template <class Iterator>
+Indenter<Iterator>::Indenter() :
+ ppHardwareTabSize(8),
+ ppIndentSize(4),
+ ppContinuationIndentSize(8),
+ yyLinizerState(new LinizerState),
+ yyLine(0),
+ yyBraceDepth(0),
+ yyLeftBraceFollows(0)
+{
+}
+
+template <class Iterator>
+Indenter<Iterator>::~Indenter()
+{
+ delete yyLinizerState;
+}
+
+template <class Iterator>
+Indenter<Iterator> &Indenter<Iterator>::instance()
+{
+ static Indenter rc;
+ return rc;
+}
+
+template <class Iterator>
+void Indenter<Iterator>::setIndentSize(int size)
+{
+ ppIndentSize = size;
+ ppContinuationIndentSize = 2 * size;
+}
+
+template <class Iterator>
+void Indenter<Iterator>::setTabSize(int size )
+{
+ ppHardwareTabSize = size;
+}
+/*
+ Returns the first non-space character in the string t, or
+ QChar::null if the string is made only of white space.
+*/
+template <class Iterator>
+QChar Indenter<Iterator>::firstNonWhiteSpace( const QString& t )
+{
+ if (const int len = t.length())
+ for ( int i = 0; i < len; i++)
+ if ( !t[i].isSpace() )
+ return t[i];
+ return QChar::Null;
+}
+
+/*
+ Returns true if string t is made only of white space; otherwise
+ returns false.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::isOnlyWhiteSpace( const QString& t )
+{
+ return t.isEmpty() || firstNonWhiteSpace( t ).isNull();
+}
+
+/*
+ Assuming string t is a line, returns the column number of a given
+ index. Column numbers and index are identical for strings that don't
+ contain '\t's.
+*/
+template <class Iterator>
+int Indenter<Iterator>::columnForIndex( const QString& t, int index ) const
+{
+ int col = 0;
+ if ( index > t.length() )
+ index = t.length();
+
+ const QChar tab = QLatin1Char('\t');
+
+ for ( int i = 0; i < index; i++ ) {
+ if ( t[i] == tab ) {
+ col = ( (col / ppHardwareTabSize) + 1 ) * ppHardwareTabSize;
+ } else {
+ col++;
+ }
+ }
+ return col;
+}
+
+/*
+ Returns the indentation size of string t.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentOfLine( const QString& t ) const
+{
+ return columnForIndex( t, t.indexOf(firstNonWhiteSpace(t)) );
+}
+
+/*
+ Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better
+ left alone since they break the "index equals column" rule. No
+ provisions are taken against '\n' or '\r', which shouldn't occur in
+ t anyway.
+*/
+static inline void eraseChar( QString& t, int k, QChar ch )
+{
+ if ( t[k] != QLatin1Char('\t') )
+ t[k] = ch;
+}
+
+/*
+ Removes some nefast constructs from a code line and returns the
+ resulting line.
+*/
+template <class Iterator>
+QString Indenter<Iterator>::trimmedCodeLine( const QString& t )
+{
+ QString trimmed = t;
+ int k;
+
+ const QChar capitalX = QLatin1Char('X');
+ const QChar blank = QLatin1Char(' ');
+ const QChar colon = QLatin1Char(':');
+ const QChar semicolon = QLatin1Char(';');
+ /*
+ Replace character and string literals by X's, since they may
+ contain confusing characters (such as '{' and ';'). "Hello!" is
+ replaced by XXXXXXXX. The literals are rigourously of the same
+ length before and after; otherwise, we would break alignment of
+ continuation lines.
+ */
+ k = 0;
+ while ( (k = m_constants.m_literal.indexIn(trimmed), k) != -1 ) {
+ const int matchedLength = m_constants.m_literal.matchedLength();
+ for ( int i = 0; i < matchedLength ; i++ )
+ eraseChar( trimmed, k + i, capitalX );
+ k += matchedLength;
+ }
+
+ /*
+ Replace inline C-style comments by spaces. Other comments are
+ handled elsewhere.
+ */
+ k = 0;
+ while ( (k = m_constants.m_inlineCComment.indexIn(trimmed, k)) != -1 ) {
+ const int matchedLength = m_constants.m_inlineCComment.matchedLength();
+ for ( int i = 0; i < matchedLength; i++ )
+ eraseChar( trimmed, k + i, blank );
+ k += matchedLength;
+ }
+
+ /*
+ Replace goto and switch labels by whitespace, but be careful
+ with this case:
+
+ foo1: bar1;
+ bar2;
+ */
+ while ( trimmed.lastIndexOf(colon ) != -1 && m_constants.m_label.indexIn(trimmed) != -1 ) {
+ const QString cap1 = m_constants.m_label.cap( 1 );
+ const int pos1 = m_constants.m_label.pos( 1 );
+ int stop = cap1.length();
+
+ if ( pos1 + stop < trimmed.length() && ppIndentSize < stop )
+ stop = ppIndentSize;
+
+ int i = 0;
+ while ( i < stop ) {
+ eraseChar( trimmed, pos1 + i, blank );
+ i++;
+ }
+ while ( i < cap1.length() ) {
+ eraseChar( trimmed, pos1 + i,semicolon );
+ i++;
+ }
+ }
+
+ /*
+ Remove C++-style comments.
+ */
+ k = trimmed.indexOf(m_constants.m_slashSlash );
+ if ( k != -1 )
+ trimmed.truncate( k );
+
+ return trimmed;
+}
+
+/*
+ Returns '(' if the last parenthesis is opening, ')' if it is
+ closing, and QChar::null if there are no parentheses in t.
+*/
+static inline QChar lastParen( const QString& t )
+{
+
+ const QChar opening = QLatin1Char('(');
+ const QChar closing = QLatin1Char(')');
+
+
+ int i = t.length();
+ while ( i > 0 ) {
+ i--;
+ const QChar c = t[i];
+ if (c == opening || c == closing )
+ return c;
+ }
+ return QChar::Null;
+}
+
+/*
+ Returns true if typedIn the same as okayCh or is null; otherwise
+ returns false.
+*/
+static inline bool okay( QChar typedIn, QChar okayCh )
+{
+ return typedIn == QChar::Null || typedIn == okayCh;
+}
+
+
+/*
+ Saves and restores the state of the global linizer. This enables
+ backtracking.
+*/
+#define YY_SAVE() \
+ LinizerState savedState = *yyLinizerState
+#define YY_RESTORE() \
+ *yyLinizerState = savedState
+
+/*
+ Advances to the previous line in yyProgram and update yyLine
+ accordingly. yyLine is cleaned from comments and other damageable
+ constructs. Empty lines are skipped.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::readLine()
+{
+ int k;
+
+ const QChar openingBrace = QLatin1Char('{');
+ const QChar closingBrace = QLatin1Char('}');
+ const QChar blank = QLatin1Char(' ');
+ const QChar hash = QLatin1Char('#');
+
+ yyLinizerState->leftBraceFollows =
+ ( firstNonWhiteSpace(yyLinizerState->line) == openingBrace );
+
+ do {
+ if ( yyLinizerState->iter == yyProgramBegin ) {
+ yyLinizerState->line = QString::null;
+ return false;
+ }
+
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+
+ yyLinizerState->line = trimmedCodeLine( yyLinizerState->line );
+
+ /*
+ Remove C-style comments that span multiple lines. If the
+ bottom line starts in a C-style comment, we are not aware
+ of that and eventually yyLine will contain a slash-aster.
+
+ Notice that both if's can be executed, since
+ yyLinizerState->inCComment is potentially set to false in
+ the first if. The order of the if's is also important.
+ */
+
+ if ( yyLinizerState->inCComment ) {
+
+ k = yyLinizerState->line.indexOf( m_constants.m_slashAster );
+ if ( k == -1 ) {
+ yyLinizerState->line = QString::null;
+ } else {
+ yyLinizerState->line.truncate( k );
+ yyLinizerState->inCComment = false;
+ }
+ }
+
+ if ( !yyLinizerState->inCComment ) {
+ k = yyLinizerState->line.indexOf( m_constants.m_asterSlash );
+ if ( k != -1 ) {
+ for ( int i = 0; i < k + 2; i++ )
+ eraseChar( yyLinizerState->line, i, blank );
+ yyLinizerState->inCComment = true;
+ }
+ }
+
+ /*
+ Remove preprocessor directives.
+ */
+ k = 0;
+ while ( k < yyLinizerState->line.length() ) {
+ QChar ch = yyLinizerState->line[k];
+ if ( ch == hash ) {
+ yyLinizerState->line = QString::null;
+ } else if ( !ch.isSpace() ) {
+ break;
+ }
+ k++;
+ }
+
+ /*
+ Remove trailing spaces.
+ */
+ k = yyLinizerState->line.length();
+ while ( k > 0 && yyLinizerState->line[k - 1].isSpace() )
+ k--;
+ yyLinizerState->line.truncate( k );
+
+ /*
+ '}' increment the brace depth and '{' decrements it and not
+ the other way around, as we are parsing backwards.
+ */
+ yyLinizerState->braceDepth +=
+ yyLinizerState->line.count( closingBrace ) - yyLinizerState->line.count( openingBrace );
+
+ /*
+ We use a dirty trick for
+
+ } else ...
+
+ We don't count the '}' yet, so that it's more or less
+ equivalent to the friendly construct
+
+ }
+ else ...
+ */
+ if ( yyLinizerState->pendingRightBrace )
+ yyLinizerState->braceDepth++;
+ yyLinizerState->pendingRightBrace =
+ ( m_constants.m_braceX.indexIn(yyLinizerState->line) == 0 );
+ if ( yyLinizerState->pendingRightBrace )
+ yyLinizerState->braceDepth--;
+ } while ( yyLinizerState->line.isEmpty() );
+
+ return true;
+}
+
+/*
+ Resets the linizer to its initial state, with yyLine containing the
+ line above the bottom line of the program.
+*/
+template <class Iterator>
+void Indenter<Iterator>::startLinizer()
+{
+ yyLinizerState->braceDepth = 0;
+ yyLinizerState->inCComment = false;
+ yyLinizerState->pendingRightBrace = false;
+
+ yyLine = &yyLinizerState->line;
+ yyBraceDepth = &yyLinizerState->braceDepth;
+ yyLeftBraceFollows = &yyLinizerState->leftBraceFollows;
+
+ yyLinizerState->iter = yyProgramEnd;
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+ readLine();
+}
+
+/*
+ Returns true if the start of the bottom line of yyProgram (and
+ potentially the whole line) is part of a C-style comment; otherwise
+ returns false.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::bottomLineStartsInCComment()
+{
+ /*
+ We could use the linizer here, but that would slow us down
+ terribly. We are better to trim only the code lines we need.
+ */
+ Iterator p = yyProgramEnd;
+ --p; // skip bottom line
+
+ for ( int i = 0; i < BigRoof; i++ ) {
+ if ( p == yyProgramBegin )
+ return false;
+ --p;
+
+ if ( (*p).contains(m_constants.m_slashAster) || (*p).contains(m_constants.m_asterSlash) ) {
+ QString trimmed = trimmedCodeLine( *p );
+
+ if ( trimmed.contains(m_constants.m_slashAster) ) {
+ return true;
+ } else if ( trimmed.contains(m_constants.m_asterSlash) ) {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram
+ assuming that it starts in a C-style comment, a condition that is
+ tested elsewhere.
+
+ Essentially, we're trying to align against some text on the previous
+ line.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentWhenBottomLineStartsInCComment() const
+{
+ int k = yyLine->lastIndexOf(m_constants.m_slashAster );
+ if ( k == -1 ) {
+ /*
+ We found a normal text line in a comment. Align the
+ bottom line with the text on this line.
+ */
+ return indentOfLine( *yyLine );
+ } else {
+ /*
+ The C-style comment starts on this line. If there is
+ text on the same line, align with it. Otherwise, align
+ with the slash-aster plus a given offset.
+ */
+ const int indent = columnForIndex( *yyLine, k );
+ k += 2;
+ while ( k < yyLine->length() ) {
+ if ( !(*yyLine)[k].isSpace() )
+ return columnForIndex( *yyLine, k );
+ k++;
+ }
+ return indent + ppCommentOffset;
+ }
+}
+
+/*
+ A function called match...() modifies the linizer state. If it
+ returns true, yyLine is the top line of the matched construct;
+ otherwise, the linizer is left in an unknown state.
+
+ A function called is...() keeps the linizer state intact.
+*/
+
+/*
+ Returns true if the current line (and upwards) forms a braceless
+ control statement; otherwise returns false.
+
+ The first line of the following example is a "braceless control
+ statement":
+
+ if ( x )
+ y;
+*/
+template <class Iterator>
+bool Indenter<Iterator>::matchBracelessControlStatement()
+{
+ int delimDepth = 0;
+
+ const QChar semicolon = QLatin1Char(';');
+
+
+ if ( yyLine->endsWith(m_constants.m_else))
+ return true;
+
+ if ( !yyLine->endsWith(QLatin1Char(')')))
+ return false;
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ int j = yyLine->length();
+ while ( j > 0 ) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch ( ch.unicode() ) {
+ case ')':
+ delimDepth++;
+ break;
+ case '(':
+ delimDepth--;
+ if ( delimDepth == 0 ) {
+ if ( yyLine->contains(m_constants.m_iflikeKeyword) ) {
+ /*
+ We have
+
+ if ( x )
+ y
+
+ "if ( x )" is not part of the statement
+ "y".
+ */
+ return true;
+ }
+ }
+ if ( delimDepth == -1 ) {
+ /*
+ We have
+
+ if ( (1 +
+ 2)
+
+ and not
+
+ if ( 1 +
+ 2 )
+ */
+ return false;
+ }
+ break;
+ case '{':
+ case '}':
+ case ';':
+ /*
+ We met a statement separator, but not where we
+ expected it. What follows is probably a weird
+ continuation line. Be careful with ';' in for,
+ though.
+ */
+ if ( ch != semicolon || delimDepth == 0 )
+ return false;
+ }
+ }
+
+ if ( !readLine() )
+ break;
+ }
+ return false;
+}
+
+/*
+ Returns true if yyLine is an unfinished line; otherwise returns
+ false.
+
+ In many places we'll use the terms "standalone line", "unfinished
+ line" and "continuation line". The meaning of these should be
+ evident from this code example:
+
+ a = b; // standalone line
+ c = d + // unfinished line
+ e + // unfinished continuation line
+ f + // unfinished continuation line
+ g; // continuation line
+*/
+template <class Iterator>
+bool Indenter<Iterator>::isUnfinishedLine()
+{
+ bool unf = false;
+
+ YY_SAVE();
+
+ const QChar openingParenthesis = QLatin1Char('(');
+ const QChar semicolon = QLatin1Char(';');
+
+ if ( yyLine->isEmpty() )
+ return false;
+
+ const QChar lastCh = (*yyLine)[ yyLine->length() - 1];
+ if ( ! m_constants.m_bracesSemicolon.contains(lastCh) && !yyLine->endsWith(m_constants.m_3dots) ) {
+ /*
+ It doesn't end with ';' or similar. If it's neither
+ "Q_OBJECT" nor "if ( x )", it must be an unfinished line.
+ */
+ unf = ( yyLine->contains(m_constants.m_qobject) == 0 &&
+ !matchBracelessControlStatement() );
+ } else if ( lastCh == semicolon ) {
+ if ( lastParen(*yyLine) == openingParenthesis ) {
+ /*
+ Exception:
+
+ for ( int i = 1; i < 10;
+ */
+ unf = true;
+ } else if ( readLine() && yyLine->endsWith(semicolon) &&
+ lastParen(*yyLine) == openingParenthesis ) {
+ /*
+ Exception:
+
+ for ( int i = 1;
+ i < 10;
+ */
+ unf = true;
+ }
+ }
+
+ YY_RESTORE();
+ return unf;
+}
+
+/*
+ Returns true if yyLine is a continuation line; otherwise returns
+ false.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::isContinuationLine()
+{
+ YY_SAVE();
+ const bool cont = readLine() && isUnfinishedLine();
+ YY_RESTORE();
+ return cont;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram,
+ assuming it's a continuation line.
+
+ We're trying to align the continuation line against some parenthesis
+ or other bracked left opened on a previous line, or some interesting
+ operator such as '='.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentForContinuationLine()
+{
+ int braceDepth = 0;
+ int delimDepth = 0;
+
+ bool leftBraceFollowed = *yyLeftBraceFollows;
+
+ const QChar equals = QLatin1Char('=');
+ const QChar comma = QLatin1Char(',');
+ const QChar openingParenthesis = QLatin1Char('(');
+ const QChar closingParenthesis = QLatin1Char(')');
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ int hook = -1;
+
+ int j = yyLine->length();
+ while ( j > 0 && hook < 0 ) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch ( ch.unicode() ) {
+ case ')':
+ case ']':
+ delimDepth++;
+ break;
+ case '}':
+ braceDepth++;
+ break;
+ case '(':
+ case '[':
+ delimDepth--;
+ /*
+ An unclosed delimiter is a good place to align at,
+ at least for some styles (including Trolltech's).
+ */
+ if ( delimDepth == -1 )
+ hook = j;
+ break;
+ case '{':
+ braceDepth--;
+ /*
+ A left brace followed by other stuff on the same
+ line is typically for an enum or an initializer.
+ Such a brace must be treated just like the other
+ delimiters.
+ */
+ if ( braceDepth == -1 ) {
+ if ( j < yyLine->length() - 1 ) {
+ hook = j;
+ } else {
+ return 0; // shouldn't happen
+ }
+ }
+ break;
+ case '=':
+ /*
+ An equal sign is a very natural alignment hook
+ because it's usually the operator with the lowest
+ precedence in statements it appears in. Case in
+ point:
+
+ int x = 1 +
+ 2;
+
+ However, we have to beware of constructs such as
+ default arguments and explicit enum constant
+ values:
+
+ void foo( int x = 0,
+ int y = 0 );
+
+ And not
+
+ void foo( int x = 0,
+ int y = 0 );
+
+ These constructs are caracterized by a ',' at the
+ end of the unfinished lines or by unbalanced
+ parentheses.
+ */
+ if ( j > 0 && j < yyLine->length() - 1
+ && !m_constants.m_operators.contains((*yyLine)[j - 1])
+ && (*yyLine)[j + 1] != equals ) {
+ if ( braceDepth == 0 && delimDepth == 0 &&
+ !yyLine->endsWith(comma) &&
+ (yyLine->contains(openingParenthesis) == yyLine->contains(closingParenthesis)) )
+ hook = j;
+ }
+ }
+ }
+
+ if ( hook >= 0 ) {
+ /*
+ Yes, we have a delimiter or an operator to align
+ against! We don't really align against it, but rather
+ against the following token, if any. In this example,
+ the following token is "11":
+
+ int x = ( 11 +
+ 2 );
+
+ If there is no such token, we use a continuation indent:
+
+ static QRegExp foo( QString(
+ "foo foo foo foo foo foo foo foo foo") );
+ */
+ hook++;
+ while ( hook < yyLine->length() ) {
+ if ( !(*yyLine)[hook].isSpace() )
+ return columnForIndex( *yyLine, hook );
+ hook++;
+ }
+ return indentOfLine( *yyLine ) + ppContinuationIndentSize;
+ }
+
+ if ( braceDepth != 0 )
+ break;
+
+ /*
+ The line's delimiters are balanced. It looks like a
+ continuation line or something.
+ */
+ if ( delimDepth == 0 ) {
+ if ( leftBraceFollowed ) {
+ /*
+ We have
+
+ int main()
+ {
+
+ or
+
+ Bar::Bar()
+ : Foo( x )
+ {
+
+ The "{" should be flush left.
+ */
+ if ( !isContinuationLine() )
+ return indentOfLine( *yyLine );
+ } else if ( isContinuationLine() || yyLine->endsWith(comma)) {
+ /*
+ We have
+
+ x = a +
+ b +
+ c;
+
+ or
+
+ int t[] = {
+ 1, 2, 3,
+ 4, 5, 6
+
+ The "c;" should fall right under the "b +", and the
+ "4, 5, 6" right under the "1, 2, 3,".
+ */
+ return indentOfLine( *yyLine );
+ } else {
+ /*
+ We have
+
+ stream << 1 +
+ 2;
+
+ We could, but we don't, try to analyze which
+ operator has precedence over which and so on, to
+ obtain the excellent result
+
+ stream << 1 +
+ 2;
+
+ We do have a special trick above for the assignment
+ operator above, though.
+ */
+ return indentOfLine( *yyLine ) + ppContinuationIndentSize;
+ }
+ }
+
+ if ( !readLine() )
+ break;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram if
+ that line is standalone (or should be indented likewise).
+
+ Indenting a standalone line is tricky, mostly because of braceless
+ control statements. Grossly, we are looking backwards for a special
+ line, a "hook line", that we can use as a starting point to indent,
+ and then modify the indentation level according to the braces met
+ along the way to that hook.
+
+ Let's consider a few examples. In all cases, we want to indent the
+ bottom line.
+
+ Example 1:
+
+ x = 1;
+ y = 2;
+
+ The hook line is "x = 1;". We met 0 opening braces and 0 closing
+ braces. Therefore, "y = 2;" inherits the indent of "x = 1;".
+
+ Example 2:
+
+ if ( x ) {
+ y;
+
+ The hook line is "if ( x ) {". No matter what precedes it, "y;" has
+ to be indented one level deeper than the hook line, since we met one
+ opening brace along the way.
+
+ Example 3:
+
+ if ( a )
+ while ( b ) {
+ c;
+ }
+ d;
+
+ To indent "d;" correctly, we have to go as far as the "if ( a )".
+ Compare with
+
+ if ( a ) {
+ while ( b ) {
+ c;
+ }
+ d;
+
+ Still, we're striving to go back as little as possible to accomodate
+ people with irregular indentation schemes. A hook line near at hand
+ is much more reliable than a remote one.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentForStandaloneLine()
+{
+ const QChar semicolon = QLatin1Char(';');
+ const QChar openingBrace = QLatin1Char('{');
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ if ( !*yyLeftBraceFollows ) {
+ YY_SAVE();
+
+ if ( matchBracelessControlStatement() ) {
+ /*
+ The situation is this, and we want to indent "z;":
+
+ if ( x &&
+ y )
+ z;
+
+ yyLine is "if ( x &&".
+ */
+ return indentOfLine( *yyLine ) + ppIndentSize;
+ }
+ YY_RESTORE();
+ }
+
+ if ( yyLine->endsWith(semicolon) || yyLine->count(openingBrace) > 0 ) {
+ /*
+ The situation is possibly this, and we want to indent
+ "z;":
+
+ while ( x )
+ y;
+ z;
+
+ We return the indent of "while ( x )". In place of "y;",
+ any arbitrarily complex compound statement can appear.
+ */
+
+ if ( *yyBraceDepth > 0 ) {
+ do {
+ if ( !readLine() )
+ break;
+ } while ( *yyBraceDepth > 0 );
+ }
+
+ LinizerState hookState;
+
+ while ( isContinuationLine() )
+ readLine();
+ hookState = *yyLinizerState;
+
+ readLine();
+ if ( *yyBraceDepth <= 0 ) {
+ do {
+ if ( !matchBracelessControlStatement() )
+ break;
+ hookState = *yyLinizerState;
+ } while ( readLine() );
+ }
+
+ *yyLinizerState = hookState;
+
+ while ( isContinuationLine() )
+ readLine();
+
+ /*
+ Never trust lines containing only '{' or '}', as some
+ people (Richard M. Stallman) format them weirdly.
+ */
+ if ( yyLine->trimmed().length() > 1 )
+ return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize;
+ }
+
+ if ( !readLine() )
+ return -*yyBraceDepth * ppIndentSize;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of program.
+ Unless null, typedIn stores the character of yyProgram that
+ triggered reindentation.
+
+ This function works better if typedIn is set properly; it is
+ slightly more conservative if typedIn is completely wild, and
+ slighly more liberal if typedIn is always null. The user might be
+ annoyed by the liberal behavior.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentForBottomLine(const Iterator &current,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedIn )
+{
+ if ( programBegin == programEnd )
+ return 0;
+
+ yyProgramBegin = programBegin;
+ yyProgramEnd = programEnd;
+
+ startLinizer();
+
+ Iterator lastIt = current;
+
+ QString bottomLine = *lastIt;
+ QChar firstCh = firstNonWhiteSpace( bottomLine );
+ int indent;
+
+ const QChar hash = QLatin1Char('#');
+ const QChar closingBrace = QLatin1Char('}');
+ const QChar colon = QLatin1Char(':');
+
+ if ( bottomLineStartsInCComment() ) {
+ /*
+ The bottom line starts in a C-style comment. Indent it
+ smartly, unless the user has already played around with it,
+ in which case it's better to leave her stuff alone.
+ */
+ if ( isOnlyWhiteSpace(bottomLine) ) {
+ indent = indentWhenBottomLineStartsInCComment();
+ } else {
+ indent = indentOfLine( bottomLine );
+ }
+ } else if ( okay(typedIn, hash) && firstCh == hash ) {
+ /*
+ Preprocessor directives go flush left.
+ */
+ indent = 0;
+ } else {
+ if ( isUnfinishedLine() ) {
+ indent = indentForContinuationLine();
+ } else {
+ indent = indentForStandaloneLine();
+ }
+
+ if ( okay(typedIn, closingBrace) && firstCh == closingBrace ) {
+ /*
+ A closing brace is one level more to the left than the
+ code it follows.
+ */
+ indent -= ppIndentSize;
+ } else if ( okay(typedIn, colon) ) {
+ if ( m_constants.m_caseLabel.exactMatch(bottomLine) ) {
+ /*
+ Move a case label (or the ':' in front of a
+ constructor initialization list) one level to the
+ left, but only if the user did not play around with
+ it yet. Some users have exotic tastes in the
+ matter, and most users probably are not patient
+ enough to wait for the final ':' to format their
+ code properly.
+
+ We don't attempt the same for goto labels, as the
+ user is probably the middle of "foo::bar". (Who
+ uses goto, anyway?)
+ */
+ if ( indentOfLine(bottomLine) <= indent )
+ indent -= ppIndentSize;
+ else
+ indent = indentOfLine( bottomLine );
+ }
+ }
+ }
+ return qMax( 0, indent );
+}
+
+} // namespace SharedTools
+
+#undef YY_SAVE
+#undef YY_RESTORE
+#endif
diff --git a/shared/indenter/test/main.cpp b/shared/indenter/test/main.cpp
new file mode 100644
index 0000000000..3e7f114741
--- /dev/null
+++ b/shared/indenter/test/main.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "indenter.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+#include <QtCore/QFileInfo>
+
+#include <stdio.h>
+
+typedef SharedTools::Indenter<QStringList::const_iterator> Indenter ;
+
+static QString fileContents( const QString& fileName )
+{
+ QFile f( fileName );
+ if ( !f.open(QIODevice::ReadOnly) ) {
+ const QString msg = QString(QLatin1String("error: Cannot open file '%1' for reading: %2")).
+ arg(fileName).arg(f.errorString());
+ qWarning(msg.toLatin1().constData());
+ return QString::null;
+ }
+
+ const QString contents = QString::fromUtf8(f.readAll());
+ f.close();
+ if ( contents.isEmpty() ) {
+ const QString msg = QString(QLatin1String("error: File '%1' is empty")).arg(fileName);
+ qWarning(msg.toLatin1().constData());
+ return QString::null;
+ }
+ return contents;
+}
+
+static void printUsage(char *a0)
+{
+ const QFileInfo fi(QString::fromUtf8(a0));
+ const QString usage = QString(QLatin1String("Usage: %1 [-i indent-size] [-t tab-size] file.cpp")).
+ arg(fi.fileName());
+ qWarning(usage.toUtf8().constData());
+}
+
+static int integerOptionArgument(char ** &aptr, char **end)
+{
+ if (++aptr == end)
+ return -1;
+ const QString arg = QString::fromUtf8(*aptr);
+ bool ok;
+ const int rc = arg.toInt (&ok);
+ if (!ok)
+ return -1;
+ return rc;
+}
+
+static QStringList parseCommandLine(char **begin, char **end)
+{
+ char **aptr = begin;
+ if (++aptr == end)
+ return QStringList();
+
+ QStringList fileNames;
+ for ( ; aptr != end; ++aptr) {
+ const char *arg = *aptr;
+ if (arg[0] == '-') {
+ switch (arg[1]) {
+ case 't': {
+ const int tabSize = integerOptionArgument(aptr, end);
+ if ( tabSize == -1)
+ return QStringList();
+ Indenter::instance().setTabSize(tabSize);
+ }
+ break;
+ case 'i': {
+ const int indentSize = integerOptionArgument(aptr, end);
+ if (indentSize == -1)
+ return QStringList();
+ Indenter::instance().setIndentSize(indentSize);
+ }
+ break;
+ default:
+ return QStringList();
+ }
+ } else {
+ fileNames.push_back(QString::fromUtf8(arg));
+ }
+ }
+ return fileNames;
+}
+
+int format(const QString &fileName)
+{
+ const QString code = fileContents(fileName );
+ if ( code == QString::null)
+ return 1;
+
+ QStringList program = code.split( QLatin1Char('\n'), QString::KeepEmptyParts);
+ while (!program.isEmpty()) {
+ if (!program.back().trimmed().isEmpty())
+ break;
+ program.pop_back();
+ }
+
+ QStringList p;
+ QString out;
+
+ const QChar colon = QLatin1Char(':');
+ const QChar blank = QLatin1Char(' ');
+ const QChar newLine = QLatin1Char('\n');
+
+ QStringList::const_iterator cend = program.constEnd();
+ for (QStringList::const_iterator it = program.constBegin(); it != cend; ++it) {
+ p.push_back(*it);
+ QString &line = p.back();
+
+ QChar typedIn = Indenter::instance().firstNonWhiteSpace(line);
+ if ( p.last().endsWith( colon ) )
+ typedIn = colon;
+
+ const int indent = Indenter::instance().indentForBottomLine( p.constBegin(), p.constEnd(), typedIn );
+
+ const QString trimmed = line.trimmed();
+ // Indent the line in the list so that the formatter code sees the indented line.
+ if ( !trimmed.isEmpty() ) {
+ line = QString(indent, blank);
+ line += trimmed;
+ }
+ out += line;
+ out += newLine ;
+ }
+
+ while ( out.endsWith(newLine) )
+ out.truncate( out.length() - 1 );
+
+ fputs(out.toUtf8().constData(), stdout);
+ return 0;
+}
+
+int main( int argc, char **argv )
+{
+ const QStringList fileNames = parseCommandLine(argv, argv + argc);
+ if (fileNames.empty()) {
+ printUsage(argv[0]);
+ return 1;
+ }
+
+ foreach(QString fileName, fileNames)
+ if (const int rc = format(fileName))
+ return rc;
+
+ return 0;
+}
diff --git a/shared/indenter/test/test.pro b/shared/indenter/test/test.pro
new file mode 100644
index 0000000000..9600b7abeb
--- /dev/null
+++ b/shared/indenter/test/test.pro
@@ -0,0 +1,10 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Mon Apr 16 13:02:01 2007
+######################################################################
+
+TEMPLATE = app
+TARGET=indenter
+CONFIG += console
+
+include(../indenter.pri)
+SOURCES += main.cpp
diff --git a/shared/namespace_global.h b/shared/namespace_global.h
new file mode 100644
index 0000000000..ff097a9103
--- /dev/null
+++ b/shared/namespace_global.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef NAMESPACE_GLOBAL_H
+#define NAMESPACE_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if QT_VERSION < 0x040400
+# define QT_ADD_NAMESPACE(name) ::name
+# define QT_USE_NAMESPACE
+# define QT_BEGIN_NAMESPACE
+# define QT_END_NAMESPACE
+# define QT_BEGIN_INCLUDE_NAMESPACE
+# define QT_END_INCLUDE_NAMESPACE
+# define QT_BEGIN_MOC_NAMESPACE
+# define QT_END_MOC_NAMESPACE
+# define QT_FORWARD_DECLARE_CLASS(name) class name;
+# define QT_MANGLE_NAMESPACE(name) name
+#endif
+
+#endif
diff --git a/shared/proparser/abstractproitemvisitor.h b/shared/proparser/abstractproitemvisitor.h
new file mode 100644
index 0000000000..adc9a2fdfc
--- /dev/null
+++ b/shared/proparser/abstractproitemvisitor.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ABSTRACTPROITEMVISITOR
+#define ABSTRACTPROITEMVISITOR
+
+#include "proitems.h"
+
+QT_BEGIN_NAMESPACE
+
+struct AbstractProItemVisitor {
+ virtual ~AbstractProItemVisitor() {}
+ virtual bool visitBeginProBlock(ProBlock *block) = 0;
+ virtual bool visitEndProBlock(ProBlock *block) = 0;
+
+ virtual bool visitBeginProVariable(ProVariable *variable) = 0;
+ virtual bool visitEndProVariable(ProVariable *variable) = 0;
+
+ virtual bool visitBeginProFile(ProFile *value) = 0;
+ virtual bool visitEndProFile(ProFile *value) = 0;
+
+ virtual bool visitProValue(ProValue *value) = 0;
+ virtual bool visitProFunction(ProFunction *function) = 0;
+ virtual bool visitProOperator(ProOperator *function) = 0;
+ virtual bool visitProCondition(ProCondition *function) = 0;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // ABSTRACTPROITEMVISITOR
+
diff --git a/shared/proparser/images/append.png b/shared/proparser/images/append.png
new file mode 100644
index 0000000000..5ae826e56c
--- /dev/null
+++ b/shared/proparser/images/append.png
Binary files differ
diff --git a/shared/proparser/images/other.png b/shared/proparser/images/other.png
new file mode 100644
index 0000000000..044ce1ebb8
--- /dev/null
+++ b/shared/proparser/images/other.png
Binary files differ
diff --git a/shared/proparser/images/profile.png b/shared/proparser/images/profile.png
new file mode 100644
index 0000000000..4a24ce3c2f
--- /dev/null
+++ b/shared/proparser/images/profile.png
Binary files differ
diff --git a/shared/proparser/images/remove.png b/shared/proparser/images/remove.png
new file mode 100644
index 0000000000..039f05a005
--- /dev/null
+++ b/shared/proparser/images/remove.png
Binary files differ
diff --git a/shared/proparser/images/scope.png b/shared/proparser/images/scope.png
new file mode 100644
index 0000000000..eefcb59954
--- /dev/null
+++ b/shared/proparser/images/scope.png
Binary files differ
diff --git a/shared/proparser/images/set.png b/shared/proparser/images/set.png
new file mode 100644
index 0000000000..69a8fe0523
--- /dev/null
+++ b/shared/proparser/images/set.png
Binary files differ
diff --git a/shared/proparser/images/value.png b/shared/proparser/images/value.png
new file mode 100644
index 0000000000..433cd527f4
--- /dev/null
+++ b/shared/proparser/images/value.png
Binary files differ
diff --git a/shared/proparser/procommandmanager.cpp b/shared/proparser/procommandmanager.cpp
new file mode 100644
index 0000000000..f5f40f7f5f
--- /dev/null
+++ b/shared/proparser/procommandmanager.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "procommandmanager.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+ProCommandGroup::ProCommandGroup(const QString &name)
+ : m_name(name) { }
+
+ProCommandGroup::~ProCommandGroup()
+{
+ qDeleteAll(m_commands);
+}
+
+void ProCommandGroup::appendCommand(ProCommand *cmd)
+{
+ m_commands.append(cmd);
+}
+
+void ProCommandGroup::undo()
+{
+ for(int i=m_commands.count(); i>0; --i) {
+ m_commands[i-1]->undo();
+ }
+}
+
+void ProCommandGroup::redo()
+{
+ for(int i=0; i<m_commands.count(); ++i) {
+ m_commands[i]->redo();
+ }
+}
+
+ProCommandManager::ProCommandManager(QObject *parent)
+ : QObject(parent)
+{
+ m_savepoint = 0;
+ m_pos = 0;
+ m_group = 0;
+}
+
+ProCommandManager::~ProCommandManager()
+{
+ qDeleteAll(m_groups);
+}
+
+void ProCommandManager::beginGroup(const QString &name)
+{
+ Q_ASSERT(!m_group);
+
+ if (m_pos != m_groups.count()) {
+ int removecount = m_groups.count() - m_pos;
+ for(int i=0; i<removecount; ++i) {
+ delete m_groups.takeLast();
+ }
+ m_pos = m_groups.count();
+ }
+
+ m_group = new ProCommandGroup(name);
+}
+
+bool ProCommandManager::hasGroup() const
+{
+ return (m_group != 0);
+}
+
+void ProCommandManager::endGroup()
+{
+ Q_ASSERT(m_group);
+
+ m_groups.append(m_group);
+ m_pos = m_groups.count();
+ m_group = 0;
+
+ emit modified();
+}
+
+bool ProCommandManager::command(ProCommand *cmd)
+{
+ Q_ASSERT(m_group);
+
+ if (cmd->redo()) {
+ m_group->appendCommand(cmd);
+ return true;
+ }
+
+ return false;
+}
+
+void ProCommandManager::undo()
+{
+ if (canUndo()) {
+ --m_pos;
+ m_groups[m_pos]->undo();
+ }
+
+ emit modified();
+}
+
+void ProCommandManager::redo()
+{
+ if (canRedo()) {
+ m_groups[m_pos]->redo();
+ ++m_pos;
+ }
+
+ emit modified();
+}
+
+bool ProCommandManager::isDirty() const
+{
+ if (m_groups.isEmpty())
+ return false;
+
+ if (m_pos != 0 && m_groups.at(m_pos - 1) == m_savepoint)
+ return false;
+
+ return true;
+}
+
+void ProCommandManager::notifySave()
+{
+ if (m_pos > 0)
+ m_savepoint = m_groups.at(m_pos - 1);
+}
+
+
+bool ProCommandManager::canUndo() const
+{
+ return (!m_groups.isEmpty() && m_pos > 0);
+}
+
+bool ProCommandManager::canRedo() const
+{
+ return (m_groups.count() > m_pos);
+}
diff --git a/shared/proparser/procommandmanager.h b/shared/proparser/procommandmanager.h
new file mode 100644
index 0000000000..717bf1fcef
--- /dev/null
+++ b/shared/proparser/procommandmanager.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROCOMMANDMANAGER_H
+#define PROCOMMANDMANAGER_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QModelIndex>
+
+QT_FORWARD_DECLARE_CLASS(ProItem)
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProCommand {
+public:
+ virtual ~ProCommand() {}
+ virtual bool redo() = 0;
+ virtual void undo() = 0;
+};
+
+class ProCommandGroup {
+public:
+ ProCommandGroup(const QString &name);
+ ~ProCommandGroup();
+
+ void appendCommand(ProCommand *cmd);
+
+ void undo();
+ void redo();
+
+private:
+ QString m_name;
+ QList<ProCommand *> m_commands;
+};
+
+class ProCommandManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ ProCommandManager(QObject *parent);
+ ~ProCommandManager();
+
+ void beginGroup(const QString &name);
+ void endGroup();
+
+ // excutes the Command and adds it to the open group
+ bool command(ProCommand *cmd);
+
+ bool hasGroup() const;
+ bool isDirty() const;
+
+ void notifySave();
+
+ bool canUndo() const;
+ bool canRedo() const;
+
+public slots:
+ void undo();
+ void redo();
+
+signals:
+ void modified();
+
+private:
+ ProCommandGroup *m_group;
+ QList<ProCommandGroup *> m_groups;
+
+ int m_pos;
+ ProCommandGroup *m_savepoint;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //PROCOMMANDMANAGER_H
diff --git a/shared/proparser/proeditor.cpp b/shared/proparser/proeditor.cpp
new file mode 100644
index 0000000000..e22ba28e3f
--- /dev/null
+++ b/shared/proparser/proeditor.cpp
@@ -0,0 +1,387 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QMenu>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+
+#include "proeditor.h"
+#include "proitems.h"
+#include "proeditormodel.h"
+#include "procommandmanager.h"
+#include "proxml.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+ProEditor::ProEditor(QWidget *parent, bool shortcuts)
+ : QWidget(parent)
+{
+ m_shortcuts = shortcuts;
+ m_advanced = false;
+ setupUi(this);
+
+ m_setFocusToListView = true;
+ m_blockSelectionSignal = false;
+ m_cutAction = new QAction(tr("Cut"), this);
+ m_copyAction = new QAction(tr("Copy"), this);
+ m_pasteAction = new QAction(tr("Paste"), this);
+}
+
+ProEditor::~ProEditor()
+{
+
+}
+
+void ProEditor::initialize(ProEditorModel *model, ProItemInfoManager *infomanager)
+{
+ m_model = model;
+ m_infomanager = infomanager;
+ initialize();
+}
+
+ProScopeFilter *ProEditor::filterModel() const
+{
+ return m_filter;
+}
+
+void ProEditor::selectScope(const QModelIndex &scope)
+{
+ m_setFocusToListView = false;
+ QModelIndex parent = m_filter->mapToSource(scope);
+ m_editListView->setRootIndex(parent);
+ m_editListView->setCurrentIndex(m_model->index(0,0,parent));
+ m_setFocusToListView = true;
+}
+
+void ProEditor::initialize()
+{
+ m_model->setInfoManager(m_infomanager);
+ m_filter = new ProScopeFilter(this);
+ m_filter->setSourceModel(m_model);
+
+ m_contextMenu = new QMenu(this);
+
+ if (m_shortcuts) {
+ m_cutAction->setShortcut(QKeySequence(tr("Ctrl+X")));
+ m_copyAction->setShortcut(QKeySequence(tr("Ctrl+C")));
+ m_pasteAction->setShortcut(QKeySequence(tr("Ctrl+V")));
+ m_editListView->installEventFilter(this);
+ }
+
+ m_contextMenu->addAction(m_cutAction);
+ m_contextMenu->addAction(m_copyAction);
+ m_contextMenu->addAction(m_pasteAction);
+
+ QMenu *addMenu = new QMenu(m_addToolButton);
+ m_addVariable = addMenu->addAction(tr("Add Variable"), this, SLOT(addVariable()));
+ m_addScope = addMenu->addAction(tr("Add Scope"), this, SLOT(addScope()));
+ m_addBlock = addMenu->addAction(tr("Add Block"), this, SLOT(addBlock()));
+ m_addToolButton->setMenu(addMenu);
+ m_addToolButton->setPopupMode(QToolButton::InstantPopup);
+
+ m_editListView->setModel(m_model);
+ m_editListView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(m_editListView, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(showContextMenu(const QPoint &)));
+
+ connect(m_editListView->selectionModel(),
+ SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(updateState()));
+
+ connect(m_moveUpToolButton, SIGNAL(clicked()),
+ this, SLOT(moveUp()));
+ connect(m_moveDownToolButton, SIGNAL(clicked()),
+ this, SLOT(moveDown()));
+ connect(m_removeToolButton, SIGNAL(clicked()),
+ this, SLOT(remove()));
+ connect(m_cutAction, SIGNAL(triggered()),
+ this, SLOT(cut()));
+ connect(m_copyAction, SIGNAL(triggered()),
+ this, SLOT(copy()));
+ connect(m_pasteAction, SIGNAL(triggered()),
+ this, SLOT(paste()));
+
+ updatePasteAction();
+}
+
+bool ProEditor::eventFilter(QObject *, QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *k = static_cast<QKeyEvent*>(event);
+ if (k->modifiers() == Qt::ControlModifier) {
+ switch(k->key()) {
+ case Qt::Key_X:
+ cut(); return true;
+ case Qt::Key_C:
+ copy(); return true;
+ case Qt::Key_V:
+ paste(); return true;
+ }
+ }
+ } else if (event->type() == QEvent::FocusIn) {
+ updateActions(true);
+ } else if (event->type() == QEvent::FocusOut) {
+ updateActions(false);
+ }
+
+ return false;
+}
+
+void ProEditor::showContextMenu(const QPoint &pos)
+{
+ updatePasteAction();
+ m_contextMenu->popup(m_editListView->viewport()->mapToGlobal(pos));
+}
+
+void ProEditor::updatePasteAction()
+{
+ bool pasteEnabled = false;
+
+ const QMimeData *data = QApplication::clipboard()->mimeData();
+ if (data) {
+ if (data->hasFormat(QLatin1String("application/x-problock"))) {
+ pasteEnabled = true;
+ }
+ }
+
+ m_pasteAction->setEnabled(pasteEnabled);
+}
+
+void ProEditor::updateActions(bool focus)
+{
+ bool copyEnabled = false;
+
+ if (focus)
+ copyEnabled = m_editListView->currentIndex().isValid();
+
+ m_cutAction->setEnabled(copyEnabled);
+ m_copyAction->setEnabled(copyEnabled);
+}
+
+void ProEditor::updateState()
+{
+ bool addEnabled = false;
+ bool removeEnabled = false;
+ bool upEnabled = false;
+ bool downEnabled = false;
+
+ QModelIndex parent = m_editListView->rootIndex();
+ ProBlock *scope = m_model->proBlock(parent);
+
+ if (scope) {
+ addEnabled = true;
+ QModelIndex index = m_editListView->currentIndex();
+ if (index.isValid()) {
+ removeEnabled = true;
+ int count = m_model->rowCount(parent);
+ int row = index.row();
+ if (row > 0)
+ upEnabled = true;
+ if (row < (count - 1))
+ downEnabled = true;
+ }
+ }
+
+ if (!m_blockSelectionSignal) {
+ emit itemSelected(m_editListView->currentIndex());
+ if (m_setFocusToListView)
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ }
+
+ updateActions(m_editListView->hasFocus());
+
+ m_addToolButton->setEnabled(addEnabled);
+ m_removeToolButton->setEnabled(removeEnabled);
+ m_moveUpToolButton->setEnabled(upEnabled);
+ m_moveDownToolButton->setEnabled(downEnabled);
+}
+
+void ProEditor::moveUp()
+{
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QModelIndex index = m_editListView->currentIndex();
+ QModelIndex parent = index.parent();
+ int row = index.row() - 1;
+
+ m_blockSelectionSignal = true;
+ m_model->moveItem(index, row);
+ m_blockSelectionSignal = false;
+
+ index = m_model->index(row, 0, parent);
+ m_editListView->setCurrentIndex(index);
+}
+
+void ProEditor::moveDown()
+{
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QModelIndex index = m_editListView->currentIndex();
+ QModelIndex parent = index.parent();
+ int row = index.row() + 1;
+
+ m_blockSelectionSignal = true;
+ m_model->moveItem(index, row);
+ m_blockSelectionSignal = false;
+
+ index = m_model->index(row, 0, parent);
+ m_editListView->setCurrentIndex(index);
+}
+
+void ProEditor::remove()
+{
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ m_model->removeItem(m_editListView->currentIndex());
+ updateState();
+}
+
+void ProEditor::cut()
+{
+ QModelIndex index = m_editListView->currentIndex();
+ if (!index.isValid())
+ return;
+
+ if (ProItem *item = m_model->proItem(index)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ m_model->removeItem(index);
+
+ QMimeData *data = new QMimeData();
+ QString xml = ProXmlParser::itemToString(item);
+ if (item->kind() == ProItem::ValueKind)
+ data->setData(QLatin1String("application/x-provalue"), xml.toUtf8());
+ else
+ data->setData(QLatin1String("application/x-problock"), xml.toUtf8());
+ QApplication::clipboard()->setMimeData(data);
+ }
+}
+
+void ProEditor::copy()
+{
+ QModelIndex index = m_editListView->currentIndex();
+ if (!index.isValid())
+ return;
+
+ if (ProItem *item = m_model->proItem(index)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QMimeData *data = new QMimeData();
+ QString xml = ProXmlParser::itemToString(item);
+ if (item->kind() == ProItem::ValueKind)
+ data->setData(QLatin1String("application/x-provalue"), xml.toUtf8());
+ else
+ data->setData(QLatin1String("application/x-problock"), xml.toUtf8());
+ QApplication::clipboard()->setMimeData(data);
+ }
+}
+
+void ProEditor::paste()
+{
+ if (const QMimeData *data = QApplication::clipboard()->mimeData()) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QModelIndex parent = m_editListView->rootIndex();
+ ProBlock *block = m_model->proBlock(parent);
+ if (!block)
+ return;
+
+ QString xml;
+ if (data->hasFormat(QLatin1String("application/x-provalue"))) {
+ xml = QString::fromUtf8(data->data(QLatin1String("application/x-provalue")));
+ } else if (data->hasFormat(QLatin1String("application/x-problock"))) {
+ xml = QString::fromUtf8(data->data(QLatin1String("application/x-problock")));
+ }
+
+ if (ProItem *item = ProXmlParser::stringToItem(xml)) {
+ QModelIndex parent = m_editListView->rootIndex();
+ int row = m_model->rowCount(parent);
+ m_model->insertItem(item, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+ }
+}
+
+void ProEditor::addVariable()
+{
+ QModelIndex parent = m_editListView->rootIndex();
+ if (ProBlock *pblock = m_model->proBlock(parent)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ int row = m_model->rowCount(parent);
+
+ QString defid("...");
+ ProVariable::VariableOperator op = ProVariable::SetOperator;
+ QList<ProVariableInfo *> vars = m_infomanager->variables();
+ if (!vars.isEmpty()) {
+ defid = vars.first()->id();
+ op = vars.first()->defaultOperator();
+ }
+
+ ProVariable *var = new ProVariable(defid, pblock);
+ var->setVariableOperator(op);
+
+ m_model->insertItem(var, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+}
+
+void ProEditor::addScope()
+{
+ QModelIndex parent = m_editListView->rootIndex();
+ if (ProBlock *pblock = m_model->proBlock(parent)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ int row = m_model->rowCount(parent);
+ ProBlock *scope = new ProBlock(pblock);
+ scope->setBlockKind(ProBlock::ScopeKind);
+ ProBlock *scopecontents = new ProBlock(scope);
+ scopecontents->setBlockKind(ProBlock::ScopeContentsKind);
+
+ QString defid("...");
+ QList<ProScopeInfo *> vars = m_infomanager->scopes();
+ if (!vars.isEmpty())
+ defid = vars.first()->id();
+
+ scope->setItems(QList<ProItem *>() << new ProCondition(defid) << scopecontents);
+ m_model->insertItem(scope, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+}
+
+void ProEditor::addBlock()
+{
+ QModelIndex parent = m_editListView->rootIndex();
+ if (ProBlock *pblock = m_model->proBlock(parent)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ int row = m_model->rowCount(parent);
+ ProBlock *block = new ProBlock(pblock);
+ block->setBlockKind(ProBlock::NormalKind);
+ block->setItems(QList<ProItem *>() << new ProFunction("..."));
+ m_model->insertItem(block, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+}
+
diff --git a/shared/proparser/proeditor.h b/shared/proparser/proeditor.h
new file mode 100644
index 0000000000..450fe542bf
--- /dev/null
+++ b/shared/proparser/proeditor.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROEDITOR_H
+#define PROEDITOR_H
+
+#include "namespace_global.h"
+
+#include "ui_proeditor.h"
+
+#include "proiteminfo.h"
+
+#include <QtCore/QList>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QMenu;
+class QAction;
+class ProBlock;
+class ProVariable;
+class ProFile;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProEditorModel;
+class ProScopeFilter;
+
+class ProEditor : public QWidget,
+ protected Ui::ProEditor
+{
+ Q_OBJECT
+
+public:
+ ProEditor(QWidget *parent, bool shortcuts = true);
+ ~ProEditor();
+
+ virtual void initialize(ProEditorModel *model, ProItemInfoManager *infomanager);
+
+ ProScopeFilter *filterModel() const;
+
+public slots:
+ void selectScope(const QModelIndex &scope);
+
+signals:
+ void itemSelected(const QModelIndex &index);
+
+protected slots:
+ void showContextMenu(const QPoint &pos);
+ void updatePasteAction();
+ void updateState();
+
+ void moveUp();
+ void moveDown();
+ void remove();
+ void cut();
+ void copy();
+ void paste();
+
+ void addVariable();
+ void addScope();
+ void addBlock();
+
+protected:
+ void updateActions(bool focus);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private:
+ void initialize();
+
+protected:
+ ProEditorModel *m_model;
+ QAction *m_cutAction;
+ QAction *m_copyAction;
+ QAction *m_pasteAction;
+
+private:
+ QMenu *m_contextMenu;
+
+ QAction *m_addVariable;
+ QAction *m_addScope;
+ QAction *m_addBlock;
+
+ ProScopeFilter *m_filter;
+ ProItemInfoManager *m_infomanager;
+
+ bool m_blockSelectionSignal;
+
+ // used because of some strange behavior when integrated into eclipse
+ bool m_setFocusToListView;
+ bool m_shortcuts;
+ bool m_advanced;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //PROEDITOR_H
diff --git a/shared/proparser/proeditor.ui b/shared/proparser/proeditor.ui
new file mode 100644
index 0000000000..b4daca4150
--- /dev/null
+++ b/shared/proparser/proeditor.ui
@@ -0,0 +1,143 @@
+<ui version="4.0" >
+ <class>Qt4ProjectManager::Internal::ProEditor</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::ProEditor" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>621</width>
+ <height>557</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListView" name="m_editListView" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="dragEnabled" >
+ <bool>true</bool>
+ </property>
+ <property name="uniformItemSizes" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="m_addToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_removeToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_moveUpToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_moveDownToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Down</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/shared/proparser/proeditormodel.cpp b/shared/proparser/proeditormodel.cpp
new file mode 100644
index 0000000000..1e2097739e
--- /dev/null
+++ b/shared/proparser/proeditormodel.cpp
@@ -0,0 +1,983 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QStringList>
+#include <QtCore/QMimeData>
+#include <QtCore/QDebug>
+#include <QtGui/QIcon>
+
+#include "proxml.h"
+#include "proitems.h"
+#include "proeditormodel.h"
+#include "procommandmanager.h"
+#include "proiteminfo.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProAddCommand : public ProCommand {
+public:
+ ProAddCommand(ProEditorModel *model, ProItem *item, int row, const QModelIndex &parent, bool dodelete = true)
+ : m_model(model), m_item(item), m_row(row), m_parent(parent), m_dodelete(dodelete), m_delete(false) { }
+
+ ~ProAddCommand() {
+ if (m_delete)
+ delete m_item;
+ }
+
+ bool redo() {
+ m_delete = false;
+ return m_model->insertModelItem(m_item, m_row, m_parent);
+ }
+
+ void undo() {
+ m_delete = m_dodelete;
+ m_model->removeModelItem(m_model->index(m_row, 0, m_parent));
+ }
+
+private:
+ ProEditorModel *m_model;
+ ProItem *m_item;
+ int m_row;
+ const QModelIndex m_parent;
+ bool m_dodelete;
+ bool m_delete;
+};
+
+class ProRemoveCommand : public ProCommand {
+public:
+ ProRemoveCommand(ProEditorModel *model, const QModelIndex &index, bool dodelete = true)
+ : m_model(model), m_index(index), m_dodelete(dodelete), m_delete(dodelete) { }
+
+ ~ProRemoveCommand() {
+ if (m_delete)
+ delete m_model->proItem(m_index);
+ }
+
+ bool redo() {
+ m_delete = m_dodelete;
+ return m_model->removeModelItem(m_index);
+ }
+
+ void undo() {
+ m_delete = false;
+ m_model->insertModelItem(m_model->proItem(m_index),
+ m_index.row(), m_index.parent());
+ }
+
+private:
+ ProEditorModel *m_model;
+ const QModelIndex m_index;
+ bool m_dodelete;
+ bool m_delete;
+};
+
+class ChangeProVariableIdCommand : public ProCommand {
+public:
+ ChangeProVariableIdCommand(ProEditorModel *model, ProVariable *variable, const QString &newId)
+ : m_newId(newId), m_model(model), m_variable(variable)
+ {
+ m_oldId = m_variable->variable();
+ }
+
+ ~ChangeProVariableIdCommand() { }
+
+ bool redo() {
+ m_variable->setVariable(m_newId);
+ return true;
+ }
+
+ void undo() {
+ m_variable->setVariable(m_oldId);
+ }
+
+private:
+ QString m_oldId;
+ QString m_newId;
+
+ ProEditorModel *m_model;
+ ProVariable *m_variable;
+};
+
+class ChangeProVariableOpCommand : public ProCommand {
+public:
+ ChangeProVariableOpCommand(ProEditorModel *model, ProVariable *variable, ProVariable::VariableOperator newOp)
+ : m_newOp(newOp), m_model(model), m_variable(variable)
+ {
+ m_oldOp = m_variable->variableOperator();
+ }
+
+ ~ChangeProVariableOpCommand() { }
+
+ bool redo() {
+ m_variable->setVariableOperator(m_newOp);
+ return true;
+ }
+
+ void undo() {
+ m_variable->setVariableOperator(m_oldOp);
+ }
+
+private:
+ ProVariable::VariableOperator m_oldOp;
+ ProVariable::VariableOperator m_newOp;
+
+ ProEditorModel *m_model;
+ ProVariable *m_variable;
+};
+
+class ChangeProScopeCommand : public ProCommand {
+public:
+ ChangeProScopeCommand(ProEditorModel *model, ProBlock *scope, const QString &newExp)
+ : m_newExp(newExp), m_model(model), m_scope(scope) {
+ m_oldExp = m_model->expressionToString(m_scope);
+ }
+
+ ~ChangeProScopeCommand() { }
+
+ bool redo() {
+ setScopeCondition(m_newExp);
+ return true;
+ }
+
+ void undo() {
+ setScopeCondition(m_oldExp);
+ }
+
+private:
+ void setScopeCondition(const QString &exp) {
+ ProItem *contents = m_model->scopeContents(m_scope);
+ QList<ProItem *> items = m_scope->items();
+ for (int i=items.count() - 1; i>=0; --i) {
+ if (items.at(i) != contents)
+ delete items[i];
+ }
+
+ items = m_model->stringToExpression(exp);
+ items << contents;
+ m_scope->setItems(items);
+ }
+
+ QString m_oldExp;
+ QString m_newExp;
+
+ ProEditorModel *m_model;
+ ProBlock *m_scope;
+};
+
+class ChangeProAdvancedCommand : public ProCommand {
+public:
+ ChangeProAdvancedCommand(ProEditorModel *model, ProBlock *block, const QString &newExp)
+ : m_newExp(newExp), m_model(model), m_block(block) {
+ m_oldExp = m_model->expressionToString(m_block);
+ }
+
+ ~ChangeProAdvancedCommand() { }
+
+ bool redo() {
+ setExpression(m_newExp);
+ return true;
+ }
+
+ void undo() {
+ setExpression(m_oldExp);
+ }
+
+private:
+ void setExpression(const QString &exp) {
+ qDeleteAll(m_block->items());
+ m_block->setItems(m_model->stringToExpression(exp));
+ }
+
+ QString m_oldExp;
+ QString m_newExp;
+
+ ProEditorModel *m_model;
+ ProBlock *m_block;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+ProEditorModel::ProEditorModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+ m_infomanager = 0;
+ m_cmdmanager = new ProCommandManager(this);
+}
+
+ProEditorModel::~ProEditorModel()
+{
+
+}
+
+void ProEditorModel::setInfoManager(ProItemInfoManager *infomanager)
+{
+ m_infomanager = infomanager;
+ reset();
+}
+
+ProItemInfoManager *ProEditorModel::infoManager() const
+{
+ return m_infomanager;
+}
+
+ProCommandManager *ProEditorModel::cmdManager() const
+{
+ return m_cmdmanager;
+}
+
+void ProEditorModel::setProFiles(QList<ProFile*> proFiles)
+{
+ m_changed.clear();
+ m_proFiles = proFiles;
+ reset();
+}
+
+QList<ProFile*> ProEditorModel::proFiles() const
+{
+ return m_proFiles;
+}
+
+QList<QModelIndex> ProEditorModel::findVariables(const QStringList &varnames, const QModelIndex &parent) const
+{
+ QList<QModelIndex> result;
+
+ if (varnames.isEmpty())
+ return result;
+
+ if (ProVariable *var = proVariable(parent)) {
+ if (varnames.contains(var->variable()))
+ result << parent;
+ return result;
+ }
+
+ for (int i=0; i<rowCount(parent); ++i) {
+ result += findVariables(varnames, index(i, 0, parent));
+ }
+
+ return result;
+}
+
+QList<QModelIndex> ProEditorModel::findBlocks(const QModelIndex &parent) const
+{
+ QList<QModelIndex> result;
+
+ if (proBlock(parent)) {
+ result << parent;
+ return result;
+ }
+
+ for (int i=0; i<rowCount(parent); ++i) {
+ result += findBlocks(index(i, 0, parent));
+ }
+
+ return result;
+}
+
+QString ProEditorModel::blockName(ProBlock *block) const
+{
+ // variables has a name
+ if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *v = static_cast<ProVariable*>(block);
+ if (m_infomanager) {
+ if (ProVariableInfo *info = m_infomanager->variable(v->variable()))
+ return info->name();
+ }
+ return v->variable();
+ }
+
+ return expressionToString(block, true);
+}
+
+QModelIndex ProEditorModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0 || (column != 0))
+ return QModelIndex();
+
+ if (parent.isValid()) {
+ ProItem *item = proItem(parent);
+ if (item->kind() != ProItem::BlockKind)
+ return QModelIndex();
+
+ ProBlock *block = static_cast<ProBlock*>(item);
+ if (block->blockKind() & ProBlock::VariableKind
+ || block->blockKind() & ProBlock::ProFileKind) {
+ const QList<ProItem*> items = block->items();
+ if (row >= items.count())
+ return QModelIndex();
+ ProItem *data = items.at(row);
+ return createIndex(row, 0, (void*)data);
+ } else if (ProBlock *scope = scopeContents(block)) {
+ const QList<ProItem*> items = scope->items();
+ if (row >= items.count())
+ return QModelIndex();
+ ProItem *data = items.at(row);
+ return createIndex(row, 0, (void*)data);
+ }
+
+ return QModelIndex();
+ }
+
+ if (row >= m_proFiles.count())
+ return QModelIndex();
+ ProItem *data = m_proFiles.at(row);
+ return createIndex(row, 0, (void*)data);
+}
+
+QModelIndex ProEditorModel::parent(const QModelIndex &index) const
+{
+ ProBlock *p = 0;
+ ProItem *item = proItem(index);
+ if (!item) {
+ return QModelIndex();
+ }
+
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() & ProBlock::ProFileKind) {
+ return QModelIndex();
+ }
+ p = block->parent();
+ } else if (item->kind() == ProItem::ValueKind) {
+ p = static_cast<ProValue *>(item)->variable();
+ }
+
+ if (p->blockKind() & ProBlock::ScopeContentsKind)
+ p = p->parent();
+
+ int row = -1;
+ if (p->blockKind() & ProBlock::ProFileKind) {
+ row = m_proFiles.indexOf(static_cast<ProFile*>(p));
+ } else {
+ ProBlock *pp = p->parent();
+ row = pp->items().indexOf(p);
+ }
+
+ if (row == -1) {
+ return QModelIndex();
+ }
+
+ ProItem *data = p;
+ return createIndex(row, 0, (void*)data);
+}
+
+int ProEditorModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ ProItem *s = proItem(parent);
+ if (!s)
+ return 0;
+
+ if (s->kind() != ProItem::BlockKind)
+ return 0;
+
+ ProBlock *block = static_cast<ProBlock*>(s);
+
+ if (block->blockKind() & ProBlock::VariableKind
+ || block->blockKind() & ProBlock::ProFileKind) {
+ int rows = block->items().count();
+ return rows;
+ }
+
+ if (ProBlock *scope = scopeContents(block)) {
+ int rows = scope->items().count();
+ return rows;
+ }
+
+ return 0;
+ }
+
+ return m_proFiles.count();
+}
+
+int ProEditorModel::columnCount(const QModelIndex &) const
+{
+ return 1;
+}
+
+QVariant ProEditorModel::data(const QModelIndex &index, int role) const
+{
+ ProItem *item = proItem(index);
+ if (!item) {
+ return QVariant();
+ }
+
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock*>(item);
+ if (block->blockKind() & ProBlock::ProFileKind) {
+ ProFile *pf = static_cast<ProFile*>(item);
+ if (role == Qt::DisplayRole) {
+ if (m_proFiles.count() > 1)
+ return QVariant(pf->displayFileName());
+ else
+ return QVariant(tr("<Global Scope>"));
+ } else if (role == Qt::DecorationRole) {
+ return QIcon(":/proparser/images/profile.png");
+ }
+ } else if (block->blockKind() & ProBlock::ScopeKind) {
+ if (role == Qt::DisplayRole)
+ return QVariant(blockName(block));
+ else if (role == Qt::DecorationRole)
+ return QIcon(":/proparser/images/scope.png");
+ else if (role == Qt::EditRole)
+ return QVariant(expressionToString(block));
+ } else if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *var = static_cast<ProVariable *>(block);
+ if (role == Qt::DisplayRole) {
+ return QVariant(blockName(block));
+ } else if (role == Qt::DecorationRole) {
+ if (var->variableOperator() == ProVariable::AddOperator)
+ return QIcon(":/proparser/images/append.png");
+ else if (var->variableOperator() == ProVariable::RemoveOperator)
+ return QIcon(":/proparser/images/remove.png");
+ else
+ return QIcon(":/proparser/images/set.png");
+ } else if (role == Qt::EditRole) {
+ return QVariant(var->variable());
+ }
+ } else {
+ if (role == Qt::DisplayRole)
+ return QVariant(blockName(block));
+ else if (role == Qt::DecorationRole)
+ return QIcon(":/proparser/images/other.png");
+ else if (role == Qt::EditRole)
+ return QVariant(expressionToString(block));
+ }
+ } else if (item->kind() == ProItem::ValueKind) {
+ ProValue *value = static_cast<ProValue*>(item);
+ if (role == Qt::DisplayRole) {
+ ProVariable *var = proVariable(index.parent());
+ if (var && m_infomanager) {
+ if (ProVariableInfo *varinfo = m_infomanager->variable(var->variable())) {
+ if (ProValueInfo *valinfo = varinfo->value(value->value()))
+ return QVariant(valinfo->name());
+ }
+ }
+ return QVariant(value->value());
+ } else if (role == Qt::DecorationRole) {
+ return QIcon(":/proparser/images/value.png");
+ } else if (role == Qt::EditRole) {
+ return QVariant(value->value());
+ }
+ }
+
+ return QVariant();
+}
+
+bool ProEditorModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ static bool block = false;
+
+ if (block)
+ return false;
+
+ if (role != Qt::EditRole)
+ return false;
+
+ ProItem *item = proItem(index);
+ if (!item)
+ return false;
+
+ if (item->kind() == ProItem::ValueKind) {
+ ProValue *val = static_cast<ProValue *>(item);
+ if (val->value() == value.toString())
+ return false;
+
+ block = true;
+ m_cmdmanager->beginGroup(tr("Change Item"));
+ bool result = m_cmdmanager->command(new ProRemoveCommand(this, index));
+ if (result) {
+ ProValue *item = new ProValue(value.toString(), proVariable(index.parent()));
+ result = m_cmdmanager->command(new ProAddCommand(this, item, index.row(), index.parent()));
+ }
+ block = false;
+
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return result;
+ } else if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = proBlock(index);
+ if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *var = static_cast<ProVariable *>(block);
+ if (value.type() == QVariant::Int) {
+ if ((int)var->variableOperator() == value.toInt())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Variable Assignment"));
+ m_cmdmanager->command(new ChangeProVariableOpCommand(this, var,
+ (ProVariable::VariableOperator)value.toInt()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ } else {
+ if (var->variable() == value.toString())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Variable Type"));
+ m_cmdmanager->command(new ChangeProVariableIdCommand(this, var,
+ value.toString()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ }
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ ProBlock *scope = block->parent();
+ QString oldExp = expressionToString(scope);
+ if (oldExp == value.toString())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Scope Condition"));
+ m_cmdmanager->command(new ChangeProScopeCommand(this, scope, value.toString()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ } else if (block->blockKind() & ProBlock::ProFileKind) {
+ return false;
+ } else {
+ QString oldExp = expressionToString(block);
+ if (oldExp == value.toString())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Expression"));
+ m_cmdmanager->command(new ChangeProAdvancedCommand(this, block, value.toString()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Qt::ItemFlags ProEditorModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ Qt::ItemFlags res = QAbstractItemModel::flags(index);
+ ProItem *item = proItem(index);
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock*>(item);
+ if (block->blockKind() == ProBlock::ProFileKind)
+ return res;
+ }
+
+ return res | Qt::ItemIsEditable;
+}
+
+QMimeData *ProEditorModel::mimeData(const QModelIndexList &indexes) const
+{
+ QModelIndex index = indexes.first();
+ ProItem *item = proItem(index);
+ QMimeData *data = new QMimeData();
+ QString xml = ProXmlParser::itemToString(item);
+ data->setText(xml);
+ return data;
+}
+
+bool ProEditorModel::moveItem(const QModelIndex &index, int row)
+{
+ if (!index.isValid())
+ return false;
+
+ int oldrow = index.row();
+ QModelIndex parentIndex = index.parent();
+
+ if (oldrow == row)
+ return false;
+
+ ProItem *item = proItem(index);
+
+ m_cmdmanager->beginGroup(tr("Move Item"));
+ bool result = m_cmdmanager->command(new ProRemoveCommand(this, index, false));
+ if (result)
+ result = m_cmdmanager->command(new ProAddCommand(this, item, row, parentIndex, false));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+
+ return result;
+}
+
+bool ProEditorModel::removeModelItem(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return false;
+
+ int row = index.row();
+ QModelIndex parentIndex = index.parent();
+
+ if (!parentIndex.isValid())
+ return false;
+
+ // get the pro items
+ ProBlock *block = proBlock(parentIndex);
+ if (!block)
+ return false;
+
+ QList<ProItem *> proitems = block->items();
+ proitems.takeAt(row);
+
+ beginRemoveRows(parentIndex, row, row);
+ block->setItems(proitems);
+ endRemoveRows();
+ markProFileModified(index);
+
+ return true;
+}
+
+bool ProEditorModel::removeItem(const QModelIndex &index)
+{
+ bool creategroup = !m_cmdmanager->hasGroup();
+ if (creategroup)
+ m_cmdmanager->beginGroup(tr("Remove Item"));
+
+ bool result = m_cmdmanager->command(new ProRemoveCommand(this, index));
+
+ if (creategroup)
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ return result;
+}
+
+bool ProEditorModel::insertModelItem(ProItem *item, int row, const QModelIndex &parent)
+{
+ if (!parent.isValid())
+ return false;
+
+ ProBlock *block = proBlock(parent);
+ if (!item || !block)
+ return false;
+
+ QList<ProItem *> proitems = block->items();
+ proitems.insert(row, item);
+
+ if ((block->blockKind() & ProBlock::VariableKind)
+ && item->kind() != ProItem::ValueKind)
+ return false;
+
+ if (item->kind() == ProItem::BlockKind) {
+ static_cast<ProBlock*>(item)->setParent(block);
+ } else if (item->kind() == ProItem::ValueKind) {
+ if (!(block->blockKind() & ProBlock::VariableKind))
+ return false;
+ static_cast<ProValue*>(item)->
+ setVariable(static_cast<ProVariable*>(block));
+ } else {
+ return false;
+ }
+
+ beginInsertRows(parent, row, row);
+ block->setItems(proitems);
+ endInsertRows();
+
+ markProFileModified(parent);
+ return true;
+}
+
+bool ProEditorModel::insertItem(ProItem *item, int row, const QModelIndex &parent)
+{
+ bool creategroup = !m_cmdmanager->hasGroup();
+ if (creategroup)
+ m_cmdmanager->beginGroup(tr("Insert Item"));
+
+ bool result = m_cmdmanager->command(new ProAddCommand(this, item, row, parent));
+
+ if (creategroup)
+ m_cmdmanager->endGroup();
+ markProFileModified(parent);
+ return result;
+}
+
+void ProEditorModel::markProFileModified(QModelIndex index)
+{
+ while(index.isValid())
+ {
+ if( proItem(index)->kind() == ProItem::BlockKind)
+ {
+ ProBlock * block = proBlock(index);
+ if(block->blockKind() == ProBlock::ProFileKind)
+ {
+ ProFile * file = static_cast<ProFile *>(block);
+ file->setModified(true);
+ return;
+ }
+ }
+ index = index.parent();
+ }
+}
+
+ProItem *ProEditorModel::proItem(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ return reinterpret_cast<ProItem*>(index.internalPointer());
+}
+
+ProVariable *ProEditorModel::proVariable(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ ProItem *item = proItem(index);
+ if (item->kind() != ProItem::BlockKind)
+ return 0;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() != ProBlock::VariableKind)
+ return 0;
+
+ return static_cast<ProVariable*>(block);
+}
+
+ProBlock *ProEditorModel::proBlock(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ ProItem *item = proItem(index);
+ if (item->kind() != ProItem::BlockKind)
+ return 0;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() & ProBlock::ScopeKind)
+ block = scopeContents(block);
+
+ return block;
+}
+
+QString ProEditorModel::expressionToString(ProBlock *block, bool display) const
+{
+ QString result;
+ QList<ProItem*> items = block->items();
+ for(int i=0; i<items.count(); ++i) {
+ ProItem *item = items.at(i);
+ switch(item->kind()) {
+ case ProItem::FunctionKind: {
+ ProFunction *v = static_cast<ProFunction*>(item);
+ result += v->text();
+ break; }
+ case ProItem::ConditionKind: {
+ ProCondition *v = static_cast<ProCondition*>(item);
+ if (m_infomanager && display) {
+ if (ProScopeInfo *info = m_infomanager->scope(v->text()))
+ result += info->name();
+ else
+ result += v->text();
+ } else {
+ result += v->text();
+ }
+ break; }
+ case ProItem::OperatorKind: {
+ ProOperator *v = static_cast<ProOperator*>(item);
+ if (v->operatorKind() == ProOperator::NotOperator)
+ result += QLatin1Char('!');
+ else
+ result += QLatin1Char('|');
+ break; }
+ case ProItem::ValueKind:
+ case ProItem::BlockKind:
+ break; // ### unhandled
+ }
+ }
+
+ return result;
+}
+
+ProItem *ProEditorModel::createExpressionItem(QString &str) const
+{
+ ProItem *item = 0;
+
+ str = str.trimmed();
+ if (str.endsWith(')'))
+ item = new ProFunction(str);
+ else if (!str.isEmpty())
+ item = new ProCondition(str);
+
+ str.clear();
+ return item;
+}
+
+
+QList<ProItem *> ProEditorModel::stringToExpression(const QString &exp) const
+{
+ QList<ProItem*> result;
+ int p = 0;
+ bool c = false;
+
+ QString tmpstr;
+ for (int i=0; i<exp.length(); ++i) {
+ QChar tmpchar = exp.at(i);
+ if (tmpchar == '(') ++p;
+ else if (tmpchar == ')') --p;
+ else if (tmpchar == '\'' || tmpchar == '\"') c = !c;
+ else if (!c && !p) {
+ if (tmpchar == '|') {
+ if (ProItem *item = createExpressionItem(tmpstr))
+ result << item;
+ result << new ProOperator(ProOperator::OrOperator);
+ continue;
+ } else if (tmpchar == '!') {
+ if (ProItem *item = createExpressionItem(tmpstr))
+ result << item;
+ result << new ProOperator(ProOperator::NotOperator);
+ continue;
+ }
+ }
+ tmpstr += tmpchar;
+ }
+
+ if (ProItem *item = createExpressionItem(tmpstr))
+ result << item;
+
+ return result;
+}
+
+ProBlock *ProEditorModel::scopeContents(ProBlock *block) const
+{
+ if (!(block->blockKind() & ProBlock::ScopeKind))
+ return 0;
+
+ ProItem *item = block->items().last();
+ if (item->kind() != ProItem::BlockKind)
+ return 0;
+ ProBlock *scope = static_cast<ProBlock*>(item);
+ if (!(scope->blockKind() & ProBlock::ScopeContentsKind))
+ return 0;
+ return scope;
+}
+
+ProScopeFilter::ProScopeFilter(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+ m_checkable = ProScopeFilter::None;
+}
+
+void ProScopeFilter::setVariableFilter(const QStringList &vars)
+{
+ m_vars = vars;
+}
+
+void ProScopeFilter::setCheckable(CheckableType ct)
+{
+ m_checkable = ct;
+}
+
+QList<QModelIndex> ProScopeFilter::checkedIndexes() const
+{
+ return m_checkStates.keys(true);
+}
+
+Qt::ItemFlags ProScopeFilter::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags srcflags = sourceModel()->flags(mapToSource(index));
+ srcflags &= ~Qt::ItemIsDragEnabled; //disable drag
+
+ if (m_checkable == ProScopeFilter::None)
+ return srcflags;
+
+ return (srcflags|Qt::ItemIsUserCheckable);
+}
+
+QVariant ProScopeFilter::data(const QModelIndex &index, int role) const
+{
+ bool checkable =
+ m_checkable == ProScopeFilter::Blocks
+ || m_checkable == ProScopeFilter::Variable && sourceVariable(index);
+
+ if (checkable && role == Qt::CheckStateRole) {
+ QModelIndex srcindex = mapToSource(index);
+ if (m_checkStates.value(srcindex, false))
+ return Qt::Checked;
+ else
+ return Qt::Unchecked;
+ }
+
+ return QSortFilterProxyModel::data(index, role);
+}
+
+bool ProScopeFilter::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ // map to source
+ if (m_checkable != ProScopeFilter::None && role == Qt::CheckStateRole) {
+ if ( m_checkable == ProScopeFilter::Blocks || ( m_checkable == ProScopeFilter::Variable && sourceVariable(index))) {
+ QModelIndex srcindex = mapToSource(index);
+ if (value.toInt() == Qt::Checked && !m_checkStates.value(srcindex, false)) {
+ m_checkStates.insert(srcindex, true);
+ emit dataChanged(index, index);
+ } else if (m_checkStates.value(srcindex, true)) {
+ m_checkStates.insert(srcindex, false);
+ emit dataChanged(index, index);
+ }
+ return true;
+ }
+ }
+
+ return QSortFilterProxyModel::setData(index, value, role);
+}
+
+ProVariable *ProScopeFilter::sourceVariable(const QModelIndex &index) const
+{
+ ProEditorModel *model = qobject_cast<ProEditorModel*>(sourceModel());
+ return model->proVariable(mapToSource(index));
+}
+
+bool ProScopeFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ ProEditorModel *model = qobject_cast<ProEditorModel*>(sourceModel());
+ if (!model)
+ return true;
+
+ QModelIndex index = model->index(source_row, 0, source_parent);
+ ProItem *item = model->proItem(index);
+ if (item->kind() != ProItem::BlockKind)
+ return false;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+
+ if (m_vars.isEmpty())
+ return (block->blockKind() & ProBlock::ScopeKind || block->blockKind() & ProBlock::ProFileKind);
+
+ if (block->blockKind() & ProBlock::VariableKind
+ || block->blockKind() & ProBlock::ScopeKind
+ || block->blockKind() & ProBlock::ProFileKind)
+ return !model->findVariables(m_vars, index).isEmpty();
+
+ return false;
+}
diff --git a/shared/proparser/proeditormodel.h b/shared/proparser/proeditormodel.h
new file mode 100644
index 0000000000..7e5088bba8
--- /dev/null
+++ b/shared/proparser/proeditormodel.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROEDITORMODEL_H
+#define PROEDITORMODEL_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QList>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtGui/QSortFilterProxyModel>
+
+QT_FORWARD_DECLARE_CLASS(ProBlock)
+QT_FORWARD_DECLARE_CLASS(ProFile)
+QT_FORWARD_DECLARE_CLASS(ProItem)
+QT_FORWARD_DECLARE_CLASS(ProVariable)
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProCommandManager;
+class ProItemInfoManager;
+
+class ProEditorModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ ProEditorModel(QObject *parent = 0);
+ ~ProEditorModel();
+
+ void setInfoManager(ProItemInfoManager *infomanager);
+ ProItemInfoManager *infoManager() const;
+ ProCommandManager *cmdManager() const;
+
+ void setProFiles(QList<ProFile*> proFiles);
+ QList<ProFile*> proFiles() const;
+
+ QList<QModelIndex> findVariables(const QStringList &varname, const QModelIndex &parent = QModelIndex()) const;
+ QList<QModelIndex> findBlocks(const QModelIndex &parent = QModelIndex()) const;
+
+ bool moveItem(const QModelIndex &index, int row);
+ bool insertItem(ProItem *item, int row, const QModelIndex &parent);
+ bool removeItem(const QModelIndex &index);
+
+ ProItem *proItem(const QModelIndex &index) const;
+ ProBlock *proBlock(const QModelIndex &index) const;
+ ProVariable *proVariable(const QModelIndex &index) const;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+
+ inline QList<ProFile*> changed() const { return m_changed.toList(); }
+protected:
+ ProItem *createExpressionItem(QString &str) const;
+
+ QString blockName(ProBlock *block) const;
+ ProBlock *scopeContents(ProBlock *block) const;
+
+ QString expressionToString(ProBlock *block, bool display = false) const;
+ QList<ProItem *> stringToExpression(const QString &exp) const;
+
+ bool insertModelItem(ProItem *item, int row, const QModelIndex &parent);
+ bool removeModelItem(const QModelIndex &index);
+
+private:
+ void markProFileModified(QModelIndex index);
+ ProCommandManager *m_cmdmanager;
+ QList<ProFile*> m_proFiles;
+ QSet<ProFile*> m_changed;
+ ProItemInfoManager *m_infomanager;
+
+ friend class ProAddCommand;
+ friend class ProRemoveCommand;
+ friend class ChangeProScopeCommand;
+ friend class ChangeProAdvancedCommand;
+};
+
+class ProScopeFilter : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ enum CheckableType {
+ None,
+ Variable,
+ Blocks
+ };
+
+ void setVariableFilter(const QStringList &vars);
+ void setCheckable( CheckableType ct );
+
+ // returns the checked (source) indexes
+ QList<QModelIndex> checkedIndexes() const;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ ProScopeFilter(QObject *parent);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+protected:
+ ProVariable *sourceVariable(const QModelIndex &index) const;
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+
+private:
+ CheckableType m_checkable;
+ QStringList m_vars;
+ QMap<QModelIndex, bool> m_checkStates;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //PROEDITORMODEL_H
+
diff --git a/shared/proparser/profileevaluator.cpp b/shared/proparser/profileevaluator.cpp
new file mode 100644
index 0000000000..1ed55398a5
--- /dev/null
+++ b/shared/proparser/profileevaluator.cpp
@@ -0,0 +1,1833 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "profileevaluator.h"
+#include "proparserutils.h"
+#include "proitems.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QList>
+#include <QtCore/QRegExp>
+#include <QtCore/QSet>
+#include <QtCore/QStack>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#else
+#define QT_POPEN popen
+#endif
+
+QT_BEGIN_NAMESPACE
+
+///////////////////////////////////////////////////////////////////////
+//
+// ProFileEvaluator::Private
+//
+///////////////////////////////////////////////////////////////////////
+
+class ProFileEvaluator::Private : public AbstractProItemVisitor
+{
+public:
+ Private(ProFileEvaluator *q_);
+
+ bool read(ProFile *pro);
+
+ void writeItem(const QList<ProItem *> &items, int index, QTextStream &out, QString indent);
+ ProBlock *currentBlock();
+ void updateItem();
+ bool parseLine(const QString &line);
+ void insertVariable(const QString &line, int *i);
+ void insertOperator(const char op);
+ void insertComment(const QString &comment);
+ void enterScope(bool multiLine);
+ void leaveScope();
+ void finalizeBlock();
+ void cleanup();
+
+ // implementation of AbstractProItemVisitor
+ bool visitBeginProBlock(ProBlock *block);
+ bool visitEndProBlock(ProBlock *block);
+ bool visitBeginProVariable(ProVariable *variable);
+ bool visitEndProVariable(ProVariable *variable);
+ bool visitBeginProFile(ProFile *value);
+ bool visitEndProFile(ProFile *value);
+ bool visitProValue(ProValue *value);
+ bool visitProFunction(ProFunction *function);
+ bool visitProOperator(ProOperator *oper);
+ bool visitProCondition(ProCondition *condition);
+
+ QStringList values(const QString &variableName) const;
+ QStringList values(const QString &variableName, const ProFile *pro) const;
+ QString propertyValue(const QString &val) const;
+
+ bool isActiveConfig(const QString &config, bool regex = false);
+ QStringList expandPattern(const QString &pattern);
+ void expandPatternHelper(const QString &relName, const QString &absName,
+ QStringList &sources_out);
+ QStringList expandVariableReferences(const QString &value);
+ QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
+ QString format(const char *format) const;
+
+ QString currentFileName() const;
+ QString getcwd() const;
+ ProFile *currentProFile() const;
+
+ bool evaluateConditionalFunction(const QString &function, const QString &arguments, bool *result);
+ bool evaluateFile(const QString &fileName, bool *result);
+ bool evaluateFeatureFile(const QString &fileName, bool *result);
+
+ QStringList qmakeFeaturePaths();
+
+ ProFileEvaluator *q;
+
+ QStack<ProBlock *> m_blockstack;
+ ProBlock *m_block;
+
+ ProItem *m_commentItem;
+ QString m_proitem;
+ QString m_pendingComment;
+ bool m_syntaxError;
+ bool m_contNextLine;
+ bool m_condition;
+ bool m_invertNext;
+ QString m_lastVarName;
+ ProVariable::VariableOperator m_variableOperator;
+ int m_lineNo; // Error reporting
+ QString m_oldPath; // To restore the current path to the path
+ QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri'
+
+ QHash<QString, QStringList> m_valuemap; // VariableName must be us-ascii, the content however can be non-us-ascii.
+ QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file
+ QHash<QString, QString> m_properties;
+ QString m_origfile;
+
+ int m_prevLineNo; // Checking whether we're assigning the same TARGET
+ ProFile *m_prevProFile; // See m_prevLineNo
+
+ bool m_verbose;
+};
+
+ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
+ : q(q_)
+{
+ m_prevLineNo = 0;
+ m_prevProFile = 0;
+ m_verbose = true;
+ m_block = 0;
+ m_commentItem = 0;
+ m_syntaxError = 0;
+ m_lineNo = 0;
+ m_contNextLine = false;
+}
+
+bool ProFileEvaluator::Private::read(ProFile *pro)
+{
+ QFile file(pro->fileName());
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ q->errorMessage(format("%1 not readable.").arg(pro->fileName()));
+ return false;
+ }
+
+ m_syntaxError = false;
+ m_lineNo = 1;
+ m_blockstack.push(pro);
+
+ QTextStream ts(&file);
+ while (!ts.atEnd()) {
+ QString line = ts.readLine();
+ if (!parseLine(line)) {
+ q->errorMessage(format(".pro parse failure."));
+ return false;
+ }
+ ++m_lineNo;
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::parseLine(const QString &line0)
+{
+ if (m_blockstack.isEmpty())
+ return false;
+
+ ushort quote = 0;
+ int parens = 0;
+ bool contNextLine = false;
+ QString line = line0.simplified();
+
+ for (int i = 0; !m_syntaxError && i < line.length(); ++i) {
+ ushort c = line.at(i).unicode();
+ if (quote && c == quote)
+ quote = 0;
+ else if (c == '(')
+ ++parens;
+ else if (c == ')')
+ --parens;
+ else if (c == '"' && (i == 0 || line.at(i - 1).unicode() != '\\'))
+ quote = c;
+ else if (!parens && !quote) {
+ if (c == '#') {
+ insertComment(line.mid(i + 1));
+ contNextLine = m_contNextLine;
+ break;
+ }
+ if (c == '\\' && i >= line.count() - 1) {
+ updateItem();
+ contNextLine = true;
+ continue;
+ }
+ if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) {
+ if (c == ' ')
+ updateItem();
+ else
+ m_proitem += c;
+ continue;
+ }
+ if (c == ':') {
+ enterScope(false);
+ continue;
+ }
+ if (c == '{') {
+ enterScope(true);
+ continue;
+ }
+ if (c == '}') {
+ leaveScope();
+ continue;
+ }
+ if (c == '=') {
+ insertVariable(line, &i);
+ continue;
+ }
+ if (c == '|' || c == '!') {
+ insertOperator(c);
+ continue;
+ }
+ }
+
+ m_proitem += c;
+ }
+ m_contNextLine = contNextLine;
+
+ if (!m_syntaxError) {
+ updateItem();
+ if (!m_contNextLine)
+ finalizeBlock();
+ }
+ return !m_syntaxError;
+}
+
+void ProFileEvaluator::Private::finalizeBlock()
+{
+ if (m_blockstack.isEmpty()) {
+ m_syntaxError = true;
+ } else {
+ if (m_blockstack.top()->blockKind() & ProBlock::SingleLine)
+ leaveScope();
+ m_block = 0;
+ m_commentItem = 0;
+ }
+}
+
+void ProFileEvaluator::Private::insertVariable(const QString &line, int *i)
+{
+ ProVariable::VariableOperator opkind;
+
+ switch (m_proitem.at(m_proitem.length() - 1).unicode()) {
+ case '+':
+ m_proitem.chop(1);
+ opkind = ProVariable::AddOperator;
+ break;
+ case '-':
+ m_proitem.chop(1);
+ opkind = ProVariable::RemoveOperator;
+ break;
+ case '*':
+ m_proitem.chop(1);
+ opkind = ProVariable::UniqueAddOperator;
+ break;
+ case '~':
+ m_proitem.chop(1);
+ opkind = ProVariable::ReplaceOperator;
+ break;
+ default:
+ opkind = ProVariable::SetOperator;
+ }
+
+ ProBlock *block = m_blockstack.top();
+ m_proitem = m_proitem.trimmed();
+ ProVariable *variable = new ProVariable(m_proitem, block);
+ variable->setLineNumber(m_lineNo);
+ variable->setVariableOperator(opkind);
+ block->appendItem(variable);
+ m_block = variable;
+
+ if (!m_pendingComment.isEmpty()) {
+ m_block->setComment(m_pendingComment);
+ m_pendingComment.clear();
+ }
+ m_commentItem = variable;
+
+ m_proitem.clear();
+
+ if (opkind == ProVariable::ReplaceOperator) {
+ // skip util end of line or comment
+ while (1) {
+ ++(*i);
+
+ // end of line?
+ if (*i >= line.count())
+ break;
+
+ // comment?
+ if (line.at(*i).unicode() == '#') {
+ --(*i);
+ break;
+ }
+
+ m_proitem += line.at(*i);
+ }
+ m_proitem = m_proitem.trimmed();
+ }
+}
+
+void ProFileEvaluator::Private::insertOperator(const char op)
+{
+ updateItem();
+
+ ProOperator::OperatorKind opkind;
+ switch(op) {
+ case '!':
+ opkind = ProOperator::NotOperator;
+ break;
+ case '|':
+ opkind = ProOperator::OrOperator;
+ break;
+ default:
+ opkind = ProOperator::OrOperator;
+ }
+
+ ProBlock * const block = currentBlock();
+ ProOperator * const proOp = new ProOperator(opkind);
+ proOp->setLineNumber(m_lineNo);
+ block->appendItem(proOp);
+ m_commentItem = proOp;
+}
+
+void ProFileEvaluator::Private::insertComment(const QString &comment)
+{
+ updateItem();
+
+ QString strComment;
+ if (!m_commentItem)
+ strComment = m_pendingComment;
+ else
+ strComment = m_commentItem->comment();
+
+ if (strComment.isEmpty())
+ strComment = comment;
+ else {
+ strComment += QLatin1Char('\n');
+ strComment += comment.trimmed();
+ }
+
+ strComment = strComment.trimmed();
+
+ if (!m_commentItem)
+ m_pendingComment = strComment;
+ else
+ m_commentItem->setComment(strComment);
+}
+
+void ProFileEvaluator::Private::enterScope(bool multiLine)
+{
+ updateItem();
+
+ ProBlock *parent = currentBlock();
+ ProBlock *block = new ProBlock(parent);
+ block->setLineNumber(m_lineNo);
+ parent->setBlockKind(ProBlock::ScopeKind);
+
+ parent->appendItem(block);
+
+ if (multiLine)
+ block->setBlockKind(ProBlock::ScopeContentsKind);
+ else
+ block->setBlockKind(ProBlock::ScopeContentsKind|ProBlock::SingleLine);
+
+ m_blockstack.push(block);
+ m_block = 0;
+}
+
+void ProFileEvaluator::Private::leaveScope()
+{
+ updateItem();
+ m_blockstack.pop();
+ finalizeBlock();
+}
+
+ProBlock *ProFileEvaluator::Private::currentBlock()
+{
+ if (m_block)
+ return m_block;
+
+ ProBlock *parent = m_blockstack.top();
+ m_block = new ProBlock(parent);
+ m_block->setLineNumber(m_lineNo);
+ parent->appendItem(m_block);
+
+ if (!m_pendingComment.isEmpty()) {
+ m_block->setComment(m_pendingComment);
+ m_pendingComment.clear();
+ }
+
+ m_commentItem = m_block;
+
+ return m_block;
+}
+
+void ProFileEvaluator::Private::updateItem()
+{
+ m_proitem = m_proitem.trimmed();
+ if (m_proitem.isEmpty())
+ return;
+
+ ProBlock *block = currentBlock();
+ if (block->blockKind() & ProBlock::VariableKind) {
+ m_commentItem = new ProValue(m_proitem, static_cast<ProVariable*>(block));
+ } else if (m_proitem.endsWith(QLatin1Char(')'))) {
+ m_commentItem = new ProFunction(m_proitem);
+ } else {
+ m_commentItem = new ProCondition(m_proitem);
+ }
+ m_commentItem->setLineNumber(m_lineNo);
+ block->appendItem(m_commentItem);
+
+ m_proitem.clear();
+}
+
+
+bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
+{
+ if (block->blockKind() == ProBlock::ScopeKind) {
+ m_invertNext = false;
+ m_condition = false;
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block)
+{
+ Q_UNUSED(block);
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable)
+{
+ m_lastVarName = variable->variable();
+ m_variableOperator = variable->variableOperator();
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable)
+{
+ Q_UNUSED(variable);
+ m_lastVarName.clear();
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
+{
+ m_invertNext = (oper->operatorKind() == ProOperator::NotOperator);
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
+{
+ if (!m_condition) {
+ if (m_invertNext)
+ m_condition |= !isActiveConfig(cond->text(), true);
+ else
+ m_condition |= isActiveConfig(cond->text(), true);
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
+{
+ PRE(pro);
+ bool ok = true;
+ m_lineNo = pro->lineNumber();
+
+ if (m_origfile.isEmpty())
+ m_origfile = pro->fileName();
+ if (m_oldPath.isEmpty()) {
+ // change the working directory for the initial profile we visit, since
+ // that is *the* profile. All the other times we reach this function will be due to
+ // include(file) or load(file)
+
+ m_oldPath = QDir::currentPath();
+
+ m_profileStack.push(pro);
+
+ const QString mkspecDirectory = propertyValue("QMAKE_MKSPECS");
+ if (!mkspecDirectory.isEmpty()) {
+ // This is what qmake does, everything set in the mkspec is also set
+ // But this also creates a lot of problems
+ evaluateFile(mkspecDirectory + "/default/qmake.conf", &ok);
+ evaluateFile(mkspecDirectory + "/features/default_pre.prf", &ok);
+ }
+
+ QString fn = pro->fileName();
+ ok = QDir::setCurrent(QFileInfo(fn).absolutePath());
+ }
+
+ return ok;
+}
+
+bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
+{
+ PRE(pro);
+ bool ok = true;
+ m_lineNo = pro->lineNumber();
+ if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) {
+ const QString mkspecDirectory = propertyValue("QMAKE_MKSPECS");
+ if (!mkspecDirectory.isEmpty()) {
+ evaluateFile(mkspecDirectory + "/features/default_post.prf", &ok);
+
+ QStringList processed;
+ while(1) {
+ bool finished = true;
+ QStringList configs = values("CONFIG");
+ for(int i = configs.size()-1; i >= 0; --i) {
+ const QString config = configs[i].toLower();
+ if(!processed.contains(config)) {
+ processed.append(config);
+ evaluateFile(mkspecDirectory + "/features/" + config + ".prf", &ok);
+ if(ok) {
+ finished = false;
+ break;
+ }
+ }
+ }
+ if(finished)
+ break;
+ }
+ }
+
+ m_profileStack.pop();
+ ok = QDir::setCurrent(m_oldPath);
+ }
+ return ok;
+}
+
+bool ProFileEvaluator::Private::visitProValue(ProValue *value)
+{
+ PRE(value);
+ m_lineNo = value->lineNumber();
+ QString val = value->value();
+
+ QString varName = m_lastVarName;
+
+ QStringList v = expandVariableReferences(val);
+
+ // Since qmake combines different values for the TARGET variable, we join
+ // TARGET values that are on the same line. We can't do this later with all
+ // values because this parser isn't scope-aware, so we'd risk joining
+ // scope-specific targets together.
+ if (varName == QLatin1String("TARGET")
+ && m_lineNo == m_prevLineNo
+ && currentProFile() == m_prevProFile) {
+ QStringList targets = m_valuemap.value(QLatin1String("TARGET"));
+ m_valuemap.remove(QLatin1String("TARGET"));
+ QStringList lastTarget(targets.takeLast());
+ lastTarget << v.join(QLatin1String(" "));
+ targets.push_back(lastTarget.join(QLatin1String(" ")));
+ v = targets;
+ }
+ m_prevLineNo = m_lineNo;
+ m_prevProFile = currentProFile();
+
+ // The following two blocks fix bug 180128 by making all "interesting"
+ // file name absolute in each .pro file, not just the top most one
+ if (varName == QLatin1String("SOURCES")
+ || varName == QLatin1String("HEADERS")
+ || varName == QLatin1String("INTERFACES")
+ || varName == QLatin1String("FORMS")
+ || varName == QLatin1String("FORMS3")
+ || varName == QLatin1String("RESOURCES")) {
+ // matches only existent files, expand certain(?) patterns
+ QStringList vv;
+ for (int i = v.count(); --i >= 0; )
+ vv << expandPattern(v[i]);
+ v = vv;
+ }
+
+ if (varName == QLatin1String("TRANSLATIONS")) {
+ // also matches non-existent files, but does not expand pattern
+ QString dir = QFileInfo(currentFileName()).absolutePath();
+ dir += QLatin1Char('/');
+ for (int i = v.count(); --i >= 0; )
+ v[i] = QFileInfo(dir, v[i]).absoluteFilePath();
+ }
+
+ switch (m_variableOperator) {
+ case ProVariable::UniqueAddOperator: // *
+ insertUnique(&m_valuemap, varName, v, true);
+ insertUnique(&m_filevaluemap[currentProFile()], varName, v, true);
+ break;
+ case ProVariable::SetOperator: // =
+ case ProVariable::AddOperator: // +
+ insertUnique(&m_valuemap, varName, v, false);
+ insertUnique(&m_filevaluemap[currentProFile()], varName, v, false);
+ break;
+ case ProVariable::RemoveOperator: // -
+ // fix me: interaction between AddOperator and RemoveOperator
+ insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false);
+ insertUnique(&m_filevaluemap[currentProFile()],
+ varName.prepend(QLatin1Char('-')), v, false);
+ break;
+ case ProVariable::ReplaceOperator: // ~
+ {
+ // DEFINES ~= s/a/b/?[gqi]
+
+/* Create a superset by executing replacement + adding items that have changed
+ to original list. We're not sure if this is really the right approach, so for
+ the time being we will just do nothing ...
+
+ QChar sep = val.at(1);
+ QStringList func = val.split(sep);
+ if (func.count() < 3 || func.count() > 4) {
+ q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments."));
+ return false;
+ }
+ if (func[0] != QLatin1String("s")) {
+ q->logMessage(format("~= operator can only handle s/// function."));
+ return false;
+ }
+ bool global = false, quote = false, case_sense = false;
+
+ if (func.count() == 4) {
+ global = func[3].indexOf(QLatin1Char('g')) != -1;
+ case_sense = func[3].indexOf(QLatin1Char('i')) == -1;
+ quote = func[3].indexOf(QLatin1Char('q')) != -1;
+ }
+ QString pattern = func[1];
+ QString replace = func[2];
+ if (quote)
+ pattern = QRegExp::escape(pattern);
+
+ QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
+
+ QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace,
+ global);
+ // Add changed entries to list
+ foreach (const QString &entry, replaceList)
+ if (!m_valuemap.value(varName).contains(entry))
+ insertUnique(&m_valuemap, varName, QStringList() << entry, false);
+
+ replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp,
+ replace, global);
+ foreach (const QString &entry, replaceList)
+ if (!m_filevaluemap[currentProFile()].value(varName).contains(entry))
+ insertUnique(&m_filevaluemap[currentProFile()], varName,
+ QStringList() << entry, false); */
+ }
+ break;
+
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitProFunction(ProFunction *func)
+{
+ m_lineNo = func->lineNumber();
+ bool result = true;
+ bool ok = true;
+ QString text = func->text();
+ int lparen = text.indexOf(QLatin1Char('('));
+ int rparen = text.lastIndexOf(QLatin1Char(')'));
+ Q_ASSERT(lparen < rparen);
+
+ QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
+ QString funcName = text.left(lparen);
+ ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result);
+ return ok;
+}
+
+
+QStringList ProFileEvaluator::Private::qmakeFeaturePaths()
+{
+ QStringList concat;
+ {
+ const QString base_concat = QDir::separator() + QString(QLatin1String("features"));
+ concat << base_concat + QDir::separator() + QLatin1String("mac");
+ concat << base_concat + QDir::separator() + QLatin1String("macx");
+ concat << base_concat + QDir::separator() + QLatin1String("unix");
+ concat << base_concat + QDir::separator() + QLatin1String("win32");
+ concat << base_concat + QDir::separator() + QLatin1String("mac9");
+ concat << base_concat + QDir::separator() + QLatin1String("qnx6");
+ concat << base_concat;
+ }
+ const QString mkspecs_concat = QDir::separator() + QString(QLatin1String("mkspecs"));
+ QStringList feature_roots;
+ QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
+ if (!mkspec_path.isNull())
+ feature_roots += splitPathList(QString::fromLocal8Bit(mkspec_path));
+ /*
+ if (prop)
+ feature_roots += splitPathList(prop->value("QMAKEFEATURES"));
+ if (!Option::mkfile::cachefile.isEmpty()) {
+ QString path;
+ int last_slash = Option::mkfile::cachefile.lastIndexOf(Option::dir_sep);
+ if (last_slash != -1)
+ path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash));
+ foreach (const QString &concat_it, concat)
+ feature_roots << (path + concat_it);
+ }
+ */
+
+ QByteArray qmakepath = qgetenv("QMAKEPATH");
+ if (!qmakepath.isNull()) {
+ const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
+ foreach (const QString &item, lst) {
+ foreach (const QString &concat_it, concat)
+ feature_roots << (item + mkspecs_concat + concat_it);
+ }
+ }
+ //if (!Option::mkfile::qmakespec.isEmpty())
+ // feature_roots << Option::mkfile::qmakespec + QDir::separator() + "features";
+ //if (!Option::mkfile::qmakespec.isEmpty()) {
+ // QFileInfo specfi(Option::mkfile::qmakespec);
+ // QDir specdir(specfi.absoluteFilePath());
+ // while (!specdir.isRoot()) {
+ // if (!specdir.cdUp() || specdir.isRoot())
+ // break;
+ // if (QFile::exists(specdir.path() + QDir::separator() + "features")) {
+ // foreach (const QString &concat_it, concat)
+ // feature_roots << (specdir.path() + concat_it);
+ // break;
+ // }
+ // }
+ //}
+ foreach (const QString &concat_it, concat)
+ feature_roots << (propertyValue(QLatin1String("QT_INSTALL_PREFIX")) +
+ mkspecs_concat + concat_it);
+ foreach (const QString &concat_it, concat)
+ feature_roots << (propertyValue(QLatin1String("QT_INSTALL_DATA")) +
+ mkspecs_concat + concat_it);
+ return feature_roots;
+}
+
+QString ProFileEvaluator::Private::propertyValue(const QString &name) const
+{
+ if (m_properties.contains(name))
+ return m_properties.value(name);
+ if (name == QLatin1String("QT_INSTALL_PREFIX"))
+ return QLibraryInfo::location(QLibraryInfo::PrefixPath);
+ if (name == QLatin1String("QT_INSTALL_DATA"))
+ return QLibraryInfo::location(QLibraryInfo::DataPath);
+ if (name == QLatin1String("QT_INSTALL_DOCS"))
+ return QLibraryInfo::location(QLibraryInfo::DocumentationPath);
+ if (name == QLatin1String("QT_INSTALL_HEADERS"))
+ return QLibraryInfo::location(QLibraryInfo::HeadersPath);
+ if (name == QLatin1String("QT_INSTALL_LIBS"))
+ return QLibraryInfo::location(QLibraryInfo::LibrariesPath);
+ if (name == QLatin1String("QT_INSTALL_BINS"))
+ return QLibraryInfo::location(QLibraryInfo::BinariesPath);
+ if (name == QLatin1String("QT_INSTALL_PLUGINS"))
+ return QLibraryInfo::location(QLibraryInfo::PluginsPath);
+ if (name == QLatin1String("QT_INSTALL_TRANSLATIONS"))
+ return QLibraryInfo::location(QLibraryInfo::TranslationsPath);
+ if (name == QLatin1String("QT_INSTALL_CONFIGURATION"))
+ return QLibraryInfo::location(QLibraryInfo::SettingsPath);
+ if (name == QLatin1String("QT_INSTALL_EXAMPLES"))
+ return QLibraryInfo::location(QLibraryInfo::ExamplesPath);
+ if (name == QLatin1String("QT_INSTALL_DEMOS"))
+ return QLibraryInfo::location(QLibraryInfo::DemosPath);
+ if (name == QLatin1String("QMAKE_MKSPECS"))
+ return qmake_mkspec_paths().join(Option::dirlist_sep);
+ if (name == QLatin1String("QMAKE_VERSION"))
+ return QLatin1String("1.0"); //### FIXME
+ //return qmake_version();
+#ifdef QT_VERSION_STR
+ if (name == QLatin1String("QT_VERSION"))
+ return QLatin1String(QT_VERSION_STR);
+#endif
+ return QLatin1String("UNKNOWN"); //###
+}
+
+ProFile *ProFileEvaluator::Private::currentProFile() const
+{
+ if (m_profileStack.count() > 0)
+ return m_profileStack.top();
+ return 0;
+}
+
+QString ProFileEvaluator::Private::currentFileName() const
+{
+ ProFile *pro = currentProFile();
+ if (pro)
+ return pro->fileName();
+ return QString();
+}
+
+QString ProFileEvaluator::Private::getcwd() const
+{
+ ProFile *cur = m_profileStack.top();
+ QFileInfo fi(cur->fileName());
+ return fi.absolutePath();
+}
+
+QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &str)
+{
+ bool fOK;
+ bool *ok = &fOK;
+ QStringList ret;
+ if (ok)
+ *ok = true;
+ if (str.isEmpty())
+ return ret;
+
+ const ushort LSQUARE = '[';
+ const ushort RSQUARE = ']';
+ const ushort LCURLY = '{';
+ const ushort RCURLY = '}';
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort DOLLAR = '$';
+ const ushort BACKSLASH = '\\';
+ const ushort UNDERSCORE = '_';
+ const ushort DOT = '.';
+ const ushort SPACE = ' ';
+ const ushort TAB = '\t';
+
+ const QChar *str_data = str.data();
+ const int str_len = str.length();
+
+ ushort term;
+ QString var, args;
+
+ int replaced = 0;
+ QString current;
+ for (int i = 0; i < str_len; ++i) {
+ ushort c = str_data[i].unicode();
+ const int start_var = i;
+ if (c == BACKSLASH) {
+ bool escape = false;
+ const char *symbols = "[]{}()$\\";
+ for (const char *s = symbols; *s; ++s) {
+ if (str_data[i+1] == (ushort)*s) {
+ i++;
+ escape = true;
+ if (!(replaced++))
+ current = str.left(start_var);
+ current.append(str.at(i));
+ break;
+ }
+ }
+ if (!escape && replaced)
+ current.append(QChar(c));
+ continue;
+ }
+ if (c == SPACE || c == TAB) {
+ c = 0;
+ if (!current.isEmpty()) {
+ unquote(&current);
+ ret.append(current);
+ current.clear();
+ }
+ } else if (c == DOLLAR && str_len > i+2) {
+ c = str_data[++i].unicode();
+ if (c == DOLLAR) {
+ term = 0;
+ var.clear();
+ args.clear();
+ enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR;
+ c = str_data[++i].unicode();
+ if (c == LSQUARE) {
+ c = str_data[++i].unicode();
+ term = RSQUARE;
+ var_type = PROPERTY;
+ } else if (c == LCURLY) {
+ c = str_data[++i].unicode();
+ var_type = VAR;
+ term = RCURLY;
+ } else if (c == LPAREN) {
+ c = str_data[++i].unicode();
+ var_type = ENVIRON;
+ term = RPAREN;
+ }
+ while (1) {
+ if (!(c & (0xFF<<8)) &&
+ c != DOT && c != UNDERSCORE &&
+ (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9'))
+ break;
+ var.append(QChar(c));
+ if (++i == str_len)
+ break;
+ c = str_data[i].unicode();
+ }
+ if (var_type == VAR && c == LPAREN) {
+ var_type = FUNCTION;
+ int depth = 0;
+ while (1) {
+ if (++i == str_len)
+ break;
+ c = str_data[i].unicode();
+ if (c == LPAREN) {
+ depth++;
+ } else if (c == RPAREN) {
+ if (!depth)
+ break;
+ --depth;
+ }
+ args.append(QChar(c));
+ }
+ if (i < str_len-1)
+ c = str_data[++i].unicode();
+ else
+ c = 0;
+ }
+ if (term) {
+ if (c != term) {
+ q->logMessage(format("Missing %1 terminator [found %2]")
+ .arg(QChar(term)).arg(QChar(c)));
+ if (ok)
+ *ok = false;
+ return QStringList();
+ }
+ c = 0;
+ } else if (i > str_len-1) {
+ c = 0;
+ }
+
+ QStringList replacement;
+ if (var_type == ENVIRON) {
+ replacement << QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData()));
+ } else if (var_type == PROPERTY) {
+ replacement << propertyValue(var);
+ //if (prop)
+ // replacement = QStringList(prop->value(var));
+ } else if (var_type == FUNCTION) {
+ replacement << evaluateExpandFunction(var, args);
+ } else if (var_type == VAR) {
+ replacement += values(var);
+ }
+ if (!(replaced++) && start_var)
+ current = str.left(start_var);
+ if (!replacement.isEmpty()) {
+ /* If a list is beteen two strings make sure it expands in such a way
+ * that the string to the left is prepended to the first string and
+ * the string to the right is appended to the last string, example:
+ * LIST = a b c
+ * V3 = x/$$LIST/f.cpp
+ * message($$member(V3,0)) # Outputs "x/a"
+ * message($$member(V3,1)) # Outputs "b"
+ * message($$member(V3,2)) # Outputs "c/f.cpp"
+ */
+ current.append(replacement.at(0));
+ for (int i = 1; i < replacement.count(); ++i) {
+ unquote(&current);
+ ret.append(current);
+ current = replacement.at(i);
+ }
+ }
+ } else {
+ if (replaced)
+ current.append(QLatin1Char('$'));
+ }
+ }
+ if (replaced && c != 0)
+ current.append(QChar(c));
+ }
+ if (!replaced) {
+ current = str;
+ unquote(&current);
+ ret.append(current);
+ } else if (!current.isEmpty()) {
+ unquote(&current);
+ ret.append(current);
+ q->logMessage(format("Project Parser [var replace]: %1 -> [%2]\n")
+ .arg(str).arg(ret.join(QLatin1String(","))));
+ }
+ return ret;
+}
+
+bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex)
+{
+ // magic types for easy flipping
+ if (config == QLatin1String("true"))
+ return true;
+ if (config == QLatin1String("false"))
+ return false;
+
+ // mkspecs
+ if ((Option::target_mode == Option::TARG_MACX_MODE
+ || Option::target_mode == Option::TARG_QNX6_MODE
+ || Option::target_mode == Option::TARG_UNIX_MODE)
+ && config == QLatin1String("unix"))
+ return true;
+ if (Option::target_mode == Option::TARG_MACX_MODE && config == QLatin1String("macx"))
+ return true;
+ if (Option::target_mode == Option::TARG_QNX6_MODE && config == QLatin1String("qnx6"))
+ return true;
+ if (Option::target_mode == Option::TARG_MAC9_MODE && config == QLatin1String("mac9"))
+ return true;
+ if ((Option::target_mode == Option::TARG_MAC9_MODE
+ || Option::target_mode == Option::TARG_MACX_MODE)
+ && config == QLatin1String("mac"))
+ return true;
+ if (Option::target_mode == Option::TARG_WIN_MODE && config == QLatin1String("win32"))
+ return true;
+
+ QRegExp re(config, Qt::CaseSensitive, QRegExp::Wildcard);
+ QString spec = Option::qmakespec;
+ if ((regex && re.exactMatch(spec)) || (!regex && spec == config))
+ return true;
+
+ return false;
+}
+
+QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments)
+{
+ QStringList argumentsList = split_arg_list(arguments);
+ QStringList args;
+ for (int i = 0; i < argumentsList.count(); ++i)
+ args += expandVariableReferences(argumentsList[i]);
+
+ enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
+ E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
+ E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND,
+ E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE,
+ E_REPLACE };
+
+ static QHash<QString, int> *expands = 0;
+ if (!expands) {
+ expands = new QHash<QString, int>;
+ expands->insert(QLatin1String("member"), E_MEMBER); //v (implemented)
+ expands->insert(QLatin1String("first"), E_FIRST); //v
+ expands->insert(QLatin1String("last"), E_LAST); //v
+ expands->insert(QLatin1String("cat"), E_CAT);
+ expands->insert(QLatin1String("fromfile"), E_FROMFILE);
+ expands->insert(QLatin1String("eval"), E_EVAL);
+ expands->insert(QLatin1String("list"), E_LIST);
+ expands->insert(QLatin1String("sprintf"), E_SPRINTF);
+ expands->insert(QLatin1String("join"), E_JOIN); //v
+ expands->insert(QLatin1String("split"), E_SPLIT); //v
+ expands->insert(QLatin1String("basename"), E_BASENAME); //v
+ expands->insert(QLatin1String("dirname"), E_DIRNAME); //v
+ expands->insert(QLatin1String("section"), E_SECTION);
+ expands->insert(QLatin1String("find"), E_FIND);
+ expands->insert(QLatin1String("system"), E_SYSTEM); //v
+ expands->insert(QLatin1String("unique"), E_UNIQUE);
+ expands->insert(QLatin1String("quote"), E_QUOTE); //v
+ expands->insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND);
+ expands->insert(QLatin1String("upper"), E_UPPER);
+ expands->insert(QLatin1String("lower"), E_LOWER);
+ expands->insert(QLatin1String("re_escape"), E_RE_ESCAPE);
+ expands->insert(QLatin1String("files"), E_FILES);
+ expands->insert(QLatin1String("prompt"), E_PROMPT);
+ expands->insert(QLatin1String("replace"), E_REPLACE);
+ }
+ ExpandFunc func_t = ExpandFunc(expands->value(func.toLower()));
+
+ QStringList ret;
+
+ switch (func_t) {
+ case E_BASENAME:
+ case E_DIRNAME:
+ case E_SECTION: {
+ bool regexp = false;
+ QString sep, var;
+ int beg = 0;
+ int end = -1;
+ if (func_t == E_SECTION) {
+ if (args.count() != 3 && args.count() != 4) {
+ q->logMessage(format("%1(var) section(var, sep, begin, end) "
+ "requires three arguments.").arg(func));
+ } else {
+ var = args[0];
+ sep = args[1];
+ beg = args[2].toInt();
+ if (args.count() == 4)
+ end = args[3].toInt();
+ }
+ } else {
+ if (args.count() != 1) {
+ q->logMessage(format("%1(var) requires one argument.").arg(func));
+ } else {
+ var = args[0];
+ regexp = true;
+ sep = QLatin1String("[\\\\/]");
+ if (func_t == E_DIRNAME)
+ end = -2;
+ else
+ beg = -1;
+ }
+ }
+ if (!var.isNull()) {
+ foreach (const QString str, values(var)) {
+ if (regexp)
+ ret += str.section(QRegExp(sep), beg, end);
+ else
+ ret += str.section(sep, beg, end);
+ }
+ }
+ break;
+ }
+ case E_JOIN: {
+ if (args.count() < 1 || args.count() > 4) {
+ q->logMessage(format("join(var, glue, before, after) requires four arguments."));
+ } else {
+ QString glue, before, after;
+ if (args.count() >= 2)
+ glue = args[1];
+ if (args.count() >= 3)
+ before = args[2];
+ if (args.count() == 4)
+ after = args[3];
+ const QStringList &var = values(args.first());
+ if (!var.isEmpty())
+ ret.append(before + var.join(glue) + after);
+ }
+ break;
+ }
+ case E_SPLIT: {
+ if (args.count() < 2 || args.count() > 2) {
+ q->logMessage(format("split(var, sep) requires two arguments"));
+ } else {
+ QString sep = args.at(1);
+ foreach (const QString &var, values(args.first()))
+ foreach (const QString &splt, var.split(sep))
+ ret.append(splt);
+ }
+ break;
+ }
+ case E_MEMBER: {
+ if (args.count() < 1 || args.count() > 3) {
+ q->logMessage(format("member(var, start, end) requires three arguments."));
+ } else {
+ bool ok = true;
+ const QStringList var = values(args.first());
+ int start = 0, end = 0;
+ if (args.count() >= 2) {
+ QString start_str = args[1];
+ start = start_str.toInt(&ok);
+ if (!ok) {
+ if (args.count() == 2) {
+ int dotdot = start_str.indexOf(QLatin1String(".."));
+ if (dotdot != -1) {
+ start = start_str.left(dotdot).toInt(&ok);
+ if (ok)
+ end = start_str.mid(dotdot+2).toInt(&ok);
+ }
+ }
+ if (!ok)
+ q->logMessage(format("member() argument 2 (start) '%2' invalid.")
+ .arg(start_str));
+ } else {
+ end = start;
+ if (args.count() == 3)
+ end = args[2].toInt(&ok);
+ if (!ok)
+ q->logMessage(format("member() argument 3 (end) '%2' invalid.\n")
+ .arg(args[2]));
+ }
+ }
+ if (ok) {
+ if (start < 0)
+ start += var.count();
+ if (end < 0)
+ end += var.count();
+ if (start < 0 || start >= var.count() || end < 0 || end >= var.count()) {
+ //nothing
+ } else if (start < end) {
+ for (int i = start; i <= end && var.count() >= i; i++)
+ ret.append(var[i]);
+ } else {
+ for (int i = start; i >= end && var.count() >= i && i >= 0; i--)
+ ret += var[i];
+ }
+ }
+ }
+ break;
+ }
+ case E_FIRST:
+ case E_LAST: {
+ if (args.count() != 1) {
+ q->logMessage(format("%1(var) requires one argument.").arg(func));
+ } else {
+ const QStringList var = values(args.first());
+ if (!var.isEmpty()) {
+ if (func_t == E_FIRST)
+ ret.append(var[0]);
+ else
+ ret.append(var.last());
+ }
+ }
+ break;
+ }
+ case E_SYSTEM: {
+ if (m_condition) {
+ if (args.count() < 1 || args.count() > 2) {
+ q->logMessage(format("system(execute) requires one or two arguments."));
+ } else {
+ char buff[256];
+ FILE *proc = QT_POPEN(args[0].toLatin1(), "r");
+ bool singleLine = true;
+ if (args.count() > 1)
+ singleLine = (args[1].toLower() == QLatin1String("true"));
+ QString output;
+ while (proc && !feof(proc)) {
+ int read_in = int(fread(buff, 1, 255, proc));
+ if (!read_in)
+ break;
+ for (int i = 0; i < read_in; i++) {
+ if ((singleLine && buff[i] == '\n') || buff[i] == '\t')
+ buff[i] = ' ';
+ }
+ buff[read_in] = '\0';
+ output += QLatin1String(buff);
+ }
+ ret += split_value_list(output);
+ }
+ }
+ break; }
+ case E_QUOTE:
+ for (int i = 0; i < args.count(); ++i)
+ ret += QStringList(args.at(i));
+ break;
+ case 0:
+ q->logMessage(format("'%1' is not a function").arg(func));
+ break;
+ default:
+ q->logMessage(format("Function '%1' is not implemented").arg(func));
+ break;
+ }
+
+ return ret;
+}
+
+bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &function,
+ const QString &arguments, bool *result)
+{
+ QStringList argumentsList = split_arg_list(arguments);
+ QString sep;
+ sep.append(Option::field_sep);
+
+ QStringList args;
+ for (int i = 0; i < argumentsList.count(); ++i)
+ args += expandVariableReferences(argumentsList[i]).join(sep);
+
+ enum ConditionFunc { CF_CONFIG = 1, CF_CONTAINS, CF_COUNT, CF_EXISTS, CF_INCLUDE,
+ CF_LOAD, CF_ISEMPTY, CF_SYSTEM, CF_MESSAGE};
+
+ static QHash<QString, int> *functions = 0;
+ if (!functions) {
+ functions = new QHash<QString, int>;
+ functions->insert(QLatin1String("load"), CF_LOAD); //v
+ functions->insert(QLatin1String("include"), CF_INCLUDE); //v
+ functions->insert(QLatin1String("message"), CF_MESSAGE); //v
+ functions->insert(QLatin1String("warning"), CF_MESSAGE); //v
+ functions->insert(QLatin1String("error"), CF_MESSAGE); //v
+ }
+
+ bool cond = false;
+ bool ok = true;
+
+ ConditionFunc func_t = (ConditionFunc)functions->value(function);
+
+ switch (func_t) {
+ case CF_CONFIG: {
+ if (args.count() < 1 || args.count() > 2) {
+ q->logMessage(format("CONFIG(config) requires one or two arguments."));
+ ok = false;
+ break;
+ }
+ if (args.count() == 1) {
+ //cond = isActiveConfig(args.first());
+ break;
+ }
+ const QStringList mutuals = args[1].split(QLatin1Char('|'));
+ const QStringList &configs = m_valuemap.value(QLatin1String("CONFIG"));
+ for (int i = configs.size() - 1 && ok; i >= 0; i--) {
+ for (int mut = 0; mut < mutuals.count(); mut++) {
+ if (configs[i] == mutuals[mut].trimmed()) {
+ cond = (configs[i] == args[0]);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case CF_CONTAINS: {
+ if (args.count() < 2 || args.count() > 3) {
+ q->logMessage(format("contains(var, val) requires at least two arguments."));
+ ok = false;
+ break;
+ }
+
+ QRegExp regx(args[1]);
+ const QStringList &l = values(args.first());
+ if (args.count() == 2) {
+ for (int i = 0; i < l.size(); ++i) {
+ const QString val = l[i];
+ if (regx.exactMatch(val) || val == args[1]) {
+ cond = true;
+ break;
+ }
+ }
+ } else {
+ const QStringList mutuals = args[2].split(QLatin1Char('|'));
+ for (int i = l.size() - 1; i >= 0; i--) {
+ const QString val = l[i];
+ for (int mut = 0; mut < mutuals.count(); mut++) {
+ if (val == mutuals[mut].trimmed()) {
+ cond = (regx.exactMatch(val) || val == args[1]);
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ case CF_COUNT: {
+ if (args.count() != 2 && args.count() != 3) {
+ q->logMessage(format("count(var, count) requires at least two arguments."));
+ ok = false;
+ break;
+ }
+ if (args.count() == 3) {
+ QString comp = args[2];
+ if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
+ cond = values(args.first()).count() > args[1].toInt();
+ } else if (comp == QLatin1String(">=")) {
+ cond = values(args.first()).count() >= args[1].toInt();
+ } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
+ cond = values(args.first()).count() < args[1].toInt();
+ } else if (comp == QLatin1String("<=")) {
+ cond = values(args.first()).count() <= args[1].toInt();
+ } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") || comp == QLatin1String("=") || comp == QLatin1String("==")) {
+ cond = values(args.first()).count() == args[1].toInt();
+ } else {
+ ok = false;
+ q->logMessage(format("unexpected modifier to count(%2)").arg(comp));
+ }
+ break;
+ }
+ cond = values(args.first()).count() == args[1].toInt();
+ break;
+ }
+ case CF_INCLUDE: {
+ QString parseInto;
+ if (args.count() == 2) {
+ parseInto = args[1];
+ } else if (args.count() != 1) {
+ q->logMessage(format("include(file) requires one argument."));
+ ok = false;
+ break;
+ }
+ QString fileName = args.first();
+ // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style.
+ QDir currentProPath(getcwd());
+ fileName = QDir::cleanPath(currentProPath.absoluteFilePath(fileName));
+ ok = evaluateFile(fileName, &ok);
+ break;
+ }
+ case CF_LOAD: {
+ QString parseInto;
+ bool ignore_error = false;
+ if (args.count() == 2) {
+ QString sarg = args[1];
+ ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt());
+ } else if (args.count() != 1) {
+ q->logMessage(format("load(feature) requires one argument."));
+ ok = false;
+ break;
+ }
+ ok = evaluateFeatureFile( args.first(), &cond);
+ break;
+ }
+ case CF_MESSAGE: {
+ if (args.count() != 1) {
+ q->logMessage(format("%1(message) requires one argument.").arg(function));
+ ok = false;
+ break;
+ }
+ QString msg = args.first();
+ if (function == QLatin1String("error")) {
+ QStringList parents;
+ foreach (ProFile *proFile, m_profileStack)
+ parents.append(proFile->fileName());
+ if (!parents.isEmpty())
+ parents.takeLast();
+ if (parents.isEmpty())
+ q->fileMessage(format("Project ERROR: %1").arg(msg));
+ else
+ q->fileMessage(format("Project ERROR: %1. File was included from: '%2'")
+ .arg(msg).arg(parents.join(QLatin1String("', '"))));
+ } else {
+ q->fileMessage(format("Project MESSAGE: %1").arg(msg));
+ }
+ break;
+ }
+ case CF_SYSTEM: {
+ if (args.count() != 1) {
+ q->logMessage(format("system(exec) requires one argument."));
+ ok = false;
+ break;
+ }
+ ok = system(args.first().toLatin1().constData()) == 0;
+ break;
+ }
+ case CF_ISEMPTY: {
+ if (args.count() != 1) {
+ q->logMessage(format("isEmpty(var) requires one argument."));
+ ok = false;
+ break;
+ }
+ QStringList sl = values(args.first());
+ if (sl.count() == 0) {
+ cond = true;
+ } else if (sl.count() > 0) {
+ QString var = sl.first();
+ cond = (var.isEmpty());
+ }
+ break;
+ }
+ case CF_EXISTS: {
+ if (args.count() != 1) {
+ q->logMessage(format("exists(file) requires one argument."));
+ ok = false;
+ break;
+ }
+ QString file = args.first();
+
+ file = QDir::cleanPath(file);
+
+ if (QFile::exists(file)) {
+ cond = true;
+ break;
+ }
+ //regular expression I guess
+ QString dirstr = getcwd();
+ int slsh = file.lastIndexOf(Option::dir_sep);
+ if (slsh != -1) {
+ dirstr = file.left(slsh+1);
+ file = file.right(file.length() - slsh - 1);
+ }
+ cond = QDir(dirstr).entryList(QStringList(file)).count();
+
+ break;
+ }
+ }
+
+ if (result)
+ *result = cond;
+
+ return ok;
+}
+
+QStringList ProFileEvaluator::Private::values(const QString &variableName) const
+{
+ if (variableName == QLatin1String("TARGET")) {
+ QStringList list = m_valuemap.value(variableName);
+ if (!m_origfile.isEmpty())
+ list.append(QFileInfo(m_origfile).baseName());
+ return list;
+ }
+ if (variableName == QLatin1String("PWD")) {
+ return QStringList(getcwd());
+ }
+ return m_valuemap.value(variableName);
+}
+
+QStringList ProFileEvaluator::Private::values(const QString &variableName, const ProFile *pro) const
+{
+ if (variableName == QLatin1String("TARGET")) {
+ QStringList list = m_filevaluemap[pro].value(variableName);
+ if (!m_origfile.isEmpty())
+ list.append(QFileInfo(m_origfile).baseName());
+ return list;
+ }
+ if (variableName == QLatin1String("PWD")) {
+ return QStringList(QFileInfo(pro->fileName()).absoluteFilePath());
+ }
+ return m_filevaluemap[pro].value(variableName);
+}
+
+ProFile *ProFileEvaluator::parsedProFile(const QString &fileName)
+{
+ QFileInfo fi(fileName);
+ if (fi.exists()) {
+ logMessage(d->format("Reading %1\n").arg(fileName));
+ ProFile *pro = new ProFile(fi.absoluteFilePath());
+ if (d->read(pro))
+ return pro;
+ delete pro;
+ }
+ return 0;
+}
+
+void ProFileEvaluator::releaseParsedProFile(ProFile *proFile)
+{
+ delete proFile;
+}
+
+bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *result)
+{
+ bool ok = true;
+ ProFile *pro = q->parsedProFile(fileName);
+ if (pro) {
+ m_profileStack.push(pro);
+ ok = (currentProFile() ? pro->Accept(this) : false);
+ if (ok) {
+ if (m_profileStack.count() > 0) {
+ ProFile *pro = m_profileStack.pop();
+ q->releaseParsedProFile(pro);
+ }
+ }
+ if (result)
+ *result = true;
+ } else {
+ if (result)
+ *result = false;
+ }
+/* if (ok && readFeatures) {
+ QStringList configs = values("CONFIG");
+ QSet<QString> processed;
+ foreach (const QString &fn, configs) {
+ if (!processed.contains(fn)) {
+ processed.insert(fn);
+ evaluateFeatureFile(fn, 0);
+ }
+ }
+ } */
+
+ return ok;
+}
+
+bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, bool *result)
+{
+ QString fn;
+ foreach (const QString &path, qmakeFeaturePaths()) {
+ QString fname = path + QLatin1Char('/') + fileName;
+ if (QFileInfo(fname).exists()) {
+ fn = fname;
+ break;
+ }
+ fname += QLatin1String(".prf");
+ if (QFileInfo(fname).exists()) {
+ fn = fname;
+ break;
+ }
+ }
+ return fn.isEmpty() ? false : evaluateFile(fn, result);
+}
+
+void ProFileEvaluator::Private::expandPatternHelper(const QString &relName, const QString &absName,
+ QStringList &sources_out)
+{
+ const QStringList vpaths = values(QLatin1String("VPATH"))
+ + values(QLatin1String("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ + values(QLatin1String("DEPENDPATH"))
+ + values(QLatin1String("VPATH_SOURCES"));
+
+ QFileInfo fi(absName);
+ bool found = fi.exists();
+ // Search in all vpaths
+ if (!found) {
+ foreach (const QString &vpath, vpaths) {
+ fi.setFile(vpath + QDir::separator() + relName);
+ if (fi.exists()) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ sources_out += fi.absoluteFilePath(); // Not resolving symlinks
+ } else {
+ QString val = relName;
+ QString dir;
+ QString wildcard = val;
+ QString real_dir;
+ if (wildcard.lastIndexOf(QLatin1Char('/')) != -1) {
+ dir = wildcard.left(wildcard.lastIndexOf(QLatin1Char('/')) + 1);
+ real_dir = dir;
+ wildcard = wildcard.right(wildcard.length() - dir.length());
+ }
+
+ if (real_dir.isEmpty() || QFileInfo(real_dir).exists()) {
+ QStringList files = QDir(real_dir).entryList(QStringList(wildcard));
+ if (files.isEmpty()) {
+ q->logMessage(format("Failure to find %1").arg(val));
+ } else {
+ QString a;
+ for (int i = files.count() - 1; i >= 0; --i) {
+ if (files[i] == QLatin1String(".") || files[i] == QLatin1String(".."))
+ continue;
+ a = dir + files[i];
+ sources_out += a;
+ }
+ }
+ } else {
+ q->logMessage(format("Cannot match %1/%2, as %3 does not exist.")
+ .arg(real_dir).arg(wildcard).arg(real_dir));
+ }
+ }
+}
+
+
+/*
+ * Lookup of files are done in this order:
+ * 1. look in pwd
+ * 2. look in vpaths
+ * 3. expand wild card files relative from the profiles folder
+ **/
+
+// FIXME: This code supports something that I'd consider a flaw in .pro file syntax
+// which is not even documented. So arguably this can be ditched completely...
+QStringList ProFileEvaluator::Private::expandPattern(const QString& pattern)
+{
+ if (!currentProFile())
+ return QStringList();
+
+ QStringList sources_out;
+ const QString absName = QDir::cleanPath(QDir::current().absoluteFilePath(pattern));
+
+ expandPatternHelper(pattern, absName, sources_out);
+ return sources_out;
+}
+
+QString ProFileEvaluator::Private::format(const char *fmt) const
+{
+ ProFile *pro = currentProFile();
+ QString fileName = pro ? pro->fileName() : QLatin1String("Not a file");
+ int lineNumber = pro ? m_lineNo : 0;
+ return QString::fromLatin1("%1(%2):").arg(fileName).arg(lineNumber) + QString::fromAscii(fmt);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// ProFileEvaluator
+//
+///////////////////////////////////////////////////////////////////////
+
+ProFileEvaluator::ProFileEvaluator()
+ : d(new Private(this))
+{
+ Option::init();
+}
+
+ProFileEvaluator::~ProFileEvaluator()
+{
+ delete d;
+}
+
+bool ProFileEvaluator::contains(const QString &variableName) const
+{
+ return d->m_valuemap.contains(variableName);
+}
+
+QStringList ProFileEvaluator::values(const QString &variableName) const
+{
+ return d->values(variableName);
+}
+
+QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
+{
+ return d->values(variableName, pro);
+}
+
+ProFileEvaluator::TemplateType ProFileEvaluator::templateType()
+{
+ QStringList templ = d->m_valuemap.value(QLatin1String("TEMPLATE"));
+ if (templ.count() >= 1) {
+ QString t = templ.last().toLower();
+ if (t == QLatin1String("app"))
+ return TT_Application;
+ if (t == QLatin1String("lib"))
+ return TT_Library;
+ if (t == QLatin1String("script"))
+ return TT_Script;
+ if (t == QLatin1String("subdirs"))
+ return TT_Subdirs;
+ }
+ return TT_Unknown;
+}
+
+bool ProFileEvaluator::queryProFile(ProFile *pro)
+{
+ return d->read(pro);
+}
+
+bool ProFileEvaluator::accept(ProFile *pro)
+{
+ return pro->Accept(d);
+}
+
+QString ProFileEvaluator::propertyValue(const QString &name) const
+{
+ return d->propertyValue(name);
+}
+
+namespace {
+ template<class K, class T> void insert(QHash<K,T> *out, const QHash<K,T> &in)
+ {
+ typename QHash<K,T>::const_iterator i = in.begin();
+ while (i != in.end()) {
+ out->insert(i.key(), i.value());
+ ++i;
+ }
+ }
+} // anon namespace
+
+void ProFileEvaluator::addVariables(const QHash<QString, QStringList> &variables)
+{
+ insert(&(d->m_valuemap), variables);
+}
+
+void ProFileEvaluator::addProperties(const QHash<QString, QString> &properties)
+{
+ insert(&(d->m_properties), properties);
+}
+
+void ProFileEvaluator::logMessage(const QString &message)
+{
+ if (d->m_verbose)
+ qWarning("%s", qPrintable(message));
+}
+
+void ProFileEvaluator::fileMessage(const QString &message)
+{
+ qWarning("%s", qPrintable(message));
+}
+
+void ProFileEvaluator::errorMessage(const QString &message)
+{
+ qWarning("%s", qPrintable(message));
+}
+
+// This function is unneeded and still retained. See log message for reason.
+QStringList ProFileEvaluator::absFileNames(const QString &variableName)
+{
+ QStringList sources_out;
+ QFileInfo fi(d->m_origfile);
+ QDir dir(fi.absoluteDir());
+ foreach (const QString &fn, values(variableName)) {
+ const QString absName = QDir::cleanPath(dir.absoluteFilePath(fn));
+ d->expandPatternHelper(fn, absName, sources_out);
+ }
+
+ return sources_out;
+}
+
+void ProFileEvaluator::setVerbose(bool on)
+{
+ d->m_verbose = on;
+}
+
+bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap)
+{
+ QStringList sourceFiles;
+ QString codecForTr;
+ QString codecForSource;
+ QStringList tsFileNames;
+
+ QFileInfo fi(fileName);
+ QDir rootPath;
+ if (!fi.exists())
+ return false;
+
+ rootPath.setPath(fi.absolutePath());
+ ProFile pro(fi.absoluteFilePath());
+
+ ProFileEvaluator visitor;
+ visitor.setVerbose(verbose);
+
+ if (!visitor.queryProFile(&pro))
+ return false;
+
+ if (!visitor.accept(&pro))
+ return false;
+
+ // app/lib template
+ sourceFiles += visitor.values(QLatin1String("SOURCES"));
+ sourceFiles += visitor.values(QLatin1String("HEADERS"));
+ tsFileNames = visitor.values(QLatin1String("TRANSLATIONS"));
+ QStringList trcodec = visitor.values(QLatin1String("CODEC"))
+ + visitor.values(QLatin1String("DEFAULTCODEC"))
+ + visitor.values(QLatin1String("CODECFORTR"));
+
+ if (!trcodec.isEmpty())
+ codecForTr = trcodec.last();
+
+ QStringList srccodec = visitor.values(QLatin1String("CODECFORSRC"));
+ if (!srccodec.isEmpty())
+ codecForSource = srccodec.last();
+
+ QStringList forms = visitor.values(QLatin1String("INTERFACES"))
+ + visitor.values(QLatin1String("FORMS"))
+ + visitor.values(QLatin1String("FORMS3"));
+ sourceFiles << forms;
+
+#if QT_VERSION >= 0x040500
+ sourceFiles.sort();
+ sourceFiles.removeDuplicates();
+ tsFileNames.sort();
+ tsFileNames.removeDuplicates();
+#else
+ sourceFiles = sourceFiles.toSet().toList();
+ sourceFiles.sort();
+ tsFileNames = tsFileNames.toSet().toList();
+ tsFileNames.sort();
+#endif
+
+ varMap->insert("SOURCES", sourceFiles);
+ varMap->insert("CODECFORTR", QStringList() << codecForTr);
+ varMap->insert("CODECFORSRC", QStringList() << codecForSource);
+ varMap->insert("TRANSLATIONS", tsFileNames);
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/shared/proparser/profileevaluator.h b/shared/proparser/profileevaluator.h
new file mode 100644
index 0000000000..741f3db178
--- /dev/null
+++ b/shared/proparser/profileevaluator.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILEEVALUATOR_H
+#define PROFILEEVALUATOR_H
+
+#include "proitems.h"
+#include "abstractproitemvisitor.h"
+
+#include <QtCore/QIODevice>
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QStack>
+
+QT_BEGIN_NAMESPACE
+
+class ProFile;
+
+bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap);
+
+class ProFileEvaluator
+{
+public:
+ enum TemplateType {
+ TT_Unknown = 0,
+ TT_Application,
+ TT_Library,
+ TT_Script,
+ TT_Subdirs
+ };
+
+ ProFileEvaluator();
+ virtual ~ProFileEvaluator();
+
+ ProFileEvaluator::TemplateType templateType();
+ virtual bool contains(const QString &variableName) const;
+ QStringList absFileNames(const QString &variableName);
+ QStringList absFileName(const QString &name);
+ void setVerbose(bool on);
+
+ bool queryProFile(ProFile *pro);
+ bool accept(ProFile *pro);
+
+ void addVariables(const QHash<QString, QStringList> &variables);
+ void addProperties(const QHash<QString, QString> &properties);
+ QStringList values(const QString &variableName) const;
+ QStringList values(const QString &variableName, const ProFile *pro) const;
+ QString propertyValue(const QString &val) const;
+
+ // for our descendents
+ virtual ProFile *parsedProFile(const QString &fileName);
+ virtual void releaseParsedProFile(ProFile *proFile);
+ virtual void logMessage(const QString &msg);
+ virtual void errorMessage(const QString &msg); // .pro parse errors
+ virtual void fileMessage(const QString &msg); // error() and message() from .pro file
+
+private:
+ class Private;
+ Private *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // PROFILEEVALUATOR_H
+
diff --git a/shared/proparser/proiteminfo.cpp b/shared/proparser/proiteminfo.cpp
new file mode 100644
index 0000000000..40411c193b
--- /dev/null
+++ b/shared/proparser/proiteminfo.cpp
@@ -0,0 +1,239 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "proiteminfo.h"
+
+#include <QtCore/QFile>
+
+
+using namespace Qt4ProjectManager::Internal;
+
+ProItemInfo::ProItemInfo(ProItemInfoKind kind)
+ : m_kind(kind) { }
+
+ProItemInfo::ProItemInfoKind ProItemInfo::kind() const
+{
+ return m_kind;
+}
+
+void ProItemInfo::setId(const QString &id)
+{
+ m_id = id;
+}
+
+void ProItemInfo::setName(const QString &name)
+{
+ m_name = name;
+}
+
+void ProItemInfo::setDescription(const QString &desc)
+{
+ m_description = desc;
+}
+
+QString ProItemInfo::id() const
+{
+ return m_id;
+}
+
+QString ProItemInfo::name() const
+{
+ return m_name;
+}
+
+QString ProItemInfo::description() const
+{
+ return m_description;
+}
+
+ProScopeInfo::ProScopeInfo()
+ : ProItemInfo(ProItemInfo::Scope) { }
+
+ProValueInfo::ProValueInfo()
+ : ProItemInfo(ProItemInfo::Value) { }
+
+ProVariableInfo::ProVariableInfo()
+ : ProItemInfo(ProItemInfo::Variable)
+{
+ m_operator = ProVariable::SetOperator;
+}
+
+ProVariableInfo::~ProVariableInfo()
+{
+ qDeleteAll(m_values.values());
+}
+
+void ProVariableInfo::addValue(ProValueInfo *value)
+{
+ m_values.insert(value->id(), value);
+}
+
+void ProVariableInfo::setMultiple(bool multiple)
+{
+ m_multiple = multiple;
+}
+
+void ProVariableInfo::setDefaultOperator(ProVariable::VariableOperator op)
+{
+ m_operator = op;
+}
+
+
+ProValueInfo *ProVariableInfo::value(const QString &id) const
+{
+ return m_values.value(id, 0);
+}
+
+QList<ProValueInfo *> ProVariableInfo::values() const
+{
+ return m_values.values();
+}
+
+bool ProVariableInfo::multiple() const
+{
+ return m_multiple;
+}
+
+ProVariable::VariableOperator ProVariableInfo::defaultOperator() const
+{
+ return m_operator;
+}
+
+ProItemInfoManager::ProItemInfoManager(QObject *parent)
+ : QObject(parent)
+{
+ load(QLatin1String(":/proparser/proiteminfo.xml"));
+}
+
+ProItemInfoManager::~ProItemInfoManager()
+{
+ qDeleteAll(m_variables.values());
+ qDeleteAll(m_scopes.values());
+}
+
+void ProItemInfoManager::addVariable(ProVariableInfo *variable)
+{
+ m_variables.insert(variable->id(), variable);
+}
+
+void ProItemInfoManager::addScope(ProScopeInfo *scope)
+{
+ m_scopes.insert(scope->id(), scope);
+}
+
+ProVariableInfo *ProItemInfoManager::variable(const QString &id) const
+{
+ return m_variables.value(id, 0);
+}
+
+ProScopeInfo *ProItemInfoManager::scope(const QString &id) const
+{
+ return m_scopes.value(id, 0);
+}
+
+QList<ProScopeInfo *> ProItemInfoManager::scopes() const
+{
+ return m_scopes.values();
+}
+
+QList<ProVariableInfo *> ProItemInfoManager::variables() const
+{
+ return m_variables.values();
+}
+
+bool ProItemInfoManager::load(const QString &filename)
+{
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ QDomDocument doc;
+ if (!doc.setContent(&file))
+ return false;
+
+ QDomElement root = doc.documentElement();
+ if (root.nodeName() != QLatin1String("proiteminfo"))
+ return false;
+
+ QDomElement child = root.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("scope"))
+ readScope(child);
+ else if (child.nodeName() == QLatin1String("variable"))
+ readVariable(child);
+ }
+
+ file.close();
+ return true;
+}
+
+void ProItemInfoManager::readItem(ProItemInfo *item, const QDomElement &data)
+{
+ QDomElement child = data.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("id"))
+ item->setId(child.text());
+ else if (child.nodeName() == QLatin1String("name"))
+ item->setName(child.text());
+ else if (child.nodeName() == QLatin1String("description"))
+ item->setDescription(child.text());
+ }
+}
+
+void ProItemInfoManager::readScope(const QDomElement &data)
+{
+ ProScopeInfo *scope = new ProScopeInfo();
+ readItem(scope, data);
+ addScope(scope);
+}
+
+void ProItemInfoManager::readVariable(const QDomElement &data)
+{
+ ProVariableInfo *var = new ProVariableInfo();
+ readItem(var, data);
+
+ var->setMultiple(data.attribute(QLatin1String("multiple"), QLatin1String("false")) == QLatin1String("true"));
+ var->setDefaultOperator((ProVariable::VariableOperator)data.attribute(QLatin1String("operator"),
+ QLatin1String("3")).toInt());
+
+ QDomElement child = data.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("value")) {
+ ProValueInfo *val = new ProValueInfo();
+ readItem(val, child);
+ var->addValue(val);
+ }
+ }
+
+ addVariable(var);
+}
+
diff --git a/shared/proparser/proiteminfo.h b/shared/proparser/proiteminfo.h
new file mode 100644
index 0000000000..18045dd388
--- /dev/null
+++ b/shared/proparser/proiteminfo.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROITEMINFO_H
+#define PROITEMINFO_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtXml/QDomElement>
+
+#include "proitems.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProItemInfo {
+public:
+ enum ProItemInfoKind {
+ Scope,
+ Value,
+ Variable
+ };
+
+ ProItemInfo(ProItemInfoKind kind);
+
+ ProItemInfoKind kind() const;
+ void setId(const QString &id);
+ void setName(const QString &name);
+ void setDescription(const QString &desc);
+
+ QString id() const;
+ QString name() const;
+ QString description() const;
+
+private:
+ QString m_id;
+ QString m_name;
+ QString m_description;
+ ProItemInfoKind m_kind;
+};
+
+class ProScopeInfo : public ProItemInfo {
+public:
+ ProScopeInfo();
+};
+
+class ProValueInfo : public ProItemInfo {
+public:
+ ProValueInfo();
+};
+
+class ProVariableInfo : public ProItemInfo {
+public:
+ ProVariableInfo();
+ ~ProVariableInfo();
+
+ void addValue(ProValueInfo *value);
+ void setMultiple(bool multiple);
+ void setDefaultOperator(ProVariable::VariableOperator op);
+
+ ProValueInfo *value(const QString &id) const;
+
+ QList<ProValueInfo *> values() const;
+ bool multiple() const;
+ ProVariable::VariableOperator defaultOperator() const;
+
+private:
+ ProVariable::VariableOperator m_operator;
+ bool m_multiple;
+ QMap<QString, ProValueInfo *> m_values;
+};
+
+class ProItemInfoManager : public QObject {
+ Q_OBJECT
+
+public:
+ ProItemInfoManager(QObject *parent);
+ ~ProItemInfoManager();
+
+ ProVariableInfo *variable(const QString &id) const;
+ ProScopeInfo *scope(const QString &id) const;
+
+ QList<ProScopeInfo *> scopes() const;
+ QList<ProVariableInfo *> variables() const;
+
+private:
+ bool load(const QString &filename);
+ void addVariable(ProVariableInfo *variable);
+ void addScope(ProScopeInfo *scope);
+ void readItem(ProItemInfo *item, const QDomElement &data);
+ void readScope(const QDomElement &data);
+ void readVariable(const QDomElement &data);
+
+ QMap<QString, ProScopeInfo *> m_scopes;
+ QMap<QString, ProVariableInfo *> m_variables;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //PROITEMINFO_H
diff --git a/shared/proparser/proiteminfo.xml b/shared/proparser/proiteminfo.xml
new file mode 100644
index 0000000000..1425c37150
--- /dev/null
+++ b/shared/proparser/proiteminfo.xml
@@ -0,0 +1,110 @@
+<!DOCTYPE ProItemInfo>
+<proiteminfo>
+ <scope>
+ <id>win32</id>
+ <name>Windows</name>
+ </scope>
+
+ <scope>
+ <id>unix</id>
+ <name>Unix</name>
+ </scope>
+
+ <scope>
+ <id>mac</id>
+ <name>Mac</name>
+ </scope>
+
+ <variable multiple="false">
+ <id>TARGET</id>
+ <name>Output Target</name>
+ <description>This specifies the name of the target file.</description>
+ </variable>
+
+ <variable multiple="false">
+ <id>TEMPLATE</id>
+ <name>Output Template</name>
+ <description>This variable contains the name of the template to use when generating the project.</description>
+ <value>
+ <id>app</id>
+ <name>Application</name>
+ </value>
+ <value>
+ <id>lib</id>
+ <name>Library</name>
+ </value>
+ <value>
+ <id>subdirs</id>
+ <name>Subdirectories</name>
+ </value>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>HEADERS</id>
+ <name>Header Files</name>
+ <description>Defines the header files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>SOURCES</id>
+ <name>Source Files</name>
+ <description>Defines the source files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>INCLUDEPATH</id>
+ <name>Include Path</name>
+ <description>Defines the include path for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>FORMS</id>
+ <name>Form Files</name>
+ <description>Defines the form files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>RESOURCES</id>
+ <name>Resource Files</name>
+ <description>Defines the resource files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>QT</id>
+ <name>Qt Modules</name>
+ <description>The values stored in the QT variable control which of the Qt modules are used by your project.</description>
+ <value>
+ <id>core</id>
+ <name>QtCore module</name>
+ </value>
+ <value>
+ <id>gui</id>
+ <name>QtGui module</name>
+ </value>
+ <value>
+ <id>network</id>
+ <name>QtNetwork module</name>
+ </value>
+ <value>
+ <id>opengl</id>
+ <name>QtOpenGL module</name>
+ </value>
+ <value>
+ <id>sql</id>
+ <name>QtSql module</name>
+ </value>
+ <value>
+ <id>svg</id>
+ <name>QtSvg module</name>
+ </value>
+ <value>
+ <id>xml</id>
+ <name>QtXml module</name>
+ </value>
+ <value>
+ <id>qt3support</id>
+ <name>Qt3Support module</name>
+ </value>
+ </variable>
+
+</proiteminfo>
diff --git a/shared/proparser/proitems.cpp b/shared/proparser/proitems.cpp
new file mode 100644
index 0000000000..22aabba8f6
--- /dev/null
+++ b/shared/proparser/proitems.cpp
@@ -0,0 +1,314 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+#include "proitems.h"
+#include "abstractproitemvisitor.h"
+
+QT_BEGIN_NAMESPACE
+// --------------- ProItem ------------
+void ProItem::setComment(const QString &comment)
+{
+ m_comment = comment;
+}
+
+QString ProItem::comment() const
+{
+ return m_comment;
+}
+
+// --------------- ProBlock ----------------
+ProBlock::ProBlock(ProBlock *parent)
+{
+ m_blockKind = 0;
+ m_parent = parent;
+}
+
+ProBlock::~ProBlock()
+{
+ qDeleteAll(m_proitems);
+}
+
+void ProBlock::appendItem(ProItem *proitem)
+{
+ m_proitems << proitem;
+}
+
+void ProBlock::setItems(const QList<ProItem *> &proitems)
+{
+ m_proitems = proitems;
+}
+
+QList<ProItem *> ProBlock::items() const
+{
+ return m_proitems;
+}
+
+void ProBlock::setBlockKind(int blockKind)
+{
+ m_blockKind = blockKind;
+}
+
+int ProBlock::blockKind() const
+{
+ return m_blockKind;
+}
+
+void ProBlock::setParent(ProBlock *parent)
+{
+ m_parent = parent;
+}
+
+ProBlock *ProBlock::parent() const
+{
+ return m_parent;
+}
+
+ProItem::ProItemKind ProBlock::kind() const
+{
+ return ProItem::BlockKind;
+}
+
+bool ProBlock::Accept(AbstractProItemVisitor *visitor)
+{
+ visitor->visitBeginProBlock(this);
+ foreach (ProItem *item, m_proitems) {
+ if (!item->Accept(visitor))
+ return false;
+ }
+ return visitor->visitEndProBlock(this);
+}
+
+// --------------- ProVariable ----------------
+ProVariable::ProVariable(const QString &name, ProBlock *parent)
+ : ProBlock(parent)
+{
+ setBlockKind(ProBlock::VariableKind);
+ m_variable = name;
+ m_variableKind = SetOperator;
+}
+
+void ProVariable::setVariableOperator(VariableOperator variableKind)
+{
+ m_variableKind = variableKind;
+}
+
+ProVariable::VariableOperator ProVariable::variableOperator() const
+{
+ return m_variableKind;
+}
+
+void ProVariable::setVariable(const QString &name)
+{
+ m_variable = name;
+}
+
+QString ProVariable::variable() const
+{
+ return m_variable;
+}
+
+bool ProVariable::Accept(AbstractProItemVisitor *visitor)
+{
+ visitor->visitBeginProVariable(this);
+ foreach (ProItem *item, m_proitems) {
+ if (!item->Accept(visitor))
+ return false;
+ }
+ return visitor->visitEndProVariable(this);
+}
+
+// --------------- ProValue ----------------
+ProValue::ProValue(const QString &value, ProVariable *variable)
+{
+ m_variable = variable;
+ m_value = value;
+}
+
+void ProValue::setValue(const QString &value)
+{
+ m_value = value;
+}
+
+QString ProValue::value() const
+{
+ return m_value;
+}
+
+void ProValue::setVariable(ProVariable *variable)
+{
+ m_variable = variable;
+}
+
+ProVariable *ProValue::variable() const
+{
+ return m_variable;
+}
+
+ProItem::ProItemKind ProValue::kind() const
+{
+ return ProItem::ValueKind;
+}
+
+bool ProValue::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProValue(this);
+}
+
+// --------------- ProFunction ----------------
+ProFunction::ProFunction(const QString &text)
+{
+ m_text = text;
+}
+
+void ProFunction::setText(const QString &text)
+{
+ m_text = text;
+}
+
+QString ProFunction::text() const
+{
+ return m_text;
+}
+
+ProItem::ProItemKind ProFunction::kind() const
+{
+ return ProItem::FunctionKind;
+}
+
+bool ProFunction::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProFunction(this);
+}
+
+// --------------- ProCondition ----------------
+ProCondition::ProCondition(const QString &text)
+{
+ m_text = text;
+}
+
+void ProCondition::setText(const QString &text)
+{
+ m_text = text;
+}
+
+QString ProCondition::text() const
+{
+ return m_text;
+}
+
+ProItem::ProItemKind ProCondition::kind() const
+{
+ return ProItem::ConditionKind;
+}
+
+bool ProCondition::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProCondition(this);
+}
+
+// --------------- ProOperator ----------------
+ProOperator::ProOperator(OperatorKind operatorKind)
+{
+ m_operatorKind = operatorKind;
+}
+
+void ProOperator::setOperatorKind(OperatorKind operatorKind)
+{
+ m_operatorKind = operatorKind;
+}
+
+ProOperator::OperatorKind ProOperator::operatorKind() const
+{
+ return m_operatorKind;
+}
+
+ProItem::ProItemKind ProOperator::kind() const
+{
+ return ProItem::OperatorKind;
+}
+
+bool ProOperator::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProOperator(this);
+}
+
+// --------------- ProFile ----------------
+ProFile::ProFile(const QString &fileName)
+ : ProBlock(0)
+{
+ m_modified = false;
+ setBlockKind(ProBlock::ProFileKind);
+ m_fileName = fileName;
+
+ QFileInfo fi(fileName);
+ m_displayFileName = fi.fileName();
+}
+
+ProFile::~ProFile()
+{
+
+}
+
+QString ProFile::displayFileName() const
+{
+ return m_displayFileName;
+}
+
+QString ProFile::fileName() const
+{
+ return m_fileName;
+}
+
+void ProFile::setModified(bool modified)
+{
+ m_modified = modified;
+}
+
+bool ProFile::isModified() const
+{
+ return m_modified;
+}
+
+bool ProFile::Accept(AbstractProItemVisitor *visitor)
+{
+ visitor->visitBeginProFile(this);
+ foreach (ProItem *item, m_proitems) {
+ if (!item->Accept(visitor))
+ return false;
+ }
+ return visitor->visitEndProFile(this);
+}
+
+QT_END_NAMESPACE
diff --git a/shared/proparser/proitems.h b/shared/proparser/proitems.h
new file mode 100644
index 0000000000..776a833534
--- /dev/null
+++ b/shared/proparser/proitems.h
@@ -0,0 +1,226 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROITEMS_H
+#define PROITEMS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+struct AbstractProItemVisitor;
+
+class ProItem
+{
+public:
+ ProItem()
+ : m_lineNumber(0)
+ {}
+ enum ProItemKind {
+ ValueKind,
+ FunctionKind,
+ ConditionKind,
+ OperatorKind,
+ BlockKind
+ };
+ virtual ~ProItem() {}
+
+ virtual ProItemKind kind() const = 0;
+
+ void setComment(const QString &comment);
+ QString comment() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor) = 0;
+ int lineNumber() const { return m_lineNumber; }
+ void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; }
+
+private:
+ QString m_comment;
+ int m_lineNumber;
+};
+
+class ProBlock : public ProItem
+{
+public:
+ enum ProBlockKind {
+ NormalKind = 0x00,
+ ScopeKind = 0x01,
+ ScopeContentsKind = 0x02,
+ VariableKind = 0x04,
+ ProFileKind = 0x08,
+ SingleLine = 0x10
+ };
+
+ ProBlock(ProBlock *parent);
+ ~ProBlock();
+
+ void appendItem(ProItem *proitem);
+ void setItems(const QList<ProItem *> &proitems);
+ QList<ProItem *> items() const;
+
+ void setBlockKind(int blockKind);
+ int blockKind() const;
+
+ void setParent(ProBlock *parent);
+ ProBlock *parent() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+protected:
+ QList<ProItem *> m_proitems;
+private:
+ ProBlock *m_parent;
+ int m_blockKind;
+};
+
+class ProVariable : public ProBlock
+{
+public:
+ enum VariableOperator {
+ AddOperator = 0,
+ RemoveOperator = 1,
+ ReplaceOperator = 2,
+ SetOperator = 3,
+ UniqueAddOperator = 4
+ };
+
+ ProVariable(const QString &name, ProBlock *parent);
+
+ void setVariableOperator(VariableOperator variableKind);
+ VariableOperator variableOperator() const;
+
+ void setVariable(const QString &name);
+ QString variable() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ VariableOperator m_variableKind;
+ QString m_variable;
+};
+
+class ProValue : public ProItem
+{
+public:
+ ProValue(const QString &value, ProVariable *variable);
+
+ void setValue(const QString &value);
+ QString value() const;
+
+ void setVariable(ProVariable *variable);
+ ProVariable *variable() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ QString m_value;
+ ProVariable *m_variable;
+};
+
+class ProFunction : public ProItem
+{
+public:
+ explicit ProFunction(const QString &text);
+
+ void setText(const QString &text);
+ QString text() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ QString m_text;
+};
+
+class ProCondition : public ProItem
+{
+public:
+ explicit ProCondition(const QString &text);
+
+ void setText(const QString &text);
+ QString text() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ QString m_text;
+};
+
+class ProOperator : public ProItem
+{
+public:
+ enum OperatorKind {
+ OrOperator = 1,
+ NotOperator = 2
+ };
+
+ explicit ProOperator(OperatorKind operatorKind);
+
+ void setOperatorKind(OperatorKind operatorKind);
+ OperatorKind operatorKind() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ OperatorKind m_operatorKind;
+};
+
+class ProFile : public QObject, public ProBlock
+{
+ Q_OBJECT
+
+public:
+ explicit ProFile(const QString &fileName);
+ ~ProFile();
+
+ QString displayFileName() const;
+ QString fileName() const;
+
+ void setModified(bool modified);
+ bool isModified() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+
+private:
+ QString m_fileName;
+ QString m_displayFileName;
+ bool m_modified;
+};
+
+QT_END_NAMESPACE
+
+#endif // PROITEMS_H
diff --git a/shared/proparser/proparser.pri b/shared/proparser/proparser.pri
new file mode 100644
index 0000000000..78b43d5901
--- /dev/null
+++ b/shared/proparser/proparser.pri
@@ -0,0 +1,35 @@
+VPATH += $$PWD
+QT += xml
+
+INCLUDEPATH *= $$PWD $$PWD/..
+
+# Input
+HEADERS += \
+ abstractproitemvisitor.h \
+ procommandmanager.h \
+ proeditor.h \
+ proeditormodel.h \
+ profileevaluator.h \
+ proiteminfo.h \
+ proitems.h \
+ proparserutils.h \
+ prowriter.h \
+ proxml.h \
+ valueeditor.h \
+ $$PWD/../namespace_global.h
+
+SOURCES += \
+ procommandmanager.cpp \
+ proeditor.cpp \
+ proeditormodel.cpp \
+ profileevaluator.cpp \
+ proiteminfo.cpp \
+ proitems.cpp \
+ prowriter.cpp \
+ proxml.cpp \
+ valueeditor.cpp
+
+FORMS += proeditor.ui \
+ valueeditor.ui
+
+RESOURCES += proparser.qrc
diff --git a/shared/proparser/proparser.qrc b/shared/proparser/proparser.qrc
new file mode 100644
index 0000000000..e6dde343df
--- /dev/null
+++ b/shared/proparser/proparser.qrc
@@ -0,0 +1,12 @@
+<RCC>
+ <qresource prefix="/proparser" >
+ <file>images/profile.png</file>
+ <file>images/scope.png</file>
+ <file>images/value.png</file>
+ <file>images/other.png</file>
+ <file>images/set.png</file>
+ <file>images/append.png</file>
+ <file>images/remove.png</file>
+ <file>proiteminfo.xml</file>
+ </qresource>
+</RCC>
diff --git a/shared/proparser/proparserutils.h b/shared/proparser/proparserutils.h
new file mode 100644
index 0000000000..03a767cac1
--- /dev/null
+++ b/shared/proparser/proparserutils.h
@@ -0,0 +1,275 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROPARSERUTILS_H
+#define PROPARSERUTILS_H
+
+#include <QtCore/QDir>
+#include <QtCore/QLibraryInfo>
+
+QT_BEGIN_NAMESPACE
+
+// Pre- and postcondition macros
+#define PRE(cond) do {if(!(cond))qt_assert(#cond,__FILE__,__LINE__);} while (0)
+#define POST(cond) do {if(!(cond))qt_assert(#cond,__FILE__,__LINE__);} while (0)
+
+// This struct is from qmake, but we are not using everything.
+struct Option
+{
+ //simply global convenience
+ //static QString libtool_ext;
+ //static QString pkgcfg_ext;
+ //static QString prf_ext;
+ //static QString prl_ext;
+ //static QString ui_ext;
+ //static QStringList h_ext;
+ //static QStringList cpp_ext;
+ //static QString h_moc_ext;
+ //static QString cpp_moc_ext;
+ //static QString obj_ext;
+ //static QString lex_ext;
+ //static QString yacc_ext;
+ //static QString h_moc_mod;
+ //static QString cpp_moc_mod;
+ //static QString lex_mod;
+ //static QString yacc_mod;
+ static QString dir_sep;
+ static QString dirlist_sep;
+ static QString qmakespec;
+ static QChar field_sep;
+
+ enum TARG_MODE { TARG_UNIX_MODE, TARG_WIN_MODE, TARG_MACX_MODE, TARG_MAC9_MODE, TARG_QNX6_MODE };
+ static TARG_MODE target_mode;
+ //static QString pro_ext;
+ //static QString res_ext;
+
+ static void init()
+ {
+#ifdef Q_OS_WIN
+ Option::dirlist_sep = QLatin1Char(';');
+ Option::dir_sep = QLatin1Char('\\');
+#else
+ Option::dirlist_sep = QLatin1Char(':');
+ Option::dir_sep = QLatin1Char(QLatin1Char('/'));
+#endif
+ Option::qmakespec = QString::fromLatin1(qgetenv("QMAKESPEC").data());
+ Option::field_sep = QLatin1Char(' ');
+ }
+};
+#if defined(Q_OS_WIN32)
+Option::TARG_MODE Option::target_mode = Option::TARG_WIN_MODE;
+#elif defined(Q_OS_MAC)
+Option::TARG_MODE Option::target_mode = Option::TARG_MACX_MODE;
+#elif defined(Q_OS_QNX6)
+Option::TARG_MODE Option::target_mode = Option::TARG_QNX6_MODE;
+#else
+Option::TARG_MODE Option::target_mode = Option::TARG_UNIX_MODE;
+#endif
+
+QString Option::qmakespec;
+QString Option::dirlist_sep;
+QString Option::dir_sep;
+QChar Option::field_sep;
+
+static void unquote(QString *string)
+{
+ PRE(string);
+ if ( (string->startsWith(QLatin1Char('\"')) && string->endsWith(QLatin1Char('\"')))
+ || (string->startsWith(QLatin1Char('\'')) && string->endsWith(QLatin1Char('\''))) )
+ {
+ string->remove(0,1);
+ string->remove(string->length() - 1,1);
+ }
+}
+
+static void insertUnique(QHash<QString, QStringList> *map,
+ const QString &key, const QStringList &value, bool unique = true)
+{
+ QStringList &sl = (*map)[key];
+ if (!unique) {
+ sl += value;
+ } else {
+ for (int i = 0; i < value.count(); ++i) {
+ if (!sl.contains(value.at(i)))
+ sl.append(value.at(i));
+ }
+ }
+}
+
+/*
+ See ProFileEvaluator::Private::visitProValue(...)
+
+static QStringList replaceInList(const QStringList &varList, const QRegExp &regexp,
+ const QString &replace, bool global)
+{
+ QStringList resultList = varList;
+
+ for (QStringList::Iterator varit = resultList.begin(); varit != resultList.end();) {
+ if (varit->contains(regexp)) {
+ *varit = varit->replace(regexp, replace);
+ if (varit->isEmpty())
+ varit = resultList.erase(varit);
+ else
+ ++varit;
+ if (!global)
+ break;
+ } else {
+ ++varit;
+ }
+ }
+ return resultList;
+}
+*/
+
+inline QStringList splitPathList(const QString paths)
+{
+ return paths.split(Option::dirlist_sep);
+}
+
+static QStringList split_arg_list(QString params)
+{
+ int quote = 0;
+ QStringList args;
+
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort SINGLEQUOTE = '\'';
+ const ushort DOUBLEQUOTE = '"';
+ const ushort COMMA = ',';
+ const ushort SPACE = ' ';
+ //const ushort TAB = '\t';
+
+ ushort unicode;
+ const QChar *params_data = params.data();
+ const int params_len = params.length();
+ int last = 0;
+ while(last < params_len && ((params_data+last)->unicode() == SPACE
+ /*|| (params_data+last)->unicode() == TAB*/))
+ ++last;
+ for(int x = last, parens = 0; x <= params_len; x++) {
+ unicode = (params_data+x)->unicode();
+ if(x == params_len) {
+ while(x && (params_data+(x-1))->unicode() == SPACE)
+ --x;
+ QString mid(params_data+last, x-last);
+ if(quote) {
+ if(mid[0] == quote && mid[(int)mid.length()-1] == quote)
+ mid = mid.mid(1, mid.length()-2);
+ quote = 0;
+ }
+ args << mid;
+ break;
+ }
+ if(unicode == LPAREN) {
+ --parens;
+ } else if(unicode == RPAREN) {
+ ++parens;
+ } else if(quote && unicode == quote) {
+ quote = 0;
+ } else if(!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) {
+ quote = unicode;
+ } else if(!parens && !quote && unicode == COMMA) {
+ QString mid = params.mid(last, x - last).trimmed();
+ args << mid;
+ last = x+1;
+ while(last < params_len && ((params_data+last)->unicode() == SPACE
+ /*|| (params_data+last)->unicode() == TAB*/))
+ ++last;
+ }
+ }
+ for(int i = 0; i < args.count(); i++)
+ unquote(&args[i]);
+ return args;
+}
+
+static QStringList split_value_list(const QString &vals, bool do_semicolon=false)
+{
+ QString build;
+ QStringList ret;
+ QStack<QChar> quote;
+
+ const QChar LPAREN = QLatin1Char('(');
+ const QChar RPAREN = QLatin1Char(')');
+ const QChar SINGLEQUOTE = QLatin1Char('\'');
+ const QChar DOUBLEQUOTE = QLatin1Char('"');
+ const QChar BACKSLASH = QLatin1Char('\\');
+ const QChar SEMICOLON = QLatin1Char(';');
+
+ const QChar *vals_data = vals.data();
+ const int vals_len = vals.length();
+ for(int x = 0, parens = 0; x < vals_len; x++) {
+ QChar c = vals_data[x];
+ if (x != vals_len-1 && c == BACKSLASH &&
+ vals_data[x+1].unicode() == '\'' || vals_data[x+1] == DOUBLEQUOTE) {
+ build += vals_data[x++]; // get that 'escape'
+ } else if (!quote.isEmpty() && c == quote.top()) {
+ quote.pop();
+ } else if(c == SINGLEQUOTE || c == DOUBLEQUOTE) {
+ quote.push(c);
+ } else if(c == RPAREN) {
+ --parens;
+ } else if(c == LPAREN) {
+ ++parens;
+ }
+
+ if(!parens && quote.isEmpty() && ((do_semicolon && c == SEMICOLON) ||
+ vals_data[x] == Option::field_sep)) {
+ ret << build;
+ build.clear();
+ } else {
+ build += vals_data[x];
+ }
+ }
+ if(!build.isEmpty())
+ ret << build;
+ return ret;
+}
+
+static QStringList qmake_mkspec_paths()
+{
+ QStringList ret;
+ const QString concat = QDir::separator() + QString(QLatin1String("mkspecs"));
+ QByteArray qmakepath = qgetenv("QMAKEPATH");
+ if (!qmakepath.isEmpty()) {
+ const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
+ for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it)
+ ret << ((*it) + concat);
+ }
+ ret << QLibraryInfo::location(QLibraryInfo::DataPath) + concat;
+
+ return ret;
+}
+
+QT_END_NAMESPACE
+
+#endif // PROPARSERUTILS_H
+
diff --git a/shared/proparser/prowriter.cpp b/shared/proparser/prowriter.cpp
new file mode 100644
index 0000000000..aa00600e1e
--- /dev/null
+++ b/shared/proparser/prowriter.cpp
@@ -0,0 +1,207 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QFile>
+
+#include "proitems.h"
+#include "prowriter.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+bool ProWriter::write(ProFile *profile, const QString &fileName)
+{
+ QFile data(fileName);
+ if (!data.open(QFile::WriteOnly|QFile::Text))
+ return false;
+
+ m_writeState = 0;
+ m_comment.clear();
+ m_out.setDevice(&data);
+ writeItem(profile, QString());
+ data.close();
+
+ return true;
+}
+
+QString ProWriter::contents(ProFile *profile)
+{
+ QString result;
+
+ m_writeState = 0;
+ m_comment.clear();
+ m_out.setString(&result, QIODevice::WriteOnly);
+ writeItem(profile, QString());
+
+ return result;
+}
+
+QString ProWriter::fixComment(const QString &comment, const QString &indent) const
+{
+ QString result = comment;
+ result = result.replace(QLatin1Char('\n'),
+ QLatin1Char('\n') + indent + QLatin1String("# "));
+ return QLatin1String("# ") + result;
+}
+
+void ProWriter::writeValue(ProValue *value, const QString &indent)
+{
+ if (m_writeState & NewLine) {
+ m_out << indent << QLatin1String(" ");
+ m_writeState &= ~NewLine;
+ }
+
+ m_out << value->value();
+
+ if (!(m_writeState & LastItem))
+ m_out << QLatin1String(" \\");
+
+ if (!value->comment().isEmpty())
+ m_out << QLatin1Char(' ') << fixComment(value->comment(), indent);
+
+ m_out << endl;
+ m_writeState |= NewLine;
+}
+
+void ProWriter::writeOther(ProItem *item, const QString &indent)
+{
+ if (m_writeState & NewLine) {
+ m_out << indent;
+ m_writeState &= ~NewLine;
+ }
+
+ if (item->kind() == ProItem::FunctionKind) {
+ ProFunction *v = static_cast<ProFunction*>(item);
+ m_out << v->text();
+ } else if (item->kind() == ProItem::ConditionKind) {
+ ProCondition *v = static_cast<ProCondition*>(item);
+ m_out << v->text();
+ } else if (item->kind() == ProItem::OperatorKind) {
+ ProOperator *v = static_cast<ProOperator*>(item);
+ if (v->operatorKind() == ProOperator::OrOperator)
+ m_out << QLatin1Char('|');
+ else
+ m_out << QLatin1Char('!');
+ }
+
+ if (!item->comment().isEmpty()) {
+ if (!m_comment.isEmpty())
+ m_comment += QLatin1Char('\n');
+ m_comment += item->comment();
+ }
+}
+
+void ProWriter::writeBlock(ProBlock *block, const QString &indent)
+{
+ if (m_writeState & NewLine) {
+ m_out << indent;
+ m_writeState &= ~NewLine;
+ }
+
+ if (!block->comment().isEmpty()) {
+ if (!(m_writeState & FirstItem))
+ m_out << endl << indent;
+ m_out << fixComment(block->comment(), indent) << endl << indent;
+ }
+
+ QString newindent = indent;
+ if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *v = static_cast<ProVariable*>(block);
+ m_out << v->variable();
+ switch(v->variableOperator()) {
+ case ProVariable::AddOperator:
+ m_out << QLatin1String(" += "); break;
+ case ProVariable::RemoveOperator:
+ m_out << QLatin1String(" -= "); break;
+ case ProVariable::ReplaceOperator:
+ m_out << QLatin1String(" ~= "); break;
+ case ProVariable::SetOperator:
+ m_out << QLatin1String(" = "); break;
+ case ProVariable::UniqueAddOperator:
+ m_out << QLatin1String(" *= "); break;
+ }
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ if (block->items().count() > 1) {
+ newindent = indent + QLatin1String(" ");
+ m_out << QLatin1String(" { ");
+ if (!m_comment.isEmpty()) {
+ m_out << fixComment(m_comment, indent);
+ m_comment.clear();
+ }
+ m_out << endl;
+ m_writeState |= NewLine;
+ } else {
+ m_out << QLatin1Char(':');
+ }
+ }
+
+ QList<ProItem*> items = block->items();
+ for (int i=0; i<items.count(); ++i) {
+ m_writeState &= ~LastItem;
+ m_writeState &= ~FirstItem;
+ if (i == 0)
+ m_writeState |= FirstItem;
+ if (i == (items.count()-1))
+ m_writeState |= LastItem;
+ writeItem(items.at(i), newindent);
+ }
+
+ if ((block->blockKind() & ProBlock::ScopeContentsKind) && (block->items().count() > 1)) {
+ if (m_writeState & NewLine) {
+ m_out << indent;
+ m_writeState &= ~NewLine;
+ }
+ m_out << QLatin1Char('}');
+ }
+
+ if (!m_comment.isEmpty()) {
+ m_out << fixComment(m_comment, indent);
+ m_out << endl;
+ m_writeState |= NewLine;
+ m_comment.clear();
+ }
+
+ if (!(m_writeState & NewLine)) {
+ m_out << endl;
+ m_writeState |= NewLine;
+ }
+}
+
+void ProWriter::writeItem(ProItem *item, const QString &indent)
+{
+ if (item->kind() == ProItem::ValueKind) {
+ writeValue(static_cast<ProValue*>(item), indent);
+ } else if (item->kind() == ProItem::BlockKind) {
+ writeBlock(static_cast<ProBlock*>(item), indent);
+ } else {
+ writeOther(item, indent);
+ }
+}
diff --git a/shared/proparser/prowriter.h b/shared/proparser/prowriter.h
new file mode 100644
index 0000000000..f6f7d05ebc
--- /dev/null
+++ b/shared/proparser/prowriter.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROWRITER_H
+#define PROWRITER_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QTextStream>
+
+QT_FORWARD_DECLARE_CLASS(ProFile)
+QT_FORWARD_DECLARE_CLASS(ProValue)
+QT_FORWARD_DECLARE_CLASS(ProItem)
+QT_FORWARD_DECLARE_CLASS(ProBlock)
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProWriter {
+public:
+ bool write(ProFile *profile, const QString &fileName);
+ QString contents(ProFile *profile);
+
+protected:
+ QString fixComment(const QString &comment, const QString &indent) const;
+ void writeValue(ProValue *value, const QString &indent);
+ void writeOther(ProItem *item, const QString &indent);
+ void writeBlock(ProBlock *block, const QString &indent);
+ void writeItem(ProItem *item, const QString &indent);
+
+private:
+ enum ProWriteState {
+ NewLine = 0x01,
+ FirstItem = 0x02,
+ LastItem = 0x04
+ };
+
+ QTextStream m_out;
+ int m_writeState;
+ QString m_comment;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //PROWRITER_H
diff --git a/shared/proparser/proxml.cpp b/shared/proparser/proxml.cpp
new file mode 100644
index 0000000000..57764241c3
--- /dev/null
+++ b/shared/proparser/proxml.cpp
@@ -0,0 +1,207 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "proxml.h"
+#include "proitems.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+QString ProXmlParser::itemToString(ProItem *item)
+{
+ ProXmlParser xmlparser;
+ QDomDocument doc("ProItem");
+ QDomNode itemNode = xmlparser.createItemNode(doc, item);
+
+ if (itemNode.isNull())
+ return QString();
+
+ doc.appendChild(itemNode);
+
+ return doc.toString();
+}
+
+QDomNode ProXmlParser::createItemNode(QDomDocument doc, ProItem *item) const
+{
+
+ QDomElement tag;
+ if (item->kind() == ProItem::ValueKind) {
+ tag = doc.createElement(QLatin1String("value"));
+ ProValue *v = static_cast<ProValue*>(item);
+ QDomText text = doc.createTextNode(v->value());
+ tag.appendChild(text);
+ }
+
+ if (item->kind() == ProItem::FunctionKind) {
+ tag = doc.createElement(QLatin1String("function"));
+ ProFunction *v = static_cast<ProFunction*>(item);
+ QDomText text = doc.createTextNode(v->text());
+ tag.appendChild(text);
+ }
+
+ if (item->kind() == ProItem::ConditionKind) {
+ tag = doc.createElement(QLatin1String("condition"));
+ ProCondition *v = static_cast<ProCondition*>(item);
+ QDomText text = doc.createTextNode(v->text());
+ tag.appendChild(text);
+ }
+
+ if (item->kind() == ProItem::OperatorKind) {
+ tag = doc.createElement(QLatin1String("operator"));
+ ProOperator *v = static_cast<ProOperator*>(item);
+ tag.setAttribute(QLatin1String("type"), (int)v->operatorKind());
+ }
+
+ if (tag.isNull() && item->kind() != ProItem::BlockKind) {
+ qDebug() << "*** Warning: Found unknown item!";
+ return tag;
+ }
+
+ if (tag.isNull()) {
+ ProBlock *block = static_cast<ProBlock*>(item);
+
+ if (block->blockKind() & ProBlock::ProFileKind) {
+ tag = doc.createElement(QLatin1String("file"));
+ } else if (block->blockKind() & ProBlock::VariableKind) {
+ tag = doc.createElement(QLatin1String("variable"));
+ ProVariable *v = static_cast<ProVariable*>(block);
+ tag.setAttribute(QLatin1String("name"), QString(v->variable()));
+ tag.setAttribute(QLatin1String("type"), (int)v->variableOperator());
+ } else if (block->blockKind() & ProBlock::ScopeKind) {
+ tag = doc.createElement(QLatin1String("scope"));
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ tag = doc.createElement(QLatin1String("scopecontents"));
+ } else {
+ tag = doc.createElement(QLatin1String("block"));
+ }
+
+ foreach(ProItem *child, block->items()) {
+ QDomNode childNode = createItemNode(doc, child);
+ if (!childNode.isNull())
+ tag.appendChild(childNode);
+ }
+ }
+
+ QString comment = item->comment();
+ comment = comment.replace('\\', QLatin1String("\\\\"));
+ comment = comment.replace('\n', QLatin1String("\\n"));
+
+ if (!comment.isEmpty())
+ tag.setAttribute(QLatin1String("comment"), comment);
+
+ return tag;
+}
+
+ProItem *ProXmlParser::parseItemNode(QDomDocument doc, QDomNode node) const
+{
+ QDomElement tag = node.toElement();
+ if (tag.isNull()) {
+ qDebug() << "*** Warning: Failed while parsing XML";
+ return 0;
+ }
+
+ ProItem *item = 0;
+ if (tag.tagName() == QLatin1String("value")) {
+ item = new ProValue(tag.text(), 0);
+ } else if (tag.tagName() == QLatin1String("function")) {
+ item = new ProFunction(tag.text());
+ } else if (tag.tagName() == QLatin1String("condition")) {
+ item = new ProCondition(tag.text());
+ } else if (tag.tagName() == QLatin1String("operator")) {
+ int optype = tag.attribute(QLatin1String("type")).toInt();
+ item = new ProOperator((ProOperator::OperatorKind)optype);
+ } else if (tag.tagName() == QLatin1String("variable")) {
+ QString name = tag.attribute(QLatin1String("name"));
+ int vartype = tag.attribute(QLatin1String("type")).toInt();
+ ProVariable::VariableOperator varop = ProVariable::VariableOperator(vartype);
+ ProVariable *v = new ProVariable(name, 0);
+ v->setVariableOperator(varop);
+ item = v;
+ } else if (tag.tagName() == QLatin1String("file")) {
+ ProFile *v = new ProFile(QString());
+ item = v;
+ } else if (tag.tagName() == QLatin1String("scope")) {
+ ProBlock *v = new ProBlock(0);
+ v->setBlockKind(ProBlock::ScopeKind);
+ item = v;
+ } else if (tag.tagName() == QLatin1String("scopecontents")) {
+ ProBlock *v = new ProBlock(0);
+ v->setBlockKind(ProBlock::ScopeContentsKind);
+ item = v;
+ } else if (tag.tagName() == QLatin1String("block")) {
+ item = new ProBlock(0);
+ }
+
+ if (!item) {
+ qDebug() << "*** Warning: Could not create item!";
+ return 0;
+ }
+
+ QString comment = tag.attribute(QLatin1String("comment"));
+ if (!comment.isEmpty()) {
+ //### fix multiple lines
+ item->setComment(comment);
+ }
+
+ if (item->kind() != ProItem::BlockKind)
+ return item;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+ ProVariable *variable = 0;
+ if (block->blockKind() & ProBlock::VariableKind)
+ variable = static_cast<ProVariable *>(block);
+
+ QDomNodeList children = tag.childNodes();
+ for (int i=0; i<children.count(); ++i) {
+ ProItem *childItem = parseItemNode(doc, children.at(i));
+ if (!childItem)
+ continue;
+
+ if (variable && childItem->kind() == ProItem::ValueKind)
+ static_cast<ProValue*>(childItem)->setVariable(variable);
+ else if (childItem->kind() == ProItem::BlockKind)
+ static_cast<ProBlock*>(childItem)->setParent(block);
+
+ block->appendItem(childItem);
+ }
+
+ return item;
+}
+
+ProItem *ProXmlParser::stringToItem(const QString &xml)
+{
+ ProXmlParser xmlparser;
+ QDomDocument doc("ProItem");
+
+ doc.setContent(xml);
+
+ return xmlparser.parseItemNode(doc, doc.documentElement());
+}
diff --git a/shared/proparser/proxml.h b/shared/proparser/proxml.h
new file mode 100644
index 0000000000..a6e2b3ca50
--- /dev/null
+++ b/shared/proparser/proxml.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROXML_H
+#define PROXML_H
+
+#include "namespace_global.h"
+
+#include <QtXml>
+QT_FORWARD_DECLARE_CLASS(ProItem)
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProXmlParser {
+public:
+ static QString itemToString(ProItem *item);
+ static ProItem *stringToItem(const QString &xml);
+private:
+ QDomNode createItemNode(QDomDocument doc, ProItem *item) const;
+ ProItem *parseItemNode(QDomDocument doc, QDomNode node) const;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //PROXML_H
diff --git a/shared/proparser/valueeditor.cpp b/shared/proparser/valueeditor.cpp
new file mode 100644
index 0000000000..9d367dad1e
--- /dev/null
+++ b/shared/proparser/valueeditor.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "valueeditor.h"
+#include "proitems.h"
+#include "proeditormodel.h"
+#include "proiteminfo.h"
+
+#include <QtGui/QMenu>
+#include <QtGui/QKeyEvent>
+
+using namespace Qt4ProjectManager::Internal;
+
+ValueEditor::ValueEditor(QWidget *parent) :
+ QWidget(parent),
+ m_model(0),
+ m_handleModelChanges(true),
+ m_infomanager(0)
+{
+ setupUi(this);
+}
+
+ValueEditor::~ValueEditor()
+{
+}
+
+void ValueEditor::initialize(ProEditorModel *model, ProItemInfoManager *infomanager)
+{
+ m_model = model;
+ m_infomanager = infomanager;
+ initialize();
+}
+
+void ValueEditor::hideVariable()
+{
+ m_varGroupBox->setVisible(false);
+}
+
+void ValueEditor::showVariable(bool advanced)
+{
+ m_varComboBoxLabel->setVisible(!advanced);
+ m_varComboBox->setVisible(!advanced);
+
+ m_varLineEditLabel->setVisible(advanced);
+ m_varLineEdit->setVisible(advanced);
+
+ m_assignComboBoxLabel->setVisible(advanced);
+ m_assignComboBox->setVisible(advanced);
+
+ m_varGroupBox->setVisible(true);
+}
+
+void ValueEditor::setItemEditType(ItemEditType type)
+{
+ m_editStackWidget->setCurrentIndex(type);
+}
+
+void ValueEditor::setDescription(ItemEditType type, const QString &header, const QString &description)
+{
+ switch (type) {
+ case MultiUndefined:
+ m_multiUndefinedGroupBox->setTitle(header);
+ m_multiUndefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_multiUndefinedDescriptionLabel->setText(description);
+ break;
+ case MultiDefined:
+ m_multiDefinedGroupBox->setTitle(header);
+ m_multiDefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_multiDefinedDescriptionLabel->setText(description);
+ break;
+ case SingleUndefined:
+ m_singleUndefinedGroupBox->setTitle(header);
+ m_singleUndefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_singleUndefinedDescriptionLabel->setText(description);
+ break;
+ default:
+ m_singleDefinedGroupBox->setTitle(header);
+ m_singleDefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_singleDefinedDescriptionLabel->setText(description);
+ break;
+ }
+}
+
+void ValueEditor::initialize()
+{
+ hideVariable();
+ setItemEditType(MultiUndefined);
+
+ m_itemListView->setModel(m_model);
+ m_itemListView->setRootIndex(QModelIndex());
+
+ connect(m_itemAddButton, SIGNAL(clicked()),
+ this, SLOT(addItem()));
+ connect(m_itemRemoveButton, SIGNAL(clicked()),
+ this, SLOT(removeItem()));
+
+ connect(m_itemListView->selectionModel(),
+ SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(updateItemList(const QModelIndex &)));
+
+ connect(m_itemListWidget, SIGNAL(itemChanged(QListWidgetItem *)),
+ this, SLOT(updateItemChanges(QListWidgetItem *)));
+
+ foreach(ProVariableInfo *varinfo, m_infomanager->variables()) {
+ m_varComboBox->addItem(varinfo->name(), varinfo->id());
+ }
+
+ connect(m_varLineEdit, SIGNAL(editingFinished()), this, SLOT(updateVariableId()));
+ connect(m_varComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateVariableId(int)));
+ connect(m_assignComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateVariableOp(int)));
+
+ connect(m_itemLineEdit, SIGNAL(editingFinished()), this, SLOT(updateItemId()));
+ connect(m_itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateItemId(int)));
+
+ connect(m_model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(modelChanged(const QModelIndex &)));
+
+ connect(m_model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(modelChanged(const QModelIndex &)));
+
+ connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(modelChanged(const QModelIndex &)));
+
+ updateItemList(QModelIndex());
+}
+
+void ValueEditor::modelChanged(const QModelIndex &index)
+{
+ if (m_handleModelChanges) {
+ if (m_currentIndex == index || m_currentIndex == index.parent())
+ editIndex(m_currentIndex);
+ }
+}
+
+void ValueEditor::editIndex(const QModelIndex &index)
+{
+ if (!m_model)
+ return;
+ m_currentIndex = index;
+ ProBlock *block = m_model->proBlock(index);
+
+ m_varGroupBox->setEnabled(block != 0);
+ m_editStackWidget->setEnabled(block != 0);
+
+ if (!block)
+ return;
+
+ if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ showScope(block);
+ } else if (block->blockKind() & ProBlock::VariableKind) {
+ showVariable(static_cast<ProVariable*>(block));
+ } else {
+ showOther(block);
+ }
+}
+
+ValueEditor::ItemEditType ValueEditor::itemType(bool defined, bool multiple) const
+{
+ if (defined) {
+ if (multiple)
+ return MultiDefined;
+ else
+ return SingleDefined;
+ } else {
+ if (multiple)
+ return MultiUndefined;
+ else
+ return SingleUndefined;
+ }
+}
+
+void ValueEditor::showVariable(ProVariable *variable)
+{
+ if (!m_model)
+ return;
+ ProVariableInfo *info = m_infomanager->variable(variable->variable());
+
+ const bool advanced = (!m_model->infoManager() || (info == 0));
+ bool defined = false;
+ bool multiple = true;
+
+ QSet<QString> values;
+ foreach(ProItem *proitem, variable->items()) {
+ if (proitem->kind() == ProItem::ValueKind) {
+ ProValue *val = static_cast<ProValue *>(proitem);
+ values.insert(val->value());
+ }
+ }
+
+ if (!advanced && info) {
+ defined = !info->values().isEmpty();
+
+ // check if all values are known
+ foreach(QString val, values) {
+ if (!info->value(val)) {
+ defined = false;
+ break;
+ }
+ }
+
+ multiple = info->multiple();
+ }
+
+ if (values.count() > 1)
+ multiple = true;
+
+ bool wasblocked;
+
+ if (!advanced) {
+ const int index = m_varComboBox->findData(variable->variable(), Qt::UserRole, Qt::MatchExactly);
+ wasblocked = m_varComboBox->blockSignals(true);
+ m_varComboBox->setCurrentIndex(index);
+ m_varComboBox->blockSignals(wasblocked);
+ } else {
+ wasblocked = m_varLineEdit->blockSignals(true);
+ m_varLineEdit->setText(variable->variable());
+ m_varLineEdit->blockSignals(wasblocked);
+ }
+
+ ItemEditType type = itemType(defined, multiple);
+
+ wasblocked = m_assignComboBox->blockSignals(true);
+ m_assignComboBox->setCurrentIndex(variable->variableOperator());
+ m_assignComboBox->blockSignals(wasblocked);
+
+ QString header = tr("Edit Values");
+ QString desc;
+ if (info) {
+ header = tr("Edit %1").arg(info->name());
+ desc = info->description();
+ }
+ setDescription(type, header, desc);
+
+ m_itemListWidget->clear();
+
+ switch (type) {
+ case MultiUndefined: {
+ const QModelIndex parent = m_currentIndex;
+ m_itemListView->setRootIndex(parent);
+ m_itemListView->setCurrentIndex(m_model->index(0,0,parent));
+ }
+ break;
+ case MultiDefined:
+ wasblocked = m_itemListWidget->blockSignals(true);
+
+ foreach(ProValueInfo *valinfo, info->values()) {
+ QListWidgetItem *item = new QListWidgetItem(m_itemListWidget);
+ item->setText(valinfo->name());
+ item->setData(Qt::UserRole, valinfo->id());
+
+ if (values.contains(valinfo->id()))
+ item->setCheckState(Qt::Checked);
+ else
+ item->setCheckState(Qt::Unchecked);
+ }
+
+ m_itemListWidget->blockSignals(wasblocked);
+ break;
+ case SingleUndefined:
+ wasblocked = m_itemLineEdit->blockSignals(true);
+ if (values.isEmpty())
+ m_itemLineEdit->setText(QString());
+ else
+ m_itemLineEdit->setText(values.toList().first());
+ m_itemLineEdit->blockSignals(wasblocked);
+ break;
+ case SingleDefined:
+ wasblocked = m_itemComboBox->blockSignals(true);
+ m_itemComboBox->clear();
+
+ foreach(ProValueInfo *valinfo, info->values()) {
+ m_itemComboBox->addItem(valinfo->name(), valinfo->id());
+ }
+
+ int index = -1;
+ if (!values.isEmpty()) {
+ const QString id = values.toList().first();
+ index = m_itemComboBox->findData(id, Qt::UserRole, Qt::MatchExactly);
+ }
+
+ m_itemComboBox->setCurrentIndex(index);
+ m_itemComboBox->blockSignals(wasblocked);
+ break;
+ }
+
+ showVariable(advanced);
+ setItemEditType(type);
+}
+
+void ValueEditor::showScope(ProBlock *)
+{
+ if (!m_model)
+ return;
+ const bool wasblocked = m_itemLineEdit->blockSignals(true);
+ m_itemLineEdit->setText(m_model->data(m_currentIndex, Qt::EditRole).toString());
+ m_itemLineEdit->blockSignals(wasblocked);
+
+ setDescription(SingleUndefined, tr("Edit Scope"));
+
+ hideVariable();
+ setItemEditType(SingleUndefined);
+}
+
+void ValueEditor::showOther(ProBlock *)
+{
+ if (!m_model)
+ return;
+ const bool wasblocked = m_itemLineEdit->blockSignals(true);
+ m_itemLineEdit->setText(m_model->data(m_currentIndex, Qt::EditRole).toString());
+ m_itemLineEdit->blockSignals(wasblocked);
+
+ setDescription(SingleUndefined, tr("Edit Advanced Expression"));
+
+ hideVariable();
+ setItemEditType(SingleUndefined);
+}
+
+void ValueEditor::addItem(QString value)
+{
+ if (!m_model)
+ return;
+ QModelIndex parent = m_currentIndex;
+ ProVariable *var = static_cast<ProVariable *>(m_model->proBlock(parent));
+
+ if (value.isEmpty()) {
+ value = QLatin1String("...");
+
+ if (ProVariableInfo *varinfo = m_infomanager->variable(var->variable())) {
+ const QList<ProValueInfo *> vals = varinfo->values();
+ if (!vals.isEmpty())
+ value = vals.first()->id();
+ }
+ }
+
+ m_handleModelChanges = false;
+ m_model->insertItem(new ProValue(value, var),
+ m_model->rowCount(parent), parent);
+
+ const QModelIndex idx = m_model->index(m_model->rowCount(parent)-1, 0, parent);
+ m_itemListView->setCurrentIndex(idx);
+ m_itemListView->edit(idx);
+ m_itemListView->scrollToBottom();
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::removeItem()
+{
+ if (!m_model)
+ return;
+ m_handleModelChanges = false;
+ const QModelIndex idx = m_itemListView->currentIndex();
+ m_itemListView->closePersistentEditor(idx);
+ m_model->removeItem(idx);
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateItemList(const QModelIndex &)
+{
+ if (!m_model)
+ return;
+ m_itemRemoveButton->setEnabled(m_model->rowCount(m_currentIndex));
+}
+
+QModelIndex ValueEditor::findValueIndex(const QString &id) const
+{
+ if (!m_model)
+ return QModelIndex();
+ const QModelIndex parent = m_currentIndex;
+ const int rows = m_model->rowCount(parent);
+
+ for (int row=0; row<rows; ++row) {
+ const QModelIndex index = m_model->index(row, 0, parent);
+ ProItem *item = m_model->proItem(index);
+ if (!item || item->kind() != ProItem::ValueKind)
+ continue;
+
+ if (static_cast<ProValue*>(item)->value() == id)
+ return index;
+ }
+
+ return QModelIndex();
+}
+
+void ValueEditor::updateItemChanges(QListWidgetItem *item)
+{
+ if (!m_model)
+ return;
+ const QModelIndex parent = m_currentIndex;
+ ProBlock *block = m_model->proBlock(parent);
+
+ if (!block || !(block->blockKind() & ProBlock::VariableKind))
+ return;
+
+ ProVariable *var = static_cast<ProVariable *>(block);
+ const QString id = item->data(Qt::UserRole).toString();
+
+ m_handleModelChanges = false;
+ const QModelIndex index = findValueIndex(id);
+ if (item->checkState() == Qt::Checked && !index.isValid()) {
+ m_model->insertItem(new ProValue(id, var),
+ m_model->rowCount(parent), m_currentIndex);
+ } else if (item->checkState() != Qt::Checked && index.isValid()) {
+ m_model->removeItem(index);
+ }
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateVariableId() {
+ if (!m_model)
+ return;
+ m_handleModelChanges = false;
+ m_model->setData(m_currentIndex, QVariant(m_varLineEdit->text()));
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateVariableId(int index) {
+ if (!m_model)
+ return;
+ ProVariableInfo *info = m_infomanager->variable(m_varComboBox->itemData(index).toString());
+
+ m_model->setData(m_currentIndex, info->id());
+ m_model->setData(m_currentIndex, info->defaultOperator());
+}
+
+void ValueEditor::updateVariableOp(int index) {
+ if (!m_model)
+ return;
+ m_handleModelChanges = false;
+ m_model->setData(m_currentIndex, QVariant(index));
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateItemId() {
+ if (!m_model)
+ return;
+ QModelIndex index = m_currentIndex;
+ if (m_varGroupBox->isVisible()) {
+ index = m_model->index(0,0,index);
+ if (!index.isValid()) {
+ addItem(m_itemLineEdit->text());
+ return;
+ }
+ }
+
+ m_handleModelChanges = false;
+ m_model->setData(index, QVariant(m_itemLineEdit->text()));
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateItemId(int index) {
+ if (!m_model)
+ return;
+ QModelIndex idx = m_currentIndex;
+ if (m_varGroupBox->isVisible()) {
+ idx = m_model->index(0,0,idx);
+ if (!idx.isValid()) {
+ addItem(m_itemComboBox->itemData(index).toString());
+ return;
+ }
+ }
+
+ m_handleModelChanges = false;
+ m_model->setData(idx, m_itemComboBox->itemData(index));
+ m_handleModelChanges = true;
+}
diff --git a/shared/proparser/valueeditor.h b/shared/proparser/valueeditor.h
new file mode 100644
index 0000000000..50ba2f8a92
--- /dev/null
+++ b/shared/proparser/valueeditor.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VALUEEDITOR_H
+#define VALUEEDITOR_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QList>
+#include <QtGui/QWidget>
+#include <QtCore/QPointer>
+#include "ui_valueeditor.h"
+
+QT_BEGIN_NAMESPACE
+class ProBlock;
+class ProVariable;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProEditorModel;
+class ProItemInfoManager;
+
+class ValueEditor : public QWidget,
+ protected Ui::ValueEditor
+{
+ Q_OBJECT
+
+public:
+ ValueEditor(QWidget *parent = 0);
+ ~ValueEditor();
+
+ void initialize(ProEditorModel *model, ProItemInfoManager *infomanager);
+
+public slots:
+ void editIndex(const QModelIndex &index);
+
+protected slots:
+ void modelChanged(const QModelIndex &index);
+
+ void addItem(QString value = QString());
+ void removeItem();
+
+ void updateItemList(const QModelIndex &item);
+ void updateItemChanges(QListWidgetItem *item);
+
+ void updateVariableId();
+ void updateVariableId(int index);
+ void updateVariableOp(int index);
+
+ void updateItemId();
+ void updateItemId(int index);
+
+private:
+ enum ItemEditType {
+ SingleDefined = 0,
+ SingleUndefined = 1,
+ MultiDefined = 2,
+ MultiUndefined = 3
+ };
+
+ void hideVariable();
+ void showVariable(bool advanced);
+ void setItemEditType(ItemEditType type);
+ void setDescription(ItemEditType type, const QString &header, const QString &desc = QString());
+
+ void initialize();
+
+ void showVariable(ProVariable *variable);
+ void showScope(ProBlock *scope);
+ void showOther(ProBlock *block);
+
+ ItemEditType itemType(bool defined, bool multiple) const;
+ QModelIndex findValueIndex(const QString &id) const;
+
+protected:
+ QPointer<ProEditorModel> m_model;
+
+private:
+ bool m_handleModelChanges;
+
+ QModelIndex m_currentIndex;
+ ProItemInfoManager *m_infomanager;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //VALUEEDITOR_H
diff --git a/shared/proparser/valueeditor.ui b/shared/proparser/valueeditor.ui
new file mode 100644
index 0000000000..9a281035d2
--- /dev/null
+++ b/shared/proparser/valueeditor.ui
@@ -0,0 +1,384 @@
+<ui version="4.0" >
+ <class>Qt4ProjectManager::Internal::ValueEditor</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::ValueEditor" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>621</width>
+ <height>557</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_varGroupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Edit Variable</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="m_varComboBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="m_varLineEditLabel" >
+ <property name="text" >
+ <string>Variable Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="m_assignComboBoxLabel" >
+ <property name="text" >
+ <string>Assignment Operator:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="m_varLineEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="m_varComboBoxLabel" >
+ <property name="text" >
+ <string>Variable:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="m_assignComboBox" >
+ <item>
+ <property name="text" >
+ <string>Append (+=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Remove (-=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Replace (~=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Set (=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Unique (*=)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="m_editStackWidget" >
+ <property name="currentIndex" >
+ <number>2</number>
+ </property>
+ <widget class="QWidget" name="m_singleDefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_singleDefinedGroupBox" >
+ <property name="title" >
+ <string>Select Item</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_singleDefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="m_itemComboBox" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="m_singleUndefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_singleUndefinedGroupBox" >
+ <property name="title" >
+ <string>Edit Item</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_singleUndefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="m_itemLineEdit" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="m_multiDefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_multiDefinedGroupBox" >
+ <property name="title" >
+ <string>Select Items</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_multiDefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="m_itemListWidget" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="m_multiUndefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_multiUndefinedGroupBox" >
+ <property name="title" >
+ <string>Edit Items</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_multiUndefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListView" name="m_itemListView" >
+ <property name="uniformItemSizes" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="m_itemAddButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_itemRemoveButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>44</width>
+ <height>128</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/shared/qrceditor/qrceditor.cpp b/shared/qrceditor/qrceditor.cpp
new file mode 100644
index 0000000000..ac7305c4d8
--- /dev/null
+++ b/shared/qrceditor/qrceditor.cpp
@@ -0,0 +1,401 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qrceditor.h"
+#include "undocommands_p.h"
+
+#include <QtCore/QDebug>
+#include <QtGui/QMenu>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+namespace SharedTools {
+
+QrcEditor::QrcEditor(QWidget *parent) :
+ QWidget(parent),
+ m_treeview(new ResourceView(&m_history)),
+ m_addFileAction(0)
+{
+ m_ui.setupUi(this);
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->setSpacing(0);
+ layout->setMargin(0);
+ m_ui.centralWidget->setLayout(layout);
+
+ m_treeview->enableContextMenu(false);
+ layout->addWidget(m_treeview);
+ connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(onRemove()));
+
+ // 'Add' button with menu
+ QMenu *addMenu = new QMenu(this);
+ m_addFileAction = addMenu->addAction(tr("Add Files"), this, SLOT(onAddFiles()));
+ addMenu->addAction(tr("Add Prefix"), this, SLOT(onAddPrefix()));
+ m_ui.addButton->setMenu(addMenu);
+
+ connect(m_treeview, SIGNAL(addPrefixTriggered()), this, SLOT(onAddPrefix()));
+ connect(m_treeview, SIGNAL(addFilesTriggered(const QString &)), this, SLOT(onAddFiles()));
+ connect(m_treeview, SIGNAL(removeItem()), this, SLOT(onRemove()));
+ connect(m_treeview, SIGNAL(currentIndexChanged()), this, SLOT(updateCurrent()));
+ connect(m_treeview, SIGNAL(dirtyChanged(bool)), this, SIGNAL(dirtyChanged(bool)));
+ m_treeview->setFocus();
+
+ connect(m_ui.aliasText, SIGNAL(textEdited(const QString &)),
+ this, SLOT(onAliasChanged(const QString &)));
+ connect(m_ui.prefixText, SIGNAL(textEdited(const QString &)),
+ this, SLOT(onPrefixChanged(const QString &)));
+ connect(m_ui.languageText, SIGNAL(textEdited(const QString &)),
+ this, SLOT(onLanguageChanged(const QString &)));
+
+ // Prevent undo command merging after a switch of focus:
+ // (0) The initial text is "Green".
+ // (1) The user appends " is a color." --> text is "Green is a color."
+ // (2) The user clicks into some other line edit --> loss of focus
+ // (3) The user gives focuse again and substitutes "Green" with "Red"
+ // --> text now is "Red is a color."
+ // (4) The user hits undo --> text now is "Green is a color."
+ // Without calling advanceMergeId() it would have been "Green", instead.
+ connect(m_ui.aliasText, SIGNAL(editingFinished()),
+ m_treeview, SLOT(advanceMergeId()));
+ connect(m_ui.prefixText, SIGNAL(editingFinished()),
+ m_treeview, SLOT(advanceMergeId()));
+ connect(m_ui.languageText, SIGNAL(editingFinished()),
+ m_treeview, SLOT(advanceMergeId()));
+
+ connect(m_treeview, SIGNAL(addFilesTriggered(const QString&)),
+ this, SIGNAL(addFilesTriggered(const QString&)));
+
+ connect(&m_history, SIGNAL(canRedoChanged(bool)), this, SLOT(updateHistoryControls()));
+ connect(&m_history, SIGNAL(canUndoChanged(bool)), this, SLOT(updateHistoryControls()));
+ connect(&m_history, SIGNAL(canRedoChanged(bool)), this, SLOT(updateCurrent()));
+ connect(&m_history, SIGNAL(canUndoChanged(bool)), this, SLOT(updateCurrent()));
+ updateHistoryControls();
+ updateCurrent();
+}
+
+QrcEditor::~QrcEditor()
+{
+}
+
+QString QrcEditor::fileName() const
+{
+ return m_treeview->fileName();
+}
+
+void QrcEditor::setFileName(const QString &fileName)
+{
+ m_treeview->setFileName(fileName);
+}
+
+bool QrcEditor::load(const QString &fileName)
+{
+ const bool success = m_treeview->load(fileName);
+ if (success) {
+ // Set "focus"
+ m_treeview->setCurrentIndex(m_treeview->model()->index(0,0));
+
+ // Expand prefix nodes
+ m_treeview->expandAll();
+ }
+ return success;
+}
+
+bool QrcEditor::save()
+{
+ return m_treeview->save();
+}
+
+bool QrcEditor::isDirty()
+{
+ return m_treeview->isDirty();
+}
+
+void QrcEditor::setDirty(bool dirty)
+{
+ m_treeview->setDirty(dirty);
+}
+
+// Propagates a change of selection in the tree
+// to the alias/prefix/language edit controls
+void QrcEditor::updateCurrent()
+{
+ const bool isValid = m_treeview->currentIndex().isValid();
+ const bool isPrefix = m_treeview->isPrefix(m_treeview->currentIndex()) && isValid;
+ const bool isFile = !isPrefix && isValid;
+
+ m_ui.aliasLabel->setEnabled(isFile);
+ m_ui.aliasText->setEnabled(isFile);
+ m_currentAlias = m_treeview->currentAlias();
+ m_ui.aliasText->setText(m_currentAlias);
+
+ m_ui.prefixLabel->setEnabled(isPrefix);
+ m_ui.prefixText->setEnabled(isPrefix);
+ m_currentPrefix = m_treeview->currentPrefix();
+ m_ui.prefixText->setText(m_currentPrefix);
+
+ m_ui.languageLabel->setEnabled(isPrefix);
+ m_ui.languageText->setEnabled(isPrefix);
+ m_currentLanguage = m_treeview->currentLanguage();
+ m_ui.languageText->setText(m_currentLanguage);
+
+ m_ui.addButton->setEnabled(true);
+ m_addFileAction->setEnabled(isValid);
+ m_ui.removeButton->setEnabled(isValid);
+}
+
+void QrcEditor::updateHistoryControls()
+{
+ emit undoStackChanged(m_history.canUndo(), m_history.canRedo());
+}
+
+void QrcEditor::resolveLocationIssues(QStringList &files)
+{
+ const QDir dir = QFileInfo(m_treeview->fileName()).absoluteDir();
+ const QString dotdotSlash = QLatin1String("../");
+ int i = 0;
+ int count = files.count();
+
+ // Find first troublesome file
+ for (; i < count; i++) {
+ QString const &file = files.at(i);
+ const QString relativePath = dir.relativeFilePath(file);
+ if (relativePath.startsWith(dotdotSlash))
+ break;
+ }
+
+ // All paths fine -> no interaction needed
+ if (i == count) {
+ return;
+ }
+
+ // Interact with user from now on
+ bool abort = false;
+ for (; i < count; i++) {
+ // Path fine -> skip file
+ QString const &file = files.at(i);
+ QString const relativePath = dir.relativeFilePath(file);
+ if (!relativePath.startsWith(dotdotSlash)) {
+ continue;
+ }
+
+ // Path troublesome and aborted -> remove file
+ if (abort) {
+ files.removeAt(i);
+ count--;
+ i--;
+ continue;
+ } else {
+ // Path troublesome -> query user
+ QMessageBox message(this);
+ message.setWindowTitle(tr("Invalid file"));
+ message.setIcon(QMessageBox::Warning);
+ QPushButton * const continueButton = message.addButton(tr("Add anyway"), QMessageBox::AcceptRole);
+ QPushButton * const copyButton = message.addButton(tr("Copy"), QMessageBox::ActionRole);
+ QPushButton * const skipButton = message.addButton(tr("Don't add"), QMessageBox::DestructiveRole);
+ QPushButton * const abortButton = message.addButton(tr("Abort"), QMessageBox::RejectRole);
+ message.setDefaultButton(copyButton);
+ message.setEscapeButton(skipButton);
+ message.setText(tr("The file %1 is not in a subdirectory of the resource file. Continuing will result in an invalid resource file.")
+ .arg(QDir::toNativeSeparators(file)));
+ message.exec();
+ if (message.clickedButton() == continueButton) {
+ continue;
+ } else if (message.clickedButton() == skipButton) {
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ } else if (message.clickedButton() == copyButton) {
+ const QFileInfo fi(file);
+ const QFileInfo suggestion(dir, fi.fileName());
+ const QString copyName = QFileDialog::getSaveFileName(this, tr("Choose copy location"),
+ suggestion.absoluteFilePath());
+ if (!copyName.isEmpty()) {
+ if (QFile::exists(copyName)) {
+ if (!QFile::remove(copyName)) {
+ QMessageBox::critical(this, tr("Overwrite failed"),
+ tr("Could not overwrite file %1.")
+ .arg(QDir::toNativeSeparators(copyName)));
+ // Remove file
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ continue;
+ }
+ }
+ if (!QFile::copy(file, copyName)) {
+ QMessageBox::critical(this, tr("Copying failed"),
+ tr("Could not copy the file to %1.")
+ .arg(QDir::toNativeSeparators(copyName)));
+ // Remove file
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ continue;
+ }
+ files[i] = copyName;
+ } else {
+ // Remove file
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ }
+ } else if (message.clickedButton() == abortButton) {
+ abort = true;
+
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ }
+ }
+ }
+}
+
+void QrcEditor::setResourceDragEnabled(bool e)
+{
+ m_treeview->setResourceDragEnabled(e);
+}
+
+bool QrcEditor::resourceDragEnabled() const
+{
+ return m_treeview->resourceDragEnabled();
+}
+
+void QrcEditor::setDefaultAddFileEnabled(bool enable)
+{
+ m_treeview->setDefaultAddFileEnabled(enable);
+}
+
+bool QrcEditor::defaultAddFileEnabled() const
+{
+ return m_treeview->defaultAddFileEnabled();
+}
+
+void QrcEditor::addFile(const QString &prefix, const QString &file)
+{
+ // TODO: make this function UNDO / REDO aware
+ m_treeview->addFile(prefix, file);
+}
+
+/*
+void QrcEditor::removeFile(const QString &prefix, const QString &file)
+{
+ m_treeview->removeFile(prefix, file);
+}
+*/
+// Slot for change of line edit content 'alias'
+void QrcEditor::onAliasChanged(const QString &alias)
+{
+ const QString &before = m_currentAlias;
+ const QString &after = alias;
+ m_treeview->setCurrentAlias(before, after);
+ m_currentAlias = alias;
+ updateHistoryControls();
+}
+
+// Slot for change of line edit content 'prefix'
+void QrcEditor::onPrefixChanged(const QString &prefix)
+{
+ const QString &before = m_currentPrefix;
+ const QString &after = prefix;
+ m_treeview->setCurrentPrefix(before, after);
+ m_currentPrefix = prefix;
+ updateHistoryControls();
+}
+
+// Slot for change of line edit content 'language'
+void QrcEditor::onLanguageChanged(const QString &language)
+{
+ const QString &before = m_currentLanguage;
+ const QString &after = language;
+ m_treeview->setCurrentLanguage(before, after);
+ m_currentLanguage = language;
+ updateHistoryControls();
+}
+
+// Slot for 'Remove' button
+void QrcEditor::onRemove()
+{
+ // Find current item, push and execute command
+ const QModelIndex current = m_treeview->currentIndex();
+ int afterDeletionArrayIndex = current.row();
+ QModelIndex afterDeletionParent = current.parent();
+ m_treeview->findSamePlacePostDeletionModelIndex(afterDeletionArrayIndex, afterDeletionParent);
+ QUndoCommand * const removeCommand = new RemoveEntryCommand(m_treeview, current);
+ m_history.push(removeCommand);
+ const QModelIndex afterDeletionModelIndex
+ = m_treeview->model()->index(afterDeletionArrayIndex, 0, afterDeletionParent);
+ m_treeview->setCurrentIndex(afterDeletionModelIndex);
+ updateHistoryControls();
+}
+
+// Slot for 'Add File' button
+void QrcEditor::onAddFiles()
+{
+ QModelIndex const current = m_treeview->currentIndex();
+ int const currentIsPrefixNode = m_treeview->isPrefix(current);
+ int const prefixArrayIndex = currentIsPrefixNode ? current.row()
+ : m_treeview->model()->parent(current).row();
+ int const cursorFileArrayIndex = currentIsPrefixNode ? 0 : current.row();
+ QStringList fileNames = m_treeview->fileNamesToAdd();
+ resolveLocationIssues(fileNames);
+ if (fileNames.isEmpty())
+ return;
+ QUndoCommand * const addFilesCommand = new AddFilesCommand(
+ m_treeview, prefixArrayIndex, cursorFileArrayIndex, fileNames);
+ m_history.push(addFilesCommand);
+ updateHistoryControls();
+}
+
+// Slot for 'Add Prefix' button
+void QrcEditor::onAddPrefix()
+{
+ QUndoCommand * const addEmptyPrefixCommand = new AddEmptyPrefixCommand(m_treeview);
+ m_history.push(addEmptyPrefixCommand);
+ updateHistoryControls();
+}
+
+// Slot for 'Undo' button
+void QrcEditor::onUndo()
+{
+ m_history.undo();
+ updateCurrent();
+ updateHistoryControls();
+}
+
+// Slot for 'Redo' button
+void QrcEditor::onRedo()
+{
+ m_history.redo();
+ updateCurrent();
+ updateHistoryControls();
+}
+
+} // namespace SharedTools
diff --git a/shared/qrceditor/qrceditor.h b/shared/qrceditor/qrceditor.h
new file mode 100644
index 0000000000..54c9b790f4
--- /dev/null
+++ b/shared/qrceditor/qrceditor.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QRCEDITOR_H
+#define QRCEDITOR_H
+
+#include "ui_qrceditor.h"
+#include "resourceview.h"
+
+#include <QtGui/QWidget>
+#include <QtGui/QUndoStack>
+
+namespace SharedTools {
+
+class QrcEditor : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QrcEditor(QWidget *parent = 0);
+ virtual ~QrcEditor();
+
+ bool load(const QString &fileName);
+ bool save();
+
+ bool isDirty();
+ void setDirty(bool dirty);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ void setResourceDragEnabled(bool e);
+ bool resourceDragEnabled() const;
+
+ void setDefaultAddFileEnabled(bool enable);
+ bool defaultAddFileEnabled() const;
+
+ void addFile(const QString &prefix, const QString &file);
+// void removeFile(const QString &prefix, const QString &file);
+
+signals:
+ void dirtyChanged(bool dirty);
+ void addFilesTriggered(const QString &prefix);
+
+private slots:
+ void updateCurrent();
+ void updateHistoryControls();
+
+private:
+ void resolveLocationIssues(QStringList &files);
+
+private slots:
+ void onAliasChanged(const QString &alias);
+ void onPrefixChanged(const QString &prefix);
+ void onLanguageChanged(const QString &language);
+ void onRemove();
+ void onAddFiles();
+ void onAddPrefix();
+
+signals:
+ void undoStackChanged(bool canUndo, bool canRedo);
+
+public slots:
+ void onUndo();
+ void onRedo();
+
+private:
+ Ui::QrcEditor m_ui;
+ QUndoStack m_history;
+ ResourceView *m_treeview;
+ QAction *m_addFileAction;
+
+ QString m_currentAlias;
+ QString m_currentPrefix;
+ QString m_currentLanguage;
+};
+
+}
+
+#endif
diff --git a/shared/qrceditor/qrceditor.pri b/shared/qrceditor/qrceditor.pri
new file mode 100644
index 0000000000..3efd26553f
--- /dev/null
+++ b/shared/qrceditor/qrceditor.pri
@@ -0,0 +1,28 @@
+QT_BUILD_TREE=$$(QT_BUILD_TREE)
+isEmpty(QT_BUILD_TREE):QT_BUILD_TREE=$$(QTDIR)
+QT_QRC_BUILD_TREE = $$fromfile($$QT_BUILD_TREE/.qmake.cache,QT_SOURCE_TREE)
+
+INCLUDEPATH *= $$QT_QRC_BUILD_TREE/tools/designer/src/lib/shared
+INCLUDEPATH *= $$PWD $$PWD/..
+
+QT *= xml
+
+DEFINES *= QT_NO_SHARED_EXPORT
+
+# Input
+SOURCES += \
+ $$PWD/resourcefile.cpp \
+ $$PWD/resourceview.cpp \
+ $$PWD/qrceditor.cpp \
+ $$PWD/undocommands.cpp \
+
+HEADERS += \
+ $$PWD/resourcefile_p.h \
+ $$PWD/resourceview.h \
+ $$PWD/qrceditor.h \
+ $$PWD/undocommands_p.h \
+ \
+ $$PWD/../namespace_global.h \
+
+FORMS += $$PWD/qrceditor.ui
+
diff --git a/shared/qrceditor/qrceditor.ui b/shared/qrceditor/qrceditor.ui
new file mode 100644
index 0000000000..02b5780f54
--- /dev/null
+++ b/shared/qrceditor/qrceditor.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QrcEditor</class>
+ <widget class="QWidget" name="QrcEditor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>491</width>
+ <height>381</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>-1</number>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="centralWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>200</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Properties</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="aliasText"/>
+ </item>
+ <item row="1" column="1" rowspan="2">
+ <widget class="QLineEdit" name="prefixText"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="prefixLabel">
+ <property name="text">
+ <string>Prefix:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="languageLabel">
+ <property name="text">
+ <string>Language:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="languageText"/>
+ </item>
+ <item row="0" column="0" rowspan="2">
+ <widget class="QLabel" name="aliasLabel">
+ <property name="text">
+ <string>Alias:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ <zorder>centralWidget</zorder>
+ <zorder>groupBox</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/shared/qrceditor/resourcefile.cpp b/shared/qrceditor/resourcefile.cpp
new file mode 100644
index 0000000000..defd22749f
--- /dev/null
+++ b/shared/qrceditor/resourcefile.cpp
@@ -0,0 +1,982 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+TRANSLATOR qdesigner_internal::ResourceModel
+*/
+
+#include "resourcefile_p.h"
+
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QMimeData>
+#include <QtCore/QDebug>
+#include <QtGui/QIcon>
+#include <QtGui/QImageReader>
+
+#include <QtXml/QDomDocument>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+/******************************************************************************
+** ResourceFile
+*/
+
+ResourceFile::ResourceFile(const QString &file_name)
+{
+ setFileName(file_name);
+}
+
+ResourceFile::~ResourceFile()
+{
+ clearPrefixList();
+}
+
+bool ResourceFile::load()
+{
+ m_error_message.clear();
+
+ if (m_file_name.isEmpty()) {
+ m_error_message = QCoreApplication::translate("Designer", "file name is empty");
+ return false;
+ }
+
+ QFile file(m_file_name);
+ if (!file.open(QIODevice::ReadOnly)) {
+ m_error_message = file.errorString();
+ return false;
+ }
+
+ clearPrefixList();
+
+ QDomDocument doc;
+
+ QString error_msg;
+ int error_line, error_col;
+ if (!doc.setContent(&file, &error_msg, &error_line, &error_col)) {
+ m_error_message = QCoreApplication::translate("Designer", "XML error on line %1, col %2: %3")
+ .arg(error_line).arg(error_col).arg(error_msg);
+ return false;
+ }
+
+ QDomElement root = doc.firstChildElement(QLatin1String("RCC"));
+ if (root.isNull()) {
+ m_error_message = QCoreApplication::translate("Designer", "no <RCC> root element");
+ return false;
+ }
+
+ QDomElement relt = root.firstChildElement(QLatin1String("qresource"));
+ for (; !relt.isNull(); relt = relt.nextSiblingElement(QLatin1String("qresource"))) {
+
+ QString prefix = fixPrefix(relt.attribute(QLatin1String("prefix")));
+ if (prefix.isEmpty())
+ prefix = QString(QLatin1Char('/'));
+ const QString language = relt.attribute(QLatin1String("lang"));
+
+ const int idx = indexOfPrefix(prefix);
+ Prefix * p = NULL;
+ if (idx == -1) {
+ p = new Prefix(prefix, language);
+ m_prefix_list.append(p);
+ } else {
+ p = m_prefix_list[idx];
+ }
+ Q_ASSERT(p != NULL);
+
+ QDomElement felt = relt.firstChildElement(QLatin1String("file"));
+ for (; !felt.isNull(); felt = felt.nextSiblingElement(QLatin1String("file"))) {
+ const QString fileName = absolutePath(felt.text());
+ const QString alias = felt.attribute(QLatin1String("alias"));
+ File * const file = new File(p, fileName, alias);
+ p->file_list.append(file);
+ }
+ }
+
+ return true;
+}
+
+bool ResourceFile::save()
+{
+ m_error_message.clear();
+
+ if (m_file_name.isEmpty()) {
+ m_error_message = QCoreApplication::translate("Designer", "file name is empty");
+ return false;
+ }
+
+ QFile file(m_file_name);
+ if (!file.open(QIODevice::WriteOnly)) {
+ m_error_message = file.errorString();
+ return false;
+ }
+
+ QDomDocument doc;
+ QDomElement root = doc.createElement(QLatin1String("RCC"));
+ doc.appendChild(root);
+
+ const QStringList name_list = prefixList();
+
+ foreach (QString name, name_list) {
+ FileList file_list;
+ QString lang;
+ foreach (Prefix *pref, m_prefix_list) {
+ if (pref->name == name){
+ file_list += pref->file_list;
+ lang = pref->lang;
+ }
+ }
+
+ QDomElement relt = doc.createElement(QLatin1String("qresource"));
+ root.appendChild(relt);
+ relt.setAttribute(QLatin1String("prefix"), name);
+ if(!lang.isEmpty())
+ relt.setAttribute(QLatin1String("lang"), lang);
+
+ foreach (const File *f, file_list) {
+ const File &file = *f;
+ QDomElement felt = doc.createElement(QLatin1String("file"));
+ relt.appendChild(felt);
+ const QString conv_file = relativePath(file.name).replace(QDir::separator(), QLatin1Char('/'));
+ const QDomText text = doc.createTextNode(conv_file);
+ felt.appendChild(text);
+ if (!file.alias.isEmpty())
+ felt.setAttribute(QLatin1String("alias"), file.alias);
+ }
+ }
+
+ QTextStream stream(&file);
+ doc.save(stream, 4);
+
+ return true;
+}
+
+bool ResourceFile::split(const QString &_path, QString *prefix, QString *file) const
+{
+ prefix->clear();
+ file->clear();
+
+ QString path = _path;
+ if (!path.startsWith(QLatin1Char(':')))
+ return false;
+ path = path.mid(1);
+
+ for (int i = 0; i < m_prefix_list.size(); ++i) {
+ Prefix const * const &pref = m_prefix_list.at(i);
+ if (!path.startsWith(pref->name))
+ continue;
+
+ *prefix = pref->name;
+ if (pref->name == QString(QLatin1Char('/')))
+ *file = path.mid(1);
+ else
+ *file = path.mid(pref->name.size() + 1);
+
+ const QString filePath = absolutePath(*file);
+
+ for (int j = 0; j < pref->file_list.count(); j++) {
+ File const * const &f = pref->file_list.at(j);
+ if (!f->alias.isEmpty()) {
+ if (absolutePath(f->alias) == filePath) {
+ *file = f->name;
+ return true;
+ }
+ } else if (f->name == filePath)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QString ResourceFile::resolvePath(const QString &path) const
+{
+ QString prefix, file;
+ if (split(path, &prefix, &file))
+ return absolutePath(file);
+
+ return QString();
+}
+
+QStringList ResourceFile::prefixList() const
+{
+ QStringList result;
+ for (int i = 0; i < m_prefix_list.size(); ++i)
+ result.append(m_prefix_list.at(i)->name);
+ return result;
+}
+
+bool ResourceFile::isEmpty() const
+{
+ return m_file_name.isEmpty() && m_prefix_list.isEmpty();
+}
+
+QStringList ResourceFile::fileList(int pref_idx) const
+{
+ Q_ASSERT((pref_idx >= 0) && (pref_idx < m_prefix_list.count()));
+ const FileList &abs_file_list = m_prefix_list.at(pref_idx)->file_list;
+ QStringList result;
+ foreach (const File *abs_file, abs_file_list)
+ result.append(relativePath(abs_file->name));
+ return result;
+}
+
+void ResourceFile::addFile(int prefix_idx, const QString &file, int file_idx)
+{
+ Prefix * const p = m_prefix_list[prefix_idx];
+ Q_ASSERT(p != NULL);
+ FileList &files = p->file_list;
+ Q_ASSERT((file_idx >= -1) && (file_idx <= files.size()));
+ if (file_idx == -1)
+ file_idx = files.size();
+ files.insert(file_idx, new File(p, absolutePath(file)));
+}
+
+void ResourceFile::addPrefix(const QString &prefix, int prefix_idx)
+{
+ QString fixed_prefix = fixPrefix(prefix);
+ if (indexOfPrefix(fixed_prefix) != -1)
+ return;
+
+ Q_ASSERT((prefix_idx >= -1) && (prefix_idx <= m_prefix_list.size()));
+ if (prefix_idx == -1)
+ prefix_idx = m_prefix_list.size();
+ m_prefix_list.insert(prefix_idx, new Prefix(fixed_prefix));
+}
+
+void ResourceFile::removePrefix(int prefix_idx)
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ Prefix * const p = m_prefix_list.at(prefix_idx);
+ delete p;
+ m_prefix_list.removeAt(prefix_idx);
+}
+
+void ResourceFile::removeFile(int prefix_idx, int file_idx)
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ FileList &fileList = m_prefix_list[prefix_idx]->file_list;
+ Q_ASSERT((file_idx >= 0) && (file_idx < fileList.count()));
+ delete fileList.at(file_idx);
+ fileList.removeAt(file_idx);
+}
+
+void ResourceFile::replacePrefix(int prefix_idx, const QString &prefix)
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ m_prefix_list[prefix_idx]->name = fixPrefix(prefix);
+}
+
+void ResourceFile::replaceLang(int prefix_idx, const QString &lang)
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ m_prefix_list[prefix_idx]->lang = lang;
+}
+
+void ResourceFile::replaceAlias(int prefix_idx, int file_idx, const QString &alias)
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
+ Q_ASSERT((file_idx >= 0) && (file_idx < fileList.count()));
+ fileList[file_idx]->alias = alias;
+}
+
+
+void ResourceFile::replaceFile(int pref_idx, int file_idx, const QString &file)
+{
+ Q_ASSERT((pref_idx >= 0) && (pref_idx < m_prefix_list.count()));
+ FileList &fileList = m_prefix_list.at(pref_idx)->file_list;
+ Q_ASSERT((file_idx >= 0) && (file_idx < fileList.count()));
+ fileList[file_idx]->name = file;
+}
+
+int ResourceFile::indexOfPrefix(const QString &prefix) const
+{
+ QString fixed_prefix = fixPrefix(prefix);
+ for (int i = 0; i < m_prefix_list.size(); ++i) {
+ if (m_prefix_list.at(i)->name == fixed_prefix)
+ return i;
+ }
+ return -1;
+}
+
+int ResourceFile::indexOfFile(int pref_idx, const QString &file) const
+{
+ Q_ASSERT((pref_idx >= 0) && (pref_idx < m_prefix_list.count()));
+ Prefix * const p = m_prefix_list.at(pref_idx);
+ File equalFile(p, absolutePath(file));
+ return p->file_list.indexOf(&equalFile);
+}
+
+QString ResourceFile::relativePath(const QString &abs_path) const
+{
+ if (m_file_name.isEmpty() || QFileInfo(abs_path).isRelative())
+ return abs_path;
+
+ QFileInfo fileInfo(m_file_name);
+ return fileInfo.absoluteDir().relativeFilePath(abs_path);
+}
+
+QString ResourceFile::absolutePath(const QString &rel_path) const
+{
+ const QFileInfo fi(rel_path);
+ if (fi.isAbsolute())
+ return rel_path;
+
+ QString rc = QFileInfo(m_file_name).path();
+ rc += QDir::separator();
+ rc += rel_path;
+ return QDir::cleanPath(rc);
+}
+
+bool ResourceFile::contains(const QString &prefix, const QString &file) const
+{
+ int pref_idx = indexOfPrefix(prefix);
+ if (pref_idx == -1)
+ return false;
+ if (file.isEmpty())
+ return true;
+ Q_ASSERT((pref_idx >= 0) && (pref_idx < m_prefix_list.count()));
+ Prefix * const p = m_prefix_list.at(pref_idx);
+ Q_ASSERT(p != NULL);
+ File equalFile(p, absolutePath(file));
+ return p->file_list.contains(&equalFile);
+}
+
+bool ResourceFile::contains(int pref_idx, const QString &file) const
+{
+ Q_ASSERT((pref_idx >= 0) && (pref_idx < m_prefix_list.count()));
+ Prefix * const p = m_prefix_list.at(pref_idx);
+ File equalFile(p, absolutePath(file));
+ return p->file_list.contains(&equalFile);
+}
+
+/*static*/ QString ResourceFile::fixPrefix(const QString &prefix)
+{
+ const QChar slash = QLatin1Char('/');
+ QString result = QString(slash);
+ for (int i = 0; i < prefix.size(); ++i) {
+ const QChar c = prefix.at(i);
+ if (c == slash && result.at(result.size() - 1) == slash)
+ continue;
+ result.append(c);
+ }
+
+ if (result.size() > 1 && result.endsWith(slash))
+ result = result.mid(0, result.size() - 1);
+
+ return result;
+}
+
+int ResourceFile::prefixCount() const
+{
+ return m_prefix_list.size();
+}
+
+QString ResourceFile::prefix(int idx) const
+{
+ Q_ASSERT((idx >= 0) && (idx < m_prefix_list.count()));
+ return m_prefix_list.at(idx)->name;
+}
+
+QString ResourceFile::lang(int idx) const
+{
+ Q_ASSERT((idx >= 0) && (idx < m_prefix_list.count()));
+ return m_prefix_list.at(idx)->lang;
+}
+
+int ResourceFile::fileCount(int prefix_idx) const
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ return m_prefix_list.at(prefix_idx)->file_list.size();
+}
+
+QString ResourceFile::file(int prefix_idx, int file_idx) const
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
+ Q_ASSERT((file_idx >= 0) && (file_idx < fileList.count()));
+ return fileList.at(file_idx)->name;
+}
+
+QString ResourceFile::alias(int prefix_idx, int file_idx) const
+{
+ Q_ASSERT((prefix_idx >= 0) && (prefix_idx < m_prefix_list.count()));
+ FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
+ Q_ASSERT((file_idx >= 0) && (file_idx < fileList.count()));
+ return fileList.at(file_idx)->alias;
+}
+
+void * ResourceFile::prefixPointer(int prefixIndex) const
+{
+ Q_ASSERT((prefixIndex >= 0) && (prefixIndex < m_prefix_list.count()));
+ return m_prefix_list.at(prefixIndex);
+}
+
+void * ResourceFile::filePointer(int prefixIndex, int fileIndex) const
+{
+ Q_ASSERT((prefixIndex >= 0) && (prefixIndex < m_prefix_list.count()));
+ FileList &fileList = m_prefix_list.at(prefixIndex)->file_list;
+ Q_ASSERT((fileIndex >= 0) && (fileIndex < fileList.count()));
+ return fileList.at(fileIndex);
+}
+
+int ResourceFile::prefixPointerIndex(const Prefix *prefix) const
+{
+ int const count = m_prefix_list.count();
+ for (int i = 0; i < count; i++) {
+ Prefix * const other = m_prefix_list.at(i);
+ if (*other == *prefix)
+ return i;
+ }
+ return -1;
+}
+
+void ResourceFile::clearPrefixList()
+{
+ qDeleteAll(m_prefix_list);
+ m_prefix_list.clear();
+}
+
+/******************************************************************************
+** ResourceModel
+*/
+
+ResourceModel::ResourceModel(const ResourceFile &resource_file, QObject *parent)
+ : QAbstractItemModel(parent), m_resource_file(resource_file), m_dirty(false)
+{
+ // Only action that works for QListWidget and the like.
+ setSupportedDragActions(Qt::CopyAction);
+}
+
+void ResourceModel::setDirty(bool b)
+{
+ if (b == m_dirty)
+ return;
+
+ m_dirty = b;
+ emit dirtyChanged(b);
+}
+
+QModelIndex ResourceModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (column != 0)
+ return QModelIndex();
+
+ void * internalPointer = NULL;
+ if (parent.isValid()) {
+ void * const pip = parent.internalPointer();
+ if (pip == NULL)
+ return QModelIndex();
+
+ // File node
+ Node * const node = reinterpret_cast<Node *>(pip);
+ Prefix * const prefix = node->prefix();
+ Q_ASSERT(prefix != NULL);
+ if ((row < 0) || (row >= prefix->file_list.count()))
+ return QModelIndex();
+ const int prefixIndex = m_resource_file.prefixPointerIndex(prefix);
+ const int fileIndex = row;
+ internalPointer = m_resource_file.filePointer(prefixIndex, fileIndex);
+ } else {
+ // Prefix node
+ if ((row < 0) || (row >= m_resource_file.prefixCount()))
+ return QModelIndex();
+ internalPointer = m_resource_file.prefixPointer(row);
+ }
+ Q_ASSERT(internalPointer != NULL);
+ return createIndex(row, 0, internalPointer);
+}
+
+QModelIndex ResourceModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ void * const internalPointer = index.internalPointer();
+ if (internalPointer == NULL)
+ return QModelIndex();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix * const prefix = node->prefix();
+ Q_ASSERT(prefix != NULL);
+ bool const isFileNode = (prefix != node);
+
+ if (isFileNode) {
+ const int row = m_resource_file.prefixPointerIndex(prefix);
+ Q_ASSERT(row >= 0);
+ return createIndex(row, 0, prefix);
+ } else {
+ return QModelIndex();
+ }
+}
+
+int ResourceModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ void * const internalPointer = parent.internalPointer();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix * const prefix = node->prefix();
+ Q_ASSERT(prefix != NULL);
+ bool const isFileNode = (prefix != node);
+
+ if (isFileNode) {
+ return 0;
+ } else {
+ return prefix->file_list.count();
+ }
+ } else {
+ return m_resource_file.prefixCount();
+ }
+}
+
+int ResourceModel::columnCount(const QModelIndex &) const
+{
+ return 1;
+}
+
+bool ResourceModel::hasChildren(const QModelIndex &parent) const
+{
+ return rowCount(parent) != 0;
+}
+
+bool ResourceModel::iconFileExtension(const QString &path)
+{
+ static QStringList ext_list;
+ if (ext_list.isEmpty()) {
+ const QList<QByteArray> _ext_list = QImageReader::supportedImageFormats();
+ foreach (const QByteArray &ext, _ext_list) {
+ QString dotExt = QString(QLatin1Char('.'));
+ dotExt += QString::fromAscii(ext);
+ ext_list.append(dotExt);
+ }
+ }
+
+ foreach (QString ext, ext_list) {
+ if (path.endsWith(ext, Qt::CaseInsensitive))
+ return true;
+ }
+
+ return false;
+}
+
+static inline void appendParenthesized(const QString &what, QString &s)
+{
+ s += QLatin1String(" (");
+ s += what;
+ s += QLatin1Char(')');
+}
+
+QVariant ResourceModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ void * const internalPointer = index.internalPointer();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix const * const prefix = node->prefix();
+ File const * const file = node->file();
+ Q_ASSERT(prefix != NULL);
+ bool const isFileNode = (prefix != node);
+
+ QVariant result;
+
+ switch (role) {
+ case Qt::DisplayRole:
+ {
+ QString stringRes;
+ if (!isFileNode) {
+ // Prefix node
+ stringRes = prefix->name;
+ const QString &lang = prefix->lang;
+ if(!lang.isEmpty())
+ appendParenthesized(lang, stringRes);
+ } else {
+ // File node
+ Q_ASSERT(file != NULL);
+ stringRes = QFileInfo(file->name).fileName();
+ const QString alias = file->alias;
+ if(!alias.isEmpty())
+ appendParenthesized(alias, stringRes);
+ }
+ result = stringRes;
+ }
+ break;
+ case Qt::DecorationRole:
+ if (isFileNode) {
+ // File node
+ Q_ASSERT(file != NULL);
+ const QString path = m_resource_file.absolutePath(file->name);
+ if (iconFileExtension(path)) {
+ const QIcon icon(path);
+ if (!icon.isNull())
+ result = icon;
+ }
+ }
+ break;
+ case Qt::ToolTipRole:
+ if (isFileNode) {
+ // File node
+ Q_ASSERT(file != NULL);
+ QString conv_file = m_resource_file.relativePath(file->name);
+ QString stringRes = conv_file.replace(QDir::separator(), QLatin1Char('/'));
+ const QString &alias_file = file->alias;
+ if(!alias_file.isEmpty())
+ appendParenthesized(alias_file, stringRes);
+
+ result = stringRes;
+ result = "Qt::ToolTipRole " + stringRes;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return result;
+}
+
+void ResourceModel::getItem(const QModelIndex &index, QString &prefix, QString &file) const
+{
+ prefix.clear();
+ file.clear();
+
+ if (!index.isValid())
+ return;
+
+ void * const internalPointer = index.internalPointer();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix * const p = node->prefix();
+ Q_ASSERT(p != NULL);
+ bool const isFileNode = (p != node);
+
+ if (isFileNode) {
+ File * const f = node->file();
+ Q_ASSERT(f != NULL);
+ if (!f->alias.isEmpty())
+ file = f->alias;
+ else
+ file = f->name;
+ } else {
+ prefix = p->name;
+ }
+}
+
+QString ResourceModel::lang(const QModelIndex &index) const
+{
+ if(!index.isValid())
+ return QString();
+
+ return m_resource_file.lang(index.row());
+}
+
+QString ResourceModel::alias(const QModelIndex &index) const
+{
+ if(!index.isValid() || !index.parent().isValid())
+ return QString();
+ return m_resource_file.alias(index.parent().row(), index.row());
+}
+
+QString ResourceModel::file(const QModelIndex &index) const
+{
+ if(!index.isValid() || !index.parent().isValid())
+ return QString();
+ return m_resource_file.file(index.parent().row(), index.row());
+}
+
+QModelIndex ResourceModel::getIndex(const QString &prefixed_file)
+{
+ QString prefix, file;
+ if (!m_resource_file.split(prefixed_file, &prefix, &file))
+ return QModelIndex();
+ return getIndex(prefix, file);
+}
+
+QModelIndex ResourceModel::getIndex(const QString &prefix, const QString &file)
+{
+ if (prefix.isEmpty())
+ return QModelIndex();
+
+ const int pref_idx = m_resource_file.indexOfPrefix(prefix);
+ if (pref_idx == -1)
+ return QModelIndex();
+
+ const QModelIndex pref_model_idx = index(pref_idx, 0, QModelIndex());
+ if (file.isEmpty())
+ return pref_model_idx;
+
+ const int file_idx = m_resource_file.indexOfFile(pref_idx, file);
+ if (file_idx == -1)
+ return QModelIndex();
+
+ return index(file_idx, 0, pref_model_idx);
+}
+
+QModelIndex ResourceModel::prefixIndex(const QModelIndex &sel_idx) const
+{
+ if (!sel_idx.isValid())
+ return QModelIndex();
+ const QModelIndex parentIndex = parent(sel_idx);
+ return parentIndex.isValid() ? parentIndex : sel_idx;
+}
+
+QModelIndex ResourceModel::addNewPrefix()
+{
+ const QString format = QLatin1String("/new/prefix%1");
+ int i = 1;
+ QString prefix = format.arg(i);
+ for ( ; m_resource_file.contains(prefix); i++)
+ prefix = format.arg(i);
+
+ i = rowCount(QModelIndex());
+ beginInsertRows(QModelIndex(), i, i);
+ m_resource_file.addPrefix(prefix);
+ endInsertRows();
+
+ setDirty(true);
+
+ return index(i, 0, QModelIndex());
+}
+
+QModelIndex ResourceModel::addFiles(const QModelIndex &model_idx, const QStringList &file_list)
+{
+ const QModelIndex prefixModelIndex = prefixIndex(model_idx);
+ const int prefixArrayIndex = prefixModelIndex.row();
+ const int cursorFileArrayIndex = (prefixModelIndex == model_idx) ? 0 : model_idx.row();
+ int dummy;
+ int lastFileArrayIndex;
+ addFiles(prefixArrayIndex, file_list, cursorFileArrayIndex, dummy, lastFileArrayIndex);
+ return index(lastFileArrayIndex, 0, prefixModelIndex);
+}
+
+void ResourceModel::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
+ int &firstFile, int &lastFile)
+{
+ Q_UNUSED(cursorFile);
+ const QModelIndex prefix_model_idx = index(prefixIndex, 0, QModelIndex());
+ const QStringList &file_list = fileNames;
+ firstFile = -1;
+ lastFile = -1;
+
+ if (!prefix_model_idx.isValid()) {
+ return;
+ }
+ const int prefix_idx = prefixIndex;
+
+ QStringList unique_list;
+ foreach (QString file, file_list) {
+ if (!m_resource_file.contains(prefix_idx, file) && !unique_list.contains(file))
+ unique_list.append(file);
+ }
+
+ if (unique_list.isEmpty()) {
+ return;
+ }
+ const int cnt = m_resource_file.fileCount(prefix_idx);
+ beginInsertRows(prefix_model_idx, cnt, cnt + unique_list.count() - 1); // ### FIXME
+
+ foreach (QString file, file_list)
+ m_resource_file.addFile(prefix_idx, file);
+
+ const QFileInfo fi(file_list.last());
+ m_lastResourceDir = fi.absolutePath();
+
+ endInsertRows();
+ setDirty(true);
+
+ firstFile = cnt;
+ lastFile = cnt + unique_list.count() - 1;
+}
+
+
+void ResourceModel::insertPrefix(int prefixIndex, const QString &prefix,
+ const QString &lang)
+{
+ beginInsertRows(QModelIndex(), prefixIndex, prefixIndex);
+ m_resource_file.addPrefix(prefix, prefixIndex);
+ m_resource_file.replaceLang(prefixIndex, lang);
+ endInsertRows();
+ setDirty(true);
+}
+
+void ResourceModel::insertFile(int prefixIndex, int fileIndex,
+ const QString &fileName, const QString &alias)
+{
+ const QModelIndex parent = index(prefixIndex, 0, QModelIndex());
+ beginInsertRows(parent, fileIndex, fileIndex);
+ m_resource_file.addFile(prefixIndex, fileName, fileIndex);
+ m_resource_file.replaceAlias(prefixIndex, fileIndex, alias);
+ endInsertRows();
+ setDirty(true);
+}
+
+void ResourceModel::changePrefix(const QModelIndex &model_idx, const QString &prefix)
+{
+ if (!model_idx.isValid())
+ return;
+
+ const QModelIndex prefix_model_idx = prefixIndex(model_idx);
+ const int prefix_idx = model_idx.row();
+ if (m_resource_file.prefix(prefix_idx) == ResourceFile::fixPrefix(prefix))
+ return;
+
+ if(m_resource_file.contains(prefix))
+ return;
+
+ m_resource_file.replacePrefix(prefix_idx, prefix);
+ emit dataChanged(prefix_model_idx, prefix_model_idx);
+ setDirty(true);
+}
+
+void ResourceModel::changeLang(const QModelIndex &model_idx, const QString &lang)
+{
+ if (!model_idx.isValid())
+ return;
+
+ const QModelIndex prefix_model_idx = prefixIndex(model_idx);
+ const int prefix_idx = model_idx.row();
+ if (m_resource_file.lang(prefix_idx) == lang)
+ return;
+
+ m_resource_file.replaceLang(prefix_idx, lang);
+ emit dataChanged(prefix_model_idx, prefix_model_idx);
+ setDirty(true);
+}
+
+void ResourceModel::changeAlias(const QModelIndex &index, const QString &alias)
+{
+ if (!index.parent().isValid())
+ return;
+
+ if(m_resource_file.alias(index.parent().row(), index.row()) == alias)
+ return;
+ m_resource_file.replaceAlias(index.parent().row(), index.row(), alias);
+ emit dataChanged(index, index);
+ setDirty(true);
+}
+
+QModelIndex ResourceModel::deleteItem(const QModelIndex &idx)
+{
+ if (!idx.isValid())
+ return QModelIndex();
+
+ QString dummy, file;
+ getItem(idx, dummy, file);
+ int prefix_idx = -1;
+ int file_idx = -1;
+
+ beginRemoveRows(parent(idx), idx.row(), idx.row());
+ if (file.isEmpty()) {
+ // Remove prefix
+ prefix_idx = idx.row();
+ m_resource_file.removePrefix(prefix_idx);
+ if (prefix_idx == m_resource_file.prefixCount())
+ --prefix_idx;
+ } else {
+ // Remove file
+ prefix_idx = prefixIndex(idx).row();
+ file_idx = idx.row();
+ m_resource_file.removeFile(prefix_idx, file_idx);
+ if (file_idx == m_resource_file.fileCount(prefix_idx))
+ --file_idx;
+ }
+ endRemoveRows();
+
+ setDirty(true);
+
+ if (prefix_idx == -1)
+ return QModelIndex();
+ const QModelIndex prefix_model_idx = index(prefix_idx, 0, QModelIndex());
+ if (file_idx == -1)
+ return prefix_model_idx;
+ return index(file_idx, 0, prefix_model_idx);
+}
+
+bool ResourceModel::reload()
+{
+ const bool result = m_resource_file.load();
+ if (result)
+ setDirty(false);
+ return result;
+}
+
+bool ResourceModel::save()
+{
+ const bool result = m_resource_file.save();
+ if (result)
+ setDirty(false);
+ return result;
+}
+
+QString ResourceModel::lastResourceOpenDirectory() const
+{
+ if (m_lastResourceDir.isEmpty())
+ return absolutePath(QString());
+ return m_lastResourceDir;
+}
+
+// Create a resource path 'prefix:/file'
+QString ResourceModel::resourcePath(const QString &prefix, const QString &file)
+{
+ QString rc = QString(QLatin1Char(':'));
+ rc += prefix;
+ rc += QLatin1Char('/');
+ rc += file;
+ return QDir::cleanPath(rc);
+}
+
+QMimeData *ResourceModel::mimeData(const QModelIndexList & indexes) const
+{
+ if (indexes.size() != 1)
+ return 0;
+
+ QString prefix, file;
+ getItem(indexes.front(), prefix, file);
+ if (prefix.isEmpty() || file.isEmpty())
+ return 0;
+
+ // DnD format of Designer 4.4
+ QDomDocument doc;
+ QDomElement elem = doc.createElement(QLatin1String("resource"));
+ elem.setAttribute(QLatin1String("type"), QLatin1String("image"));
+ elem.setAttribute(QLatin1String("file"), resourcePath(prefix, file));
+ doc.appendChild(elem);
+
+ QMimeData *rc = new QMimeData;
+ rc->setText(doc.toString());
+ return rc;
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/shared/qrceditor/resourcefile_p.h b/shared/qrceditor/resourcefile_p.h
new file mode 100644
index 0000000000..c3de0f65cf
--- /dev/null
+++ b/shared/qrceditor/resourcefile_p.h
@@ -0,0 +1,266 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RESOURCEFILE_H
+#define RESOURCEFILE_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QAbstractItemModel>
+
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+#ifdef BUILD_VSIP
+# define RESOURCE_EXPORT
+#else
+# define RESOURCE_EXPORT QDESIGNER_SHARED_EXPORT
+#endif
+
+struct File;
+struct Prefix;
+
+/*!
+ \class Node
+
+ Forms the base class for nodes in a \l ResourceFile tree.
+*/
+class Node
+{
+ File *m_file;
+ Prefix *m_prefix;
+protected:
+ Node(File *file, Prefix *prefix) : m_file(file), m_prefix(prefix)
+ {
+ Q_ASSERT(m_prefix != NULL);
+ }
+public:
+ File * file() { return m_file; }
+ Prefix * prefix() { Q_ASSERT(m_prefix != NULL); return m_prefix; }
+};
+
+/*!
+ \class File
+
+ Represents a file node in a \l ResourceFile tree.
+*/
+struct File : public Node {
+ File(Prefix *prefix, const QString &_name = QString(), const QString &_alias = QString())
+ : Node(this, prefix), name(_name), alias(_alias) {}
+ bool operator < (const File &other) const { return name < other.name; }
+ bool operator == (const File &other) const { return name == other.name; }
+ bool operator != (const File &other) const { return name != other.name; }
+ QString name;
+ QString alias;
+};
+typedef QList<File *> FileList;
+
+/*!
+ \class Prefix
+
+ Represents a prefix node in a \l ResourceFile tree.
+*/
+struct Prefix : public Node {
+ Prefix(const QString &_name = QString(), const QString &_lang = QString(), const FileList &_file_list = FileList())
+ : Node(NULL, this), name(_name), lang(_lang), file_list(_file_list) {}
+ ~Prefix()
+ {
+ qDeleteAll(file_list);
+ file_list.clear();
+ }
+ bool operator == (const Prefix &other) const { return (name == other.name) && (lang == other.lang); }
+ QString name;
+ QString lang;
+ FileList file_list;
+};
+typedef QList<Prefix *> PrefixList;
+
+/*!
+ \class ResourceFile
+
+ Represents the structure of a Qt Resource File (.qrc) file.
+*/
+class RESOURCE_EXPORT ResourceFile
+{
+public:
+ ResourceFile(const QString &file_name = QString());
+ ~ResourceFile();
+
+ void setFileName(const QString &file_name) { m_file_name = file_name; }
+ QString fileName() const { return m_file_name; }
+ bool load();
+ bool save();
+ QString errorMessage() const { return m_error_message; }
+
+private:
+ QString resolvePath(const QString &path) const;
+ QStringList prefixList() const;
+ QStringList fileList(int pref_idx) const;
+
+public:
+ int prefixCount() const;
+ QString prefix(int idx) const;
+ QString lang(int idx) const;
+
+ int fileCount(int prefix_idx) const;
+
+ QString file(int prefix_idx, int file_idx) const;
+ QString alias(int prefix_idx, int file_idx) const;
+
+ void addFile(int prefix_idx, const QString &file, int file_idx = -1);
+ void addPrefix(const QString &prefix, int prefix_idx = -1);
+
+ void removePrefix(int prefix_idx);
+ void removeFile(int prefix_idx, int file_idx);
+
+ void replacePrefix(int prefix_idx, const QString &prefix);
+ void replaceLang(int prefix_idx, const QString &lang);
+ void replaceAlias(int prefix_idx, int file_idx, const QString &alias);
+
+private:
+ void replaceFile(int pref_idx, int file_idx, const QString &file);
+public:
+ int indexOfPrefix(const QString &prefix) const;
+ int indexOfFile(int pref_idx, const QString &file) const;
+
+ bool contains(const QString &prefix, const QString &file = QString()) const;
+ bool contains(int pref_idx, const QString &file) const;
+
+ QString relativePath(const QString &abs_path) const;
+ QString absolutePath(const QString &rel_path) const;
+
+ static QString fixPrefix(const QString &prefix);
+ bool split(const QString &path, QString *prefix, QString *file) const;
+
+private:
+ bool isEmpty() const;
+
+private:
+ PrefixList m_prefix_list;
+ QString m_file_name;
+ QString m_error_message;
+
+public:
+ void * prefixPointer(int prefixIndex) const;
+ void * filePointer(int prefixIndex, int fileIndex) const;
+ int prefixPointerIndex(const Prefix *prefix) const;
+
+private:
+ void clearPrefixList();
+};
+
+/*!
+ \class ResourceModel
+
+ Wraps a \l ResourceFile as a single-column tree model.
+*/
+class RESOURCE_EXPORT ResourceModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ ResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
+
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ bool hasChildren(const QModelIndex &parent) const;
+
+protected:
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+public:
+ QString fileName() const { return m_resource_file.fileName(); }
+ void setFileName(const QString &file_name) { m_resource_file.setFileName(file_name); }
+ void getItem(const QModelIndex &index, QString &prefix, QString &file) const;
+
+ QString lang(const QModelIndex &index) const;
+ QString alias(const QModelIndex &index) const;
+ QString file(const QModelIndex &index) const;
+
+ virtual QModelIndex addNewPrefix();
+ virtual QModelIndex addFiles(const QModelIndex &idx, const QStringList &file_list);
+ void addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile, int &firstFile, int &lastFile);
+ void insertPrefix(int prefixIndex, const QString &prefix, const QString &lang);
+ void insertFile(int prefixIndex, int fileIndex, const QString &fileName, const QString &alias);
+ virtual void changePrefix(const QModelIndex &idx, const QString &prefix);
+ virtual void changeLang(const QModelIndex &idx, const QString &lang);
+ virtual void changeAlias(const QModelIndex &idx, const QString &alias);
+ virtual QModelIndex deleteItem(const QModelIndex &idx);
+ QModelIndex getIndex(const QString &prefix, const QString &file);
+ QModelIndex getIndex(const QString &prefixed_file);
+ QModelIndex prefixIndex(const QModelIndex &sel_idx) const;
+
+ QString absolutePath(const QString &path) const
+ { return m_resource_file.absolutePath(path); }
+
+private:
+ QString relativePath(const QString &path) const
+ { return m_resource_file.relativePath(path); }
+ QString lastResourceOpenDirectory() const;
+
+public:
+ virtual bool reload();
+ virtual bool save();
+ // QString errorMessage() const { return m_resource_file.errorMessage(); }
+
+ bool dirty() const { return m_dirty; }
+ void setDirty(bool b);
+
+private:
+ virtual QMimeData *mimeData (const QModelIndexList & indexes) const;
+
+ static bool iconFileExtension(const QString &path);
+ static QString resourcePath(const QString &prefix, const QString &file);
+
+signals:
+ void dirtyChanged(bool b);
+
+private:
+ ResourceFile m_resource_file;
+ bool m_dirty;
+ QString m_lastResourceDir;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // RESOURCEFILE_H
diff --git a/shared/qrceditor/resourceview.cpp b/shared/qrceditor/resourceview.cpp
new file mode 100644
index 0000000000..891b19aeae
--- /dev/null
+++ b/shared/qrceditor/resourceview.cpp
@@ -0,0 +1,661 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "resourceview.h"
+#include "undocommands_p.h"
+
+#include <QtGui/QHeaderView>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QApplication>
+#include <QtGui/QInputDialog>
+#include <QtGui/QFileDialog>
+#include <QtCore/QtDebug>
+#include <QtGui/QUndoStack>
+
+namespace SharedTools {
+
+/*!
+ \class FileEntryBackup
+
+ Backups a file node.
+*/
+class FileEntryBackup : public EntryBackup
+{
+private:
+ int m_fileIndex;
+ QString m_alias;
+
+public:
+ FileEntryBackup(ResourceModel &model, int prefixIndex, int fileIndex,
+ const QString &fileName, const QString &alias)
+ : EntryBackup(model, prefixIndex, fileName), m_fileIndex(fileIndex),
+ m_alias(alias) { }
+ void restore() const;
+};
+
+void FileEntryBackup::restore() const
+{
+ m_model->insertFile(m_prefixIndex, m_fileIndex, m_name, m_alias);
+}
+
+/*!
+ \class PrefixEntryBackup
+
+ Backups a prefix node including children.
+*/
+class PrefixEntryBackup : public EntryBackup
+{
+private:
+ QString m_language;
+ QList<FileEntryBackup> m_files;
+
+public:
+ PrefixEntryBackup(ResourceModel &model, int prefixIndex, const QString &prefix,
+ const QString &language, const QList<FileEntryBackup> &files)
+ : EntryBackup(model, prefixIndex, prefix), m_language(language), m_files(files) { }
+ void restore() const;
+};
+
+void PrefixEntryBackup::restore() const
+{
+ m_model->insertPrefix(m_prefixIndex, m_name, m_language);
+ foreach (const FileEntryBackup &entry, m_files) {
+ entry.restore();
+ }
+}
+
+namespace Internal {
+
+class RelativeResourceModel : public ResourceModel
+{
+public:
+ RelativeResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ if (!index.isValid())
+ return QVariant();
+/*
+ void const * const internalPointer = index.internalPointer();
+
+ if ((role == Qt::DisplayRole) && (internalPointer != NULL))
+ return ResourceModel::data(index, Qt::ToolTipRole);
+*/
+ return ResourceModel::data(index, role);
+ }
+
+ void setResourceDragEnabled(bool e) { m_resourceDragEnabled = e; }
+ bool resourceDragEnabled() const { return m_resourceDragEnabled; }
+
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ EntryBackup * removeEntry(const QModelIndex &index);
+
+private:
+ bool m_resourceDragEnabled;
+};
+
+RelativeResourceModel::RelativeResourceModel(const ResourceFile &resource_file, QObject *parent) :
+ ResourceModel(resource_file, parent),
+ m_resourceDragEnabled(false)
+{
+}
+
+Qt::ItemFlags RelativeResourceModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags rc = ResourceModel::flags(index);
+ if ((rc & Qt::ItemIsEnabled) && m_resourceDragEnabled)
+ rc |= Qt::ItemIsDragEnabled;
+ return rc;
+}
+
+EntryBackup * RelativeResourceModel::removeEntry(const QModelIndex &index)
+{
+ const QModelIndex prefixIndex = this->prefixIndex(index);
+ const bool isPrefixNode = (prefixIndex == index);
+
+ // Create backup, remove, return backup
+ if (isPrefixNode) {
+ QString dummy;
+ QString prefixBackup;
+ getItem(index, prefixBackup, dummy);
+ const QString languageBackup = lang(index);
+ const int childCount = rowCount(index);
+ QList<FileEntryBackup> filesBackup;
+ for (int i = 0; i < childCount; i++) {
+ const QModelIndex childIndex = this->index(i, 0, index);
+ const QString fileNameBackup = file(childIndex);
+ const QString aliasBackup = alias(childIndex);
+ FileEntryBackup entry(*this, index.row(), i, fileNameBackup, aliasBackup);
+ filesBackup << entry;
+ }
+ deleteItem(index);
+ return new PrefixEntryBackup(*this, index.row(), prefixBackup, languageBackup, filesBackup);
+ } else {
+ const QString fileNameBackup = file(index);
+ const QString aliasBackup = alias(index);
+ deleteItem(index);
+ return new FileEntryBackup(*this, prefixIndex.row(), index.row(), fileNameBackup, aliasBackup);
+ }
+}
+
+} // namespace Internal
+
+ResourceView::ResourceView(QUndoStack *history, QWidget *parent) :
+ QTreeView(parent),
+ m_qrcModel(new Internal::RelativeResourceModel(m_qrcFile, this)),
+ m_addFile(0),
+ m_editAlias(0),
+ m_removeItem(0),
+ m_addPrefix(0),
+ m_editPrefix(0),
+ m_editLang(0),
+ m_viewMenu(0),
+ m_defaultAddFile(false),
+ m_history(history),
+ m_mergeId(-1)
+{
+ advanceMergeId();
+ setModel(m_qrcModel);
+
+ header()->hide();
+
+ connect(m_qrcModel, SIGNAL(dirtyChanged(bool)),
+ this, SIGNAL(dirtyChanged(bool)));
+
+ setupMenu();
+
+ setDefaultAddFileEnabled(true);
+ enableContextMenu(true);
+}
+
+ResourceView::~ResourceView(void)
+{
+
+}
+
+void ResourceView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ emit currentIndexChanged();
+}
+
+bool ResourceView::isDirty() const
+{
+ return m_qrcModel->dirty();
+}
+
+void ResourceView::setDirty(bool dirty)
+{
+ m_qrcModel->setDirty(dirty);
+}
+
+void ResourceView::setDefaultAddFileEnabled(bool enable)
+{
+ m_defaultAddFile = enable;
+}
+
+bool ResourceView::defaultAddFileEnabled() const
+{
+ return m_defaultAddFile;
+}
+
+void ResourceView::findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const
+{
+ // Concept:
+ // - Make selection stay on same Y level
+ // - Enable user to hit delete several times in row
+ const bool hasLowerBrother = m_qrcModel->hasIndex(row + 1,
+ 0, parent);
+ if (hasLowerBrother) {
+ // First or mid child -> lower brother
+ // o
+ // +--o
+ // +-[o] <-- deleted
+ // +--o <-- chosen
+ // o
+ // --> return unmodified
+ } else {
+ if (parent == QModelIndex()) {
+ // Last prefix node
+ if (row == 0) {
+ // Last and only prefix node
+ // [o] <-- deleted
+ // +--o
+ // +--o
+ row = -1;
+ parent = QModelIndex();
+ } else {
+ const QModelIndex upperBrother = m_qrcModel->index(row - 1,
+ 0, parent);
+ if (m_qrcModel->hasChildren(upperBrother)) {
+ // o
+ // +--o <-- selected
+ // [o] <-- deleted
+ row = m_qrcModel->rowCount(upperBrother) - 1;
+ parent = upperBrother;
+ } else {
+ // o
+ // o <-- selected
+ // [o] <-- deleted
+ row--;
+ }
+ }
+ } else {
+ // Last file node
+ const bool hasPrefixBelow = m_qrcModel->hasIndex(parent.row() + 1,
+ parent.column(), QModelIndex());
+ if (hasPrefixBelow) {
+ // Last child or parent with lower brother -> lower brother of parent
+ // o
+ // +--o
+ // +-[o] <-- deleted
+ // o <-- chosen
+ row = parent.row() + 1;
+ parent = QModelIndex();
+ } else {
+ const bool onlyChild = row == 0;
+ if (onlyChild) {
+ // Last and only child of last parent -> parent
+ // o <-- chosen
+ // +-[o] <-- deleted
+ row = parent.row();
+ parent = m_qrcModel->parent(parent);
+ } else {
+ // Last child of last parent -> upper brother
+ // o
+ // +--o <-- chosen
+ // +-[o] <-- deleted
+ row--;
+ }
+ }
+ }
+ }
+}
+
+EntryBackup * ResourceView::removeEntry(const QModelIndex &index)
+{
+ Q_ASSERT(m_qrcModel != NULL);
+ return m_qrcModel->removeEntry(index);
+}
+
+void ResourceView::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
+ int &firstFile, int &lastFile)
+{
+ Q_ASSERT(m_qrcModel != NULL);
+ m_qrcModel->addFiles(prefixIndex, fileNames, cursorFile, firstFile, lastFile);
+
+ // Expand prefix node
+ const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
+ if (prefixModelIndex.isValid()) {
+ this->setExpanded(prefixModelIndex, true);
+ }
+}
+
+void ResourceView::removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex)
+{
+ Q_ASSERT((prefixIndex >= 0) && (prefixIndex < m_qrcModel->rowCount(QModelIndex())));
+ const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
+ Q_ASSERT(prefixModelIndex != QModelIndex());
+ Q_ASSERT((firstFileIndex >= 0) && (firstFileIndex < m_qrcModel->rowCount(prefixModelIndex)));
+ Q_ASSERT((lastFileIndex >= 0) && (lastFileIndex < m_qrcModel->rowCount(prefixModelIndex)));
+
+ for (int i = lastFileIndex; i >= firstFileIndex; i--) {
+ const QModelIndex index = m_qrcModel->index(i, 0, prefixModelIndex);
+ delete removeEntry(index);
+ }
+}
+
+void ResourceView::enableContextMenu(bool enable)
+{
+ if (enable) {
+ connect(this, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(popupMenu(const QModelIndex &)));
+ } else {
+ disconnect(this, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(popupMenu(const QModelIndex &)));
+ }
+}
+
+void ResourceView::setupMenu()
+{
+ m_viewMenu = new QMenu(this);
+/*
+ m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SIGNAL(addFiles()));
+ m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
+ m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SLOT(addPrefix()));
+ m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
+ m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
+ m_viewMenu->addSeparator();
+ m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SLOT(removeItem()));
+*/
+ m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SLOT(onAddFiles()));
+ m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
+ m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SIGNAL(addPrefixTriggered()));
+ m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
+ m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
+ m_viewMenu->addSeparator();
+ m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SIGNAL(removeItem()));
+}
+
+void ResourceView::mouseReleaseEvent(QMouseEvent *e)
+{
+ m_releasePos = e->globalPos();
+ if (e->button() != Qt::RightButton)
+ m_releasePos = QPoint();
+
+ QTreeView::mouseReleaseEvent(e);
+}
+
+void ResourceView::popupMenu(const QModelIndex &index)
+{
+ if (!m_releasePos.isNull()) {
+ m_addFile->setEnabled(index.isValid());
+ m_editPrefix->setEnabled(index.isValid());
+ m_editLang->setEnabled(index.isValid());
+ m_removeItem->setEnabled(index.isValid());
+
+ m_viewMenu->popup(m_releasePos);
+ }
+}
+
+QModelIndex ResourceView::addPrefix()
+{
+ const QModelIndex idx = m_qrcModel->addNewPrefix();
+ selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
+ return idx;
+}
+
+QStringList ResourceView::fileNamesToAdd()
+{
+ return QFileDialog::getOpenFileNames(this, tr("Open file"),
+ m_qrcModel->absolutePath(QString()),
+ tr("All files (*.*)"));
+}
+
+void ResourceView::onAddFiles()
+{
+ emit addFilesTriggered(currentPrefix());
+}
+
+void ResourceView::addFiles(QStringList fileList, const QModelIndex &index)
+{
+ if (fileList.isEmpty())
+ return;
+ QModelIndex idx = index;
+ if (!m_qrcModel->hasChildren(QModelIndex())) {
+ idx = addPrefix();
+ expand(idx);
+ }
+
+ idx = m_qrcModel->addFiles(idx, fileList);
+
+ if (idx.isValid()) {
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+ setExpanded(preindex, true);
+ selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
+ QString prefix, file;
+ m_qrcModel->getItem(preindex, prefix, file);
+// XXX emit filesAdded(prefix, fileList);
+ }
+}
+
+void ResourceView::addFile(const QString &prefix, const QString &file)
+{
+ const QModelIndex preindex = m_qrcModel->getIndex(prefix, QString());
+ addFiles(QStringList(file), preindex);
+}
+
+/*
+void ResourceView::removeItem()
+{
+ const QModelIndex index = currentIndex();
+ m_qrcModel->deleteItem(index);
+}
+
+void ResourceView::removeFile(const QString &prefix, const QString &file)
+{
+ const QModelIndex index = m_qrcModel->getIndex(prefix, file);
+ if (index.isValid())
+ m_qrcModel->deleteItem(index);
+}
+*/
+void ResourceView::onEditPrefix()
+{
+ QModelIndex index = currentIndex();
+ changePrefix(index);
+}
+
+void ResourceView::onEditLang()
+{
+ const QModelIndex index = currentIndex();
+ changeLang(index);
+}
+
+void ResourceView::onEditAlias()
+{
+ const QModelIndex index = currentIndex();
+ changeAlias(index);
+}
+
+bool ResourceView::load(QString fileName)
+{
+ const QFileInfo fi(fileName);
+ m_qrcModel->setFileName(fi.absoluteFilePath());
+
+ if(!fi.exists())
+ return false;
+
+ const bool result = m_qrcModel->reload();
+ reset();
+ return result;
+}
+
+bool ResourceView::save(void)
+{
+ return m_qrcModel->save();
+}
+
+void ResourceView::changePrefix(const QModelIndex &index)
+{
+ bool ok = false;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+
+ QString prefixBefore;
+ QString dummy;
+ m_qrcModel->getItem(preindex, prefixBefore, dummy);
+
+ QString const prefixAfter = QInputDialog::getText(this, tr("Change Prefix"), tr("Input Prefix:"),
+ QLineEdit::Normal, prefixBefore, &ok);
+
+ if (ok) {
+ addUndoCommand(preindex, PrefixProperty, prefixBefore, prefixAfter);
+ }
+}
+
+void ResourceView::changeLang(const QModelIndex &index)
+{
+ bool ok = false;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+
+ QString const langBefore = m_qrcModel->lang(preindex);
+ QString const langAfter = QInputDialog::getText(this, tr("Change Language"), tr("Language:"),
+ QLineEdit::Normal, langBefore, &ok);
+
+ if (ok) {
+ addUndoCommand(preindex, LanguageProperty, langBefore, langAfter);
+ }
+}
+
+void ResourceView::changeAlias(const QModelIndex &index)
+{
+ if(!index.parent().isValid())
+ return;
+
+ bool ok = false;
+
+ QString const aliasBefore = m_qrcModel->alias(index);
+ QString const aliasAfter = QInputDialog::getText(this, tr("Change File Alias"), tr("Alias:"),
+ QLineEdit::Normal, aliasBefore, &ok);
+
+ if (ok) {
+ addUndoCommand(index, AliasProperty, aliasBefore, aliasAfter);
+ }
+}
+
+QString ResourceView::currentAlias() const
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return QString();
+ return m_qrcModel->alias(current);
+}
+
+QString ResourceView::currentPrefix() const
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return QString();
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+ QString prefix, file;
+ m_qrcModel->getItem(preindex, prefix, file);
+ return prefix;
+}
+
+QString ResourceView::currentLanguage() const
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return QString();
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+ return m_qrcModel->lang(preindex);
+}
+
+QString ResourceView::getCurrentValue(NodeProperty property) const
+{
+ switch (property) {
+ case AliasProperty: return currentAlias();
+ case PrefixProperty: return currentPrefix();
+ case LanguageProperty: return currentLanguage();
+ default: Q_ASSERT(false); return QString(); // Kill warning
+ }
+}
+
+void ResourceView::changeValue(const QModelIndex &nodeIndex, NodeProperty property,
+ const QString &value)
+{
+ switch (property) {
+ case AliasProperty: m_qrcModel->changeAlias(nodeIndex, value); return;
+ case PrefixProperty: m_qrcModel->changePrefix(nodeIndex, value); return;
+ case LanguageProperty: m_qrcModel->changeLang(nodeIndex, value); return;
+ default: Q_ASSERT(false);
+ }
+}
+
+void ResourceView::advanceMergeId() {
+ m_mergeId++;
+ if (m_mergeId < 0) {
+ m_mergeId = 0;
+ }
+}
+
+void ResourceView::addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property,
+ const QString &before, const QString &after) {
+ QUndoCommand * const command = new ModifyPropertyCommand(this, nodeIndex, property,
+ m_mergeId, before, after);
+ m_history->push(command);
+}
+
+void ResourceView::setCurrentAlias(const QString &before, const QString &after)
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return;
+
+ addUndoCommand(current, AliasProperty, before, after);
+}
+
+void ResourceView::setCurrentPrefix(const QString &before, const QString &after)
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+
+ addUndoCommand(preindex, PrefixProperty, before, after);
+}
+
+void ResourceView::setCurrentLanguage(const QString &before, const QString &after)
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+
+ addUndoCommand(preindex, LanguageProperty, before, after);
+}
+
+bool ResourceView::isPrefix(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return false;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+ if (preindex == index)
+ return true;
+ return false;
+}
+
+QString ResourceView::fileName() const
+{
+ return m_qrcModel->fileName();
+}
+
+void ResourceView::setFileName(const QString &fileName)
+{
+ m_qrcModel->setFileName(fileName);
+}
+
+void ResourceView::setResourceDragEnabled(bool e)
+{
+ setDragEnabled(e);
+ m_qrcModel->setResourceDragEnabled(e);
+}
+
+bool ResourceView::resourceDragEnabled() const
+{
+ return m_qrcModel->resourceDragEnabled();
+}
+
+}
diff --git a/shared/qrceditor/resourceview.h b/shared/qrceditor/resourceview.h
new file mode 100644
index 0000000000..87cd22de36
--- /dev/null
+++ b/shared/qrceditor/resourceview.h
@@ -0,0 +1,183 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RESOURCEVIEW_H
+#define RESOURCEVIEW_H
+
+#include "namespace_global.h"
+
+#include "resourcefile_p.h"
+
+#include <QtGui/QTreeView>
+#include <QtCore/QPoint>
+
+using namespace qdesigner_internal;
+
+QT_FORWARD_DECLARE_CLASS(QAction)
+QT_FORWARD_DECLARE_CLASS(QMenu)
+QT_FORWARD_DECLARE_CLASS(QMouseEvent)
+QT_FORWARD_DECLARE_CLASS(QUndoStack)
+
+namespace SharedTools {
+
+/*!
+ \class EntryBackup
+
+ Holds the backup of a tree node including children.
+*/
+class EntryBackup
+{
+protected:
+ ResourceModel *m_model;
+ int m_prefixIndex;
+ QString m_name;
+
+ EntryBackup(ResourceModel &model, int prefixIndex, const QString &name)
+ : m_model(&model), m_prefixIndex(prefixIndex), m_name(name) { }
+
+public:
+ virtual void restore() const = 0;
+ virtual ~EntryBackup() { }
+};
+
+namespace Internal {
+ class RelativeResourceModel;
+}
+
+class ResourceView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ enum NodeProperty {
+ AliasProperty,
+ PrefixProperty,
+ LanguageProperty
+ };
+
+ ResourceView(QUndoStack *history, QWidget *parent = 0);
+ ~ResourceView(void);
+
+ bool load(QString fileName);
+ bool save(void);
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ bool isDirty() const;
+ void setDirty(bool dirty);
+
+ void enableContextMenu(bool enable);
+
+ void addFiles(QStringList fileList, const QModelIndex &index);
+
+ void addFile(const QString &prefix, const QString &file);
+// void removeFile(const QString &prefix, const QString &file);
+
+ bool isPrefix(const QModelIndex &index) const;
+
+ QString currentAlias() const;
+ QString currentPrefix() const;
+ QString currentLanguage() const;
+
+ void setResourceDragEnabled(bool e);
+ bool resourceDragEnabled() const;
+
+ void setDefaultAddFileEnabled(bool enable);
+ bool defaultAddFileEnabled() const;
+
+ void findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const;
+ EntryBackup * removeEntry(const QModelIndex &index);
+ void addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
+ int &firstFile, int &lastFile);
+ void removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex);
+ QStringList fileNamesToAdd();
+ QModelIndex addPrefix();
+
+public slots:
+ void onAddFiles();
+ void setCurrentAlias(const QString &before, const QString &after);
+ void setCurrentPrefix(const QString &before, const QString &after);
+ void setCurrentLanguage(const QString &before, const QString &after);
+ void advanceMergeId();
+
+protected:
+ void setupMenu();
+ void changePrefix(const QModelIndex &index);
+ void changeLang(const QModelIndex &index);
+ void changeAlias(const QModelIndex &index);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+signals:
+ void removeItem();
+ void dirtyChanged(bool b);
+ void currentIndexChanged();
+
+ void addFilesTriggered(const QString &prefix);
+ void addPrefixTriggered();
+
+protected slots:
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+
+private slots:
+ void onEditAlias();
+ void onEditPrefix();
+ void onEditLang();
+ void popupMenu(const QModelIndex &index);
+
+public:
+ QString getCurrentValue(NodeProperty property) const;
+ void changeValue(const QModelIndex &nodeIndex, NodeProperty property, const QString &value);
+
+private:
+ void addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property, const QString &before,
+ const QString &after);
+
+ QPoint m_releasePos;
+
+ qdesigner_internal::ResourceFile m_qrcFile;
+ Internal::RelativeResourceModel *m_qrcModel;
+
+ QAction *m_addFile;
+ QAction *m_editAlias;
+ QAction *m_removeItem;
+ QAction *m_addPrefix;
+ QAction *m_editPrefix;
+ QAction *m_editLang;
+ QMenu *m_viewMenu;
+ bool m_defaultAddFile;
+ QUndoStack *m_history;
+ int m_mergeId;
+};
+
+}
+
+#endif //RESOURCEVIEW_H
diff --git a/shared/qrceditor/test/main.cpp b/shared/qrceditor/test/main.cpp
new file mode 100644
index 0000000000..d8891accd8
--- /dev/null
+++ b/shared/qrceditor/test/main.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qrceditor.h"
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc,argv);
+ MainWindow mw;
+ mw.show();
+ return app.exec();
+}
diff --git a/shared/qrceditor/test/mainwindow.cpp b/shared/qrceditor/test/mainwindow.cpp
new file mode 100644
index 0000000000..2879602d17
--- /dev/null
+++ b/shared/qrceditor/test/mainwindow.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "mainwindow.h"
+#include "qrceditor.h"
+
+#include <QMenuBar>
+#include <QAction>
+#include <QVBoxLayout>
+#include <QFileDialog>
+#include <QStatusBar>
+
+#include <qdebug.h>
+
+MainWindow::MainWindow() :
+ m_qrcEditor(new SharedTools::QrcEditor())
+{
+ m_qrcEditor->setResourceDragEnabled(true);
+ setWindowTitle(tr("Test resource editor"));
+ QMenu* fMenu = menuBar()->addMenu(tr("File"));
+
+ QAction* oa = fMenu->addAction(tr("Open..."));
+ connect(oa, SIGNAL(triggered()), this, SLOT(slotOpen()));
+
+ QAction* sa = fMenu->addAction(tr("Save"));
+ connect(sa, SIGNAL(triggered()), this, SLOT(slotSave()));
+
+ QAction* xa = fMenu->addAction(tr("Exit!"));
+ connect(xa, SIGNAL(triggered()), this, SLOT(close()));
+
+
+ QWidget *cw = new QWidget();
+ setCentralWidget(cw);
+ QVBoxLayout *lt = new QVBoxLayout(cw);
+ lt->addWidget(m_qrcEditor);
+ setMinimumSize(QSize(500, 500));
+}
+
+void MainWindow::slotOpen()
+{
+ const QString fileName = QFileDialog::getOpenFileName (this, tr("Choose resource file"),
+ QString(),
+ tr("Resource files (*.qrc)"));
+ if (fileName.isEmpty())
+ return;
+
+ if (m_qrcEditor->load(fileName))
+ statusBar()->showMessage(tr("%1 opened").arg(fileName));
+ else
+ statusBar()->showMessage(tr("Unable to open %1!").arg(fileName));
+}
+
+void MainWindow::slotSave()
+{
+ const QString oldFileName = m_qrcEditor->fileName();
+ QString fileName = oldFileName;
+
+ if (fileName.isEmpty()) {
+ fileName = QFileDialog::getSaveFileName (this, tr("Save resource file"),
+ QString(),
+ tr("Resource files (*.qrc)"));
+ if (fileName.isEmpty())
+ return;
+ }
+
+ m_qrcEditor->setFileName(fileName);
+ if (m_qrcEditor->save())
+ statusBar()->showMessage(tr("%1 written").arg(fileName));
+ else {
+ statusBar()->showMessage(tr("Unable to write %1!").arg(fileName));
+ m_qrcEditor->setFileName(oldFileName);
+ }
+}
diff --git a/shared/qrceditor/test/mainwindow.h b/shared/qrceditor/test/mainwindow.h
new file mode 100644
index 0000000000..f6570a4a12
--- /dev/null
+++ b/shared/qrceditor/test/mainwindow.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef _MAINWINDOW_
+#define _MAINWINDOW_
+
+#include <QMainWindow>
+
+namespace SharedTools {
+ class QrcEditor;
+}
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+private slots:
+ void slotOpen();
+ void slotSave();
+
+private:
+ SharedTools::QrcEditor *m_qrcEditor;
+}; // MainWindow
+
+#endif
diff --git a/shared/qrceditor/test/test.pro b/shared/qrceditor/test/test.pro
new file mode 100644
index 0000000000..aae1b39461
--- /dev/null
+++ b/shared/qrceditor/test/test.pro
@@ -0,0 +1,11 @@
+######################################################################
+# Automatically generated by qmake (1.07a) Mon Mar 19 11:10:13 2007
+######################################################################
+
+TEMPLATE = app
+
+QT += gui
+
+include(../qrceditor.pri)
+SOURCES += main.cpp mainwindow.cpp
+HEADERS += mainwindow.h
diff --git a/shared/qrceditor/undocommands.cpp b/shared/qrceditor/undocommands.cpp
new file mode 100644
index 0000000000..90007d8c1b
--- /dev/null
+++ b/shared/qrceditor/undocommands.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2008-$THISYEAR$ $TROLLTECH$. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "undocommands_p.h"
+
+#include <QtCore/QModelIndex>
+
+namespace SharedTools {
+
+ViewCommand::ViewCommand(ResourceView *view)
+ : m_view(view)
+{ }
+
+ViewCommand::~ViewCommand()
+{ }
+
+ModelIndexViewCommand::ModelIndexViewCommand(ResourceView *view)
+ : ViewCommand(view)
+{ }
+
+ModelIndexViewCommand::~ModelIndexViewCommand()
+{ }
+
+void ModelIndexViewCommand::storeIndex(const QModelIndex &index)
+{
+ if (m_view->isPrefix(index)) {
+ m_prefixArrayIndex = index.row();
+ m_fileArrayIndex = -1;
+ } else {
+ m_fileArrayIndex = index.row();
+ m_prefixArrayIndex = m_view->model()->parent(index).row();
+ }
+}
+
+QModelIndex ModelIndexViewCommand::makeIndex() const
+{
+ const QModelIndex prefixModelIndex
+ = m_view->model()->index(m_prefixArrayIndex, 0, QModelIndex());
+ if (m_fileArrayIndex != -1) {
+ // File node
+ const QModelIndex fileModelIndex
+ = m_view->model()->index(m_fileArrayIndex, 0, prefixModelIndex);
+ return fileModelIndex;
+ } else {
+ // Prefix node
+ return prefixModelIndex;
+ }
+}
+
+
+
+ModifyPropertyCommand::ModifyPropertyCommand(ResourceView *view, const QModelIndex &nodeIndex,
+ ResourceView::NodeProperty property, const int mergeId, const QString &before,
+ const QString &after)
+ : ModelIndexViewCommand(view), m_property(property), m_before(before), m_after(after),
+ m_mergeId(mergeId)
+{
+ storeIndex(nodeIndex);
+}
+
+bool ModifyPropertyCommand::mergeWith(const QUndoCommand * command)
+{
+ const ModifyPropertyCommand * const brother
+ = dynamic_cast<const ModifyPropertyCommand *>(command);
+ if ((command == NULL) || (m_property != brother->m_property))
+ return false;
+
+ // Choose older command (this) and forgot the other
+ return true;
+}
+
+void ModifyPropertyCommand::undo()
+{
+ Q_ASSERT(m_view != NULL);
+
+ // Save current text in m_after for redo()
+ m_after = m_view->getCurrentValue(m_property);
+
+ // Reset text to m_before
+ m_view->changeValue(makeIndex(), m_property, m_before);
+}
+
+void ModifyPropertyCommand::redo()
+{
+ // Prevent execution from within QUndoStack::push
+ if (m_after.isNull()) {
+ return;
+ }
+
+ // Bring back text before undo
+ Q_ASSERT(m_view != NULL);
+ m_view->changeValue(makeIndex(), m_property, m_after);
+}
+
+RemoveEntryCommand::RemoveEntryCommand(ResourceView *view, const QModelIndex &index)
+ : ModelIndexViewCommand(view), m_entry(NULL), m_isExpanded(true)
+{
+ storeIndex(index);
+}
+
+RemoveEntryCommand::~RemoveEntryCommand()
+{
+ freeEntry();
+}
+
+void RemoveEntryCommand::redo()
+{
+ freeEntry();
+ const QModelIndex index = makeIndex();
+ m_isExpanded = m_view->isExpanded(index);
+ m_entry = m_view->removeEntry(index);
+}
+
+void RemoveEntryCommand::undo()
+{
+ if (m_entry != NULL) {
+ m_entry->restore();
+ Q_ASSERT(m_view != NULL);
+ const QModelIndex index = makeIndex();
+ m_view->setExpanded(index, m_isExpanded);
+ m_view->setCurrentIndex(index);
+ freeEntry();
+ }
+}
+
+void RemoveEntryCommand::freeEntry()
+{
+ delete m_entry;
+ m_entry = NULL;
+}
+
+AddFilesCommand::AddFilesCommand(ResourceView *view, int prefixIndex, int cursorFileIndex,
+ const QStringList &fileNames)
+ : ViewCommand(view), m_prefixIndex(prefixIndex), m_cursorFileIndex(cursorFileIndex),
+ m_fileNames(fileNames)
+{ }
+
+void AddFilesCommand::redo()
+{
+ m_view->addFiles(m_prefixIndex, m_fileNames, m_cursorFileIndex, m_firstFile, m_lastFile);
+}
+
+void AddFilesCommand::undo()
+{
+ m_view->removeFiles(m_prefixIndex, m_firstFile, m_lastFile);
+}
+
+AddEmptyPrefixCommand::AddEmptyPrefixCommand(ResourceView *view)
+ : ViewCommand(view)
+{ }
+
+void AddEmptyPrefixCommand::redo()
+{
+ m_prefixArrayIndex = m_view->addPrefix().row();
+}
+
+void AddEmptyPrefixCommand::undo()
+{
+ const QModelIndex prefixModelIndex = m_view->model()->index(
+ m_prefixArrayIndex, 0, QModelIndex());
+ delete m_view->removeEntry(prefixModelIndex);
+}
+
+} // namespace SharedTools
diff --git a/shared/qrceditor/undocommands_p.h b/shared/qrceditor/undocommands_p.h
new file mode 100644
index 0000000000..8247f93547
--- /dev/null
+++ b/shared/qrceditor/undocommands_p.h
@@ -0,0 +1,162 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef UNDO_COMMANDS_H
+#define UNDO_COMMANDS_H
+
+#include "resourceview.h"
+
+#include <QtCore/QString>
+#include <QtGui/QUndoCommand>
+
+QT_FORWARD_DECLARE_CLASS(QModelIndex);
+
+namespace SharedTools {
+
+/*!
+ \class ViewCommand
+
+ Provides a base for \l ResourceView-related commands.
+*/
+class ViewCommand : public QUndoCommand
+{
+protected:
+ ResourceView *m_view;
+
+ ViewCommand(ResourceView *view);
+ virtual ~ViewCommand();
+};
+
+/*!
+ \class ModelIndexViewCommand
+
+ Provides a mean to store/restore a \l QModelIndex as it cannot
+ be stored savely in most cases. This is an abstract class.
+*/
+class ModelIndexViewCommand : public ViewCommand
+{
+ int m_prefixArrayIndex;
+ int m_fileArrayIndex;
+
+protected:
+ ModelIndexViewCommand(ResourceView *view);
+ virtual ~ModelIndexViewCommand();
+ void storeIndex(const QModelIndex &index);
+ QModelIndex makeIndex() const;
+};
+
+/*!
+ \class ModifyPropertyCommand
+
+ Modifies the name/prefix/language property of a prefix/file node.
+*/
+class ModifyPropertyCommand : public ModelIndexViewCommand
+{
+ ResourceView::NodeProperty m_property;
+ QString m_before;
+ QString m_after;
+ int m_mergeId;
+
+public:
+ ModifyPropertyCommand(ResourceView *view, const QModelIndex &nodeIndex,
+ ResourceView::NodeProperty property, const int mergeId, const QString &before,
+ const QString &after = QString());
+
+private:
+ int id() const { return m_mergeId; }
+ bool mergeWith(const QUndoCommand * command);
+ void undo();
+ void redo();
+};
+
+/*!
+ \class RemoveEntryCommand
+
+ Removes a \l QModelIndex including all children from a \l ResourceView.
+*/
+class RemoveEntryCommand : public ModelIndexViewCommand
+{
+ EntryBackup *m_entry;
+ bool m_isExpanded;
+
+public:
+ RemoveEntryCommand(ResourceView *view, const QModelIndex &index);
+ ~RemoveEntryCommand();
+
+private:
+ void redo();
+ void undo();
+ void freeEntry();
+};
+
+/*!
+ \class AddFilesCommand
+
+ Adds a list of files to a given prefix node.
+*/
+class AddFilesCommand : public ViewCommand
+{
+ int m_prefixIndex;
+ int m_cursorFileIndex;
+ int m_firstFile;
+ int m_lastFile;
+ const QStringList m_fileNames;
+
+public:
+ AddFilesCommand(ResourceView *view, int prefixIndex, int cursorFileIndex,
+ const QStringList &fileNames);
+
+private:
+ void redo();
+ void undo();
+};
+
+/*!
+ \class AddEmptyPrefixCommand
+
+ Adds a new, empty prefix node.
+*/
+class AddEmptyPrefixCommand : public ViewCommand
+{
+ int m_prefixArrayIndex;
+
+public:
+ AddEmptyPrefixCommand(ResourceView *view);
+
+private:
+ void redo();
+ void undo();
+};
+
+} // namespace SharedTools
+
+#endif // UNDO_COMMANDS_H
diff --git a/shared/qscripthighlighter/README b/shared/qscripthighlighter/README
new file mode 100644
index 0000000000..220e01228e
--- /dev/null
+++ b/shared/qscripthighlighter/README
@@ -0,0 +1,3 @@
+Syntax highlighter for Qt script courtesy of Simon.
+
+Exists as a duplicate in Designer.
diff --git a/shared/qscripthighlighter/qscripthighlighter.cpp b/shared/qscripthighlighter/qscripthighlighter.cpp
new file mode 100644
index 0000000000..6d9449e36c
--- /dev/null
+++ b/shared/qscripthighlighter/qscripthighlighter.cpp
@@ -0,0 +1,480 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qscripthighlighter.h"
+
+#include <QtCore/QSet>
+#include <QtCore/QtAlgorithms>
+
+static const QSet<QString> &qscriptKeywords() {
+ static QSet<QString> keywords;
+ if (keywords.empty()) {
+ keywords.insert(QLatin1String("Infinity"));
+ keywords.insert(QLatin1String("NaN"));
+ keywords.insert(QLatin1String("abstract"));
+ keywords.insert(QLatin1String("boolean"));
+ keywords.insert(QLatin1String("break"));
+ keywords.insert(QLatin1String("byte"));
+ keywords.insert(QLatin1String("case"));
+ keywords.insert(QLatin1String("catch"));
+ keywords.insert(QLatin1String("char"));
+ keywords.insert(QLatin1String("class"));
+ keywords.insert(QLatin1String("const"));
+ keywords.insert(QLatin1String("constructor"));
+ keywords.insert(QLatin1String("continue"));
+ keywords.insert(QLatin1String("debugger"));
+ keywords.insert(QLatin1String("default"));
+ keywords.insert(QLatin1String("delete"));
+ keywords.insert(QLatin1String("do"));
+ keywords.insert(QLatin1String("double"));
+ keywords.insert(QLatin1String("else"));
+ keywords.insert(QLatin1String("enum"));
+ keywords.insert(QLatin1String("export"));
+ keywords.insert(QLatin1String("extends"));
+ keywords.insert(QLatin1String("false"));
+ keywords.insert(QLatin1String("final"));
+ keywords.insert(QLatin1String("finally"));
+ keywords.insert(QLatin1String("float"));
+ keywords.insert(QLatin1String("for"));
+ keywords.insert(QLatin1String("function"));
+ keywords.insert(QLatin1String("goto"));
+ keywords.insert(QLatin1String("if"));
+ keywords.insert(QLatin1String("implements"));
+ keywords.insert(QLatin1String("import"));
+ keywords.insert(QLatin1String("in"));
+ keywords.insert(QLatin1String("instanceof"));
+ keywords.insert(QLatin1String("int"));
+ keywords.insert(QLatin1String("interface"));
+ keywords.insert(QLatin1String("long"));
+ keywords.insert(QLatin1String("native"));
+ keywords.insert(QLatin1String("new"));
+ keywords.insert(QLatin1String("package"));
+ keywords.insert(QLatin1String("private"));
+ keywords.insert(QLatin1String("protected"));
+ keywords.insert(QLatin1String("public"));
+ keywords.insert(QLatin1String("return"));
+ keywords.insert(QLatin1String("short"));
+ keywords.insert(QLatin1String("static"));
+ keywords.insert(QLatin1String("super"));
+ keywords.insert(QLatin1String("switch"));
+ keywords.insert(QLatin1String("synchronized"));
+ keywords.insert(QLatin1String("this"));
+ keywords.insert(QLatin1String("throw"));
+ keywords.insert(QLatin1String("throws"));
+ keywords.insert(QLatin1String("transient"));
+ keywords.insert(QLatin1String("true"));
+ keywords.insert(QLatin1String("try"));
+ keywords.insert(QLatin1String("typeof"));
+ keywords.insert(QLatin1String("undefined"));
+ keywords.insert(QLatin1String("var"));
+ keywords.insert(QLatin1String("void"));
+ keywords.insert(QLatin1String("volatile"));
+ keywords.insert(QLatin1String("while"));
+ keywords.insert(QLatin1String("with")); // end
+ }
+ return keywords;
+}
+
+
+ namespace SharedTools {
+
+QScriptHighlighter::QScriptHighlighter(QTextDocument *parent)
+ : QSyntaxHighlighter(parent)
+{
+ setFormats(defaultFormats());
+}
+
+void QScriptHighlighter::highlightBlock(const QString &text)
+{
+ // states
+ enum {
+ StateStandard,
+ StateCommentStart1,
+ StateCCommentStart2,
+ StateCppCommentStart2,
+ StateCComment,
+ StateCppComment,
+ StateCCommentEnd1,
+ StateCCommentEnd2,
+ StateStringStart,
+ StateString,
+ StateStringEnd,
+ StateString2Start,
+ StateString2,
+ StateString2End,
+ StateNumber,
+ StatePreProcessor,
+ NumStates
+ };
+ // tokens
+ enum {
+ InputAlpha,
+ InputNumber,
+ InputAsterix,
+ InputSlash,
+ InputParen,
+ InputSpace,
+ InputHash,
+ InputQuotation,
+ InputApostrophe,
+ InputSep,
+ NumInputs
+ };
+
+ static const uchar table[NumStates][NumInputs] = {
+ { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard
+ { StateStandard, StateNumber, StateCCommentStart2, StateCppCommentStart2, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2
+ { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // CppCommentStart2
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment
+ { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppComment
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1
+ { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
+ { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart
+ { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString
+ { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
+ { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start
+ { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2
+ { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End
+ { StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber
+ { StatePreProcessor, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor
+ };
+
+ QString buffer;
+ buffer.reserve(text.length());
+ QTextCharFormat emptyFormat;
+
+ int state = onBlockStart();
+ if (text.isEmpty()) {
+ onBlockEnd(state, 0);
+ return;
+ }
+
+ int input = -1;
+ int i = 0;
+ bool lastWasBackSlash = false;
+ bool makeLastStandard = false;
+
+ static const QString alphabeth = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ static const QString mathChars = QString::fromLatin1("xXeE");
+ static const QString numbers = QString::fromLatin1("0123456789");
+ bool questionMark = false;
+ QChar lastChar;
+
+ int firstNonSpace = -1;
+ int lastNonSpace = -1;
+
+ forever {
+ const QChar c = text.at(i);
+
+ if (lastWasBackSlash) {
+ input = InputSep;
+ } else {
+ switch (c.toLatin1()) {
+ case '*':
+ input = InputAsterix;
+ break;
+ case '/':
+ input = InputSlash;
+ break;
+ case '(': case '[': case '{':
+ input = InputParen;
+ if (state == StateStandard
+ || state == StateNumber
+ || state == StatePreProcessor
+ || state == StateCCommentEnd2
+ || state == StateCCommentEnd1
+ || state == StateString2End
+ || state == StateStringEnd
+ )
+ onOpeningParenthesis(c, i);
+ break;
+ case ')': case ']': case '}':
+ input = InputParen;
+ if (state == StateStandard
+ || state == StateNumber
+ || state == StatePreProcessor
+ || state == StateCCommentEnd2
+ || state == StateCCommentEnd1
+ || state == StateString2End
+ || state == StateStringEnd
+ ) {
+ onClosingParenthesis(c, i);
+ }
+ break;
+ case '#':
+ input = InputHash;
+ break;
+ case '"':
+ input = InputQuotation;
+ break;
+ case '\'':
+ input = InputApostrophe;
+ break;
+ case ' ':
+ input = InputSpace;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '0':
+ if (alphabeth.contains(lastChar)
+ && (!mathChars.contains(lastChar) || !numbers.contains(text.at(i - 1)))) {
+ input = InputAlpha;
+ } else {
+ if (input == InputAlpha && numbers.contains(lastChar))
+ input = InputAlpha;
+ else
+ input = InputNumber;
+ }
+ break;
+ case ':': {
+ input = InputAlpha;
+ QChar nextChar = ' ';
+ if (i < text.length() - 1)
+ nextChar = text.at(i + 1);
+ if (state == StateStandard && !questionMark &&
+ lastChar != ':' && nextChar != ':') {
+ for (int j = 0; j < i; ++j) {
+ if (format(j) == emptyFormat)
+ setFormat(j, 1, m_formats[LabelFormat]);
+ }
+ }
+ break;
+ }
+ default: {
+ if (!questionMark && c == QLatin1Char('?'))
+ questionMark = true;
+ if (c.isLetter() || c == QLatin1Char('_'))
+ input = InputAlpha;
+ else
+ input = InputSep;
+ } break;
+ }
+ }
+
+ if (input != InputSpace) {
+ if (firstNonSpace < 0)
+ firstNonSpace = i;
+ lastNonSpace = i;
+ }
+
+ lastWasBackSlash = !lastWasBackSlash && c == QLatin1Char('\\');
+
+ if (input == InputAlpha)
+ buffer += c;
+
+ state = table[state][input];
+
+ switch (state) {
+ case StateStandard: {
+ setFormat(i, 1, emptyFormat);
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ if (!buffer.isEmpty() && input != InputAlpha ) {
+ highlightKeyword(i, buffer);
+ buffer.clear();
+ }
+ } break;
+ case StateCommentStart1:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = true;
+ buffer.resize(0);
+ break;
+ case StateCCommentStart2:
+ setFormat(i - 1, 2, m_formats[CommentFormat]);
+ makeLastStandard = false;
+ buffer.resize(0);
+ break;
+ case StateCppCommentStart2:
+ setFormat(i - 1, 2, m_formats[CommentFormat]);
+ makeLastStandard = false;
+ buffer.resize(0);
+ break;
+ case StateCComment:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateCppComment:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateCCommentEnd1:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateCCommentEnd2:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateStringStart:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[StringFormat]);
+ buffer.resize(0);
+ break;
+ case StateStringEnd:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString2Start:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString2:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[StringFormat]);
+ buffer.resize(0);
+ break;
+ case StateString2End:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateNumber:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat( i, 1, m_formats[NumberFormat]);
+ buffer.resize(0);
+ break;
+ case StatePreProcessor:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[PreProcessorFormat]);
+ buffer.resize(0);
+ break;
+ }
+
+ lastChar = c;
+ i++;
+ if (i >= text.length())
+ break;
+ }
+
+ highlightKeyword(text.length(), buffer);
+
+ if (state == StateCComment
+ || state == StateCCommentEnd1
+ || state == StateCCommentStart2
+ ) {
+ state = StateCComment;
+ } else if (state == StateString) {
+ state = StateString;
+ } else if (state == StateString2) {
+ state = StateString2;
+ } else {
+ state = StateStandard;
+ }
+
+ onBlockEnd(state, firstNonSpace);
+}
+
+void QScriptHighlighter::highlightKeyword(int currentPos, const QString &buffer)
+{
+ if (buffer.isEmpty())
+ return;
+
+ if (buffer.at(0) == QLatin1Char('Q')) {
+ setFormat(currentPos - buffer.length(), buffer.length(), m_formats[TypeFormat]);
+ } else {
+ if (qscriptKeywords().contains(buffer)) {
+ setFormat(currentPos - buffer.length(), buffer.length(), m_formats[KeywordFormat]);
+ }
+ }
+}
+
+const QVector<QTextCharFormat> &QScriptHighlighter::defaultFormats()
+{
+ static QVector<QTextCharFormat> rc;
+ if (rc.empty()) {
+ rc.resize(NumFormats);
+ rc[NumberFormat].setForeground(Qt::blue);
+ rc[StringFormat].setForeground(Qt::darkGreen);
+ rc[TypeFormat].setForeground(Qt::darkMagenta);
+ rc[KeywordFormat].setForeground(Qt::darkYellow);
+ rc[LabelFormat].setForeground(Qt::darkRed);
+ rc[CommentFormat].setForeground(Qt::red);
+ rc[CommentFormat].setFontItalic(true);
+ rc[PreProcessorFormat].setForeground(Qt::darkBlue);
+ }
+ return rc;
+}
+
+void QScriptHighlighter::setFormats(const QVector<QTextCharFormat> &s)
+{
+ qCopy(s.constBegin(), s.constEnd(), m_formats);
+}
+
+int QScriptHighlighter::onBlockStart() {
+ int state = 0;
+ int previousState = previousBlockState();
+ if (previousState != -1)
+ state = previousState;
+ return state;
+}
+void QScriptHighlighter::onOpeningParenthesis(QChar, int) {}
+void QScriptHighlighter::onClosingParenthesis(QChar, int) {}
+void QScriptHighlighter::onBlockEnd(int state, int) { return setCurrentBlockState(state); }
+}
+
diff --git a/shared/qscripthighlighter/qscripthighlighter.h b/shared/qscripthighlighter/qscripthighlighter.h
new file mode 100644
index 0000000000..186cb59f5f
--- /dev/null
+++ b/shared/qscripthighlighter/qscripthighlighter.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QSCRIPTSYNTAXHIGHLIGHTER_H
+#define QSCRIPTSYNTAXHIGHLIGHTER_H
+
+#include <QVector>
+#include <QtGui/QSyntaxHighlighter>
+
+namespace SharedTools {
+
+class QScriptHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ QScriptHighlighter(QTextDocument *parent = 0);
+ virtual void highlightBlock(const QString &text);
+
+ enum { NumberFormat, StringFormat, TypeFormat,
+ KeywordFormat, PreProcessorFormat, LabelFormat, CommentFormat,
+ NumFormats };
+
+ // MS VC 6 compatible, still.
+ void setFormats(const QVector<QTextCharFormat> &s);
+ static const QVector<QTextCharFormat> &defaultFormats();
+
+private:
+ // The functions are notified whenever parentheses are encountered.
+ // Custom behaviour can be added, for example storing info for indenting.
+ virtual int onBlockStart(); // returns the blocks initial state
+ virtual void onOpeningParenthesis(QChar parenthesis, int pos);
+ virtual void onClosingParenthesis(QChar parenthesis, int pos);
+ virtual void onBlockEnd(int state, int firstNonSpace); // sets the enriched user state, or simply calls setCurrentBlockState(state);
+
+ void highlightKeyword(int currentPos, const QString &buffer);
+
+ QTextCharFormat m_formats[NumFormats];
+};
+
+} // namespace SharedTools
+
+#endif // QSCRIPTSYNTAXHIGHLIGHTER_H
diff --git a/shared/qscripthighlighter/qscripthighlighter.pri b/shared/qscripthighlighter/qscripthighlighter.pri
new file mode 100644
index 0000000000..577bed10a6
--- /dev/null
+++ b/shared/qscripthighlighter/qscripthighlighter.pri
@@ -0,0 +1,4 @@
+INCLUDEPATH *= $$PWD
+
+SOURCES += $$PWD/qscripthighlighter.cpp
+HEADERS += $$PWD/qscripthighlighter.h
diff --git a/shared/qscripthighlighter/test/main.cpp b/shared/qscripthighlighter/test/main.cpp
new file mode 100644
index 0000000000..80095802da
--- /dev/null
+++ b/shared/qscripthighlighter/test/main.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qscripthighlighter.h"
+#include <QTextEdit>
+#include <QMainWindow>
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QMainWindow mw;
+
+ QTextEdit *textEdit = new QTextEdit;
+ new SharedTools::QScriptHighlighter(textEdit->document());
+ mw.setCentralWidget(textEdit);
+ mw.show();
+ return app.exec();
+}
diff --git a/shared/qscripthighlighter/test/test.pro b/shared/qscripthighlighter/test/test.pro
new file mode 100644
index 0000000000..4962411032
--- /dev/null
+++ b/shared/qscripthighlighter/test/test.pro
@@ -0,0 +1,10 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Mon Apr 16 13:02:01 2007
+######################################################################
+
+TEMPLATE = app
+
+QT += gui
+
+include(../qscripthighlighter.pri)
+SOURCES += main.cpp
diff --git a/shared/qtextended_integration.h b/shared/qtextended_integration.h
new file mode 100644
index 0000000000..d76ea28bab
--- /dev/null
+++ b/shared/qtextended_integration.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTEXTENDED_INTEGRATION
+#define QTEXTENDED_INTEGRATION
+
+// Enable support for QBuild style project parsing
+//#define QTEXTENDED_QBUILD_SUPPORT
+
+/*
+This file is intended to be the 'communication channel' for Qt-Extended (aka Qtopia) integration issues.
+
+*** The first step in the integration is to add support for QBuild to the IDE ***
+
+QBuild is the build system used in Qt-Extended 4.4 and onwards. QBuild is a replacement for qmake+make.
+The reasons for the replacement go a bit beyond this page, but in short:
+- there's only one qbuild instance running v.s. MANY qmake instances.
+- implements proper management of dependencies between files. Regardless of where you are in the source tree ... a 'make' will always result in all dependencies (that have changed) being rebuild in the correct sequence. This is something that was a major issue with Qt-Extended development in the past.
+- solves many Qt-Extended build/deployment issues
+- separates build logic (specific for Qt-Extended) from the script runner logic
+- fully supports TeamBuilder and can trottle build, moc, and IO tasks differently.
+- is fast!!!!
+
+QBuild is a bootstrapping solution, i.e. the only thing you need to do to build Qt-Extended is:
+ configure <options>
+ make
+ make image
+
+Configure will build QBuild, and QBuild will produce very small Makefile's that basically re-direct all make calls back to QBuild. The configuration options are saved in a cache file that is read by QBuild upon any invocation.
+
+Within QBuild, all pro files are named qbuild.pro and there's no need to create template pro files for "SUBDIRS". QBuild will always traverse through the complete source tree and will discover all 'real' projects.
+QBuild .pro files are also different from QMake .pro files in that the first can contain scripting language that define the project specific logic.
+
+So far one class has been modified:
+- qt4project.cpp/h -> basically the mechanism to discover project files needs to be adapted to QBuild.
+There's a bit of nastiness in the code that I'd like to see fixed, esp the ugly global boolean, but I'm not familar enough with the code to do that properly.
+
+How to use?
+- You should get yourself a copy of //depot/qtopia/main (from the Brisbane p4.trolltech.com.au:866 server)
+- The actual contents of Qtopia are irrelevant at this stage, i.e. you don't need to sync every day. We only use it as a sample of a large project containing qbuild stuff.
+- hack the ~/depot/qtopia/main/qbuild.pro file and set "SUBDIRS=examples etc/themes" (we don't want too much stuff at this stage), i.e. make sure you're not scanning 'src' as well.
+- build and run Qt Creator and make sure you have your Qt Creator IDE as the FIRST open project (or whatever you use for testing)
+- then do a project "Open Project/Session" on ~/depot/qtopia/main/qbuild.pro
+
+What you should get is the usual IDE project tree and then a second one below with the Qtopia stuff.
+The Qtopia tree however doesn't show much projects: just the base and then examples.pro and themes.pro (and this depends on these old files still lying around in the depot).
+
+To activate Qbuild support:
+- Compile Qt Creator with QTEXTENDED_QBUILD_SUPPORT defined (see top of this file)
+- rebuild and run Qt Creator
+
+What you should get is the usual IDE project tree and then a second one below with the Qtopia stuff but this time with approx 15 qbuild.pro projects.
+Issues:
+* Every project file is still named 'qbuild.pro', I hacked ProFile::ProFile() to set m_displayFileName to the base dir name when it's a qbuild.pro file (i.e. src/applications/addressbook/qbuild.pro should become 'addressbook' instead of'qbuild.pro'), but that doesn't seem to work. Also ProFile is a copy from Qt? so I can't really modify it.
+* The tree is (obviously) not showing much depth. This is because there are no .pro files in directories such as src/examples. So what we would need is a way to create virtual projects or something similar.
+Any suggestions how to fix this?
+
+*** Future steps ***
+- running configure, make, make image
+- defining configuration options (i.e. supporting multiple shadow builds)
+- running QtExtended on qvfb
+- debugging QtExtended on qvfb
+- running QtExtended on a device
+- debugging QtExtended on a device
+- and probably more
+
+*/
+
+#endif
diff --git a/shared/qtlockedfile/README.txt b/shared/qtlockedfile/README.txt
new file mode 100644
index 0000000000..6fcf2fd295
--- /dev/null
+++ b/shared/qtlockedfile/README.txt
@@ -0,0 +1,10 @@
+This is the src directory of the QtLockedFile
+solution integrated over from addons/main/utils/qtlockedfile/src .
+
+namespace.patch was applied to introduce the SharedTools namespace.
+
+It is required by the QtSingleApplication solution.
+
+History:
+
+16.05.2008 Integrated
diff --git a/shared/qtlockedfile/namespace.patch b/shared/qtlockedfile/namespace.patch
new file mode 100644
index 0000000000..eb894a3700
--- /dev/null
+++ b/shared/qtlockedfile/namespace.patch
@@ -0,0 +1,70 @@
+
+--- qtlockedfile.cpp 1970-01-01 01:00:00.000000000
++++ qtlockedfile.cpp 2008/05/16 10:51:19.000000000
+@@ -1,5 +1,7 @@
+ #include "qtlockedfile.h"
+
++namespace SharedTools {
++
+ /*!
+ \class QtLockedFile
+
+@@ -123,3 +125,5 @@
+
+ Destroys the \e QtLockedFile object. If any locks were held, they are released.
+ */
++
++}
+
+--- qtlockedfile.h 1970-01-01 01:00:00.000000000
++++ qtlockedfile.h 2008/05/16 10:51:19.000000000
+@@ -19,6 +19,8 @@
+ # define QT_QTLOCKEDFILE_EXPORT
+ #endif
+
++namespace SharedTools {
++
+ class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
+ {
+ public:
+@@ -41,4 +43,6 @@
+ LockMode m_lock_mode;
+ };
+
++}
++
+ #endif
+
+--- qtlockedfile_unix.cpp 1970-01-01 01:00:00.000000000
++++ qtlockedfile_unix.cpp 2008/05/16 10:51:19.000000000
+@@ -5,6 +5,8 @@
+
+ #include "qtlockedfile.h"
+
++namespace SharedTools {
++
+ bool QtLockedFile::lock(LockMode mode, bool block)
+ {
+ if (!isOpen()) {
+@@ -73,3 +75,4 @@
+ unlock();
+ }
+
++}
+
+--- qtlockedfile_win.cpp 1970-01-01 01:00:00.000000000
++++ qtlockedfile_win.cpp 2008/05/16 10:51:19.000000000
+@@ -2,6 +2,8 @@
+ #include <qt_windows.h>
+ #include <QtCore/QFileInfo>
+
++namespace SharedTools {
++
+ #define SEMAPHORE_PREFIX "QtLockedFile semaphore "
+ #define MUTEX_PREFIX "QtLockedFile mutex "
+ #define SEMAPHORE_MAX 100
+@@ -168,3 +170,4 @@
+ }
+ }
+
++}
diff --git a/shared/qtlockedfile/qtlockedfile.cpp b/shared/qtlockedfile/qtlockedfile.cpp
new file mode 100644
index 0000000000..e4fe1c388d
--- /dev/null
+++ b/shared/qtlockedfile/qtlockedfile.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtlockedfile.h"
+
+namespace SharedTools {
+
+/*!
+ \class QtLockedFile
+
+ \brief The QtLockedFile class extends QFile with advisory locking functions.
+
+ A file may be locked in read or write mode. Multiple instances of
+ \e QtLockedFile, created in multiple processes running on the same
+ machine, may have a file locked in read mode. Exactly one instance
+ may have it locked in write mode. A read and a write lock cannot
+ exist simultaneously on the same file.
+
+ The file locks are advisory. This means that nothing prevents
+ another process from manipulating a locked file using QFile or
+ file system functions offered by the OS. Serialization is only
+ guaranteed if all processes that access the file use
+ QtLockedFile. Also, while holding a lock on a file, a process
+ must not open the same file again (through any API), or locks
+ can be unexpectedly lost.
+
+ The lock provided by an instance of \e QtLockedFile is released
+ whenever the program terminates. This is true even when the
+ program crashes and no destructors are called.
+*/
+
+/*! \enum QtLockedFile::LockMode
+
+ This enum describes the available lock modes.
+
+ \value ReadLock A read lock.
+ \value WriteLock A write lock.
+ \value NoLock Neither a read lock nor a write lock.
+*/
+
+/*!
+ Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way
+ as \e QFile::QFile().
+
+ \sa QFile::QFile()
+*/
+QtLockedFile::QtLockedFile()
+ : QFile()
+{
+#ifdef Q_OS_WIN
+ m_semaphore_hnd = 0;
+ m_mutex_hnd = 0;
+#endif
+ m_lock_mode = NoLock;
+}
+
+/*!
+ Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in
+ the same way as \e QFile::QFile(const QString&).
+
+ \sa QFile::QFile()
+*/
+QtLockedFile::QtLockedFile(const QString &name)
+ : QFile(name)
+{
+#ifdef Q_OS_WIN
+ m_semaphore_hnd = 0;
+ m_mutex_hnd = 0;
+#endif
+ m_lock_mode = NoLock;
+}
+
+/*!
+ Returns \e true if this object has a in read or write lock;
+ otherwise returns \e false.
+
+ \sa lockMode()
+*/
+bool QtLockedFile::isLocked() const
+{
+ return m_lock_mode != NoLock;
+}
+
+/*!
+ Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock.
+
+ \sa isLocked()
+*/
+QtLockedFile::LockMode QtLockedFile::lockMode() const
+{
+ return m_lock_mode;
+}
+
+/*!
+ \fn bool QtLockedFile::lock(LockMode mode, bool block = true)
+
+ Obtains a lock of type \a mode.
+
+ If \a block is true, this
+ function will block until the lock is aquired. If \a block is
+ false, this function returns \e false immediately if the lock cannot
+ be aquired.
+
+ If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock
+ is first released and then a new lock is obtained.
+
+ This function returns \e true if, after it executes, the file is locked by this object,
+ and \e false otherwise.
+
+ \sa unlock(), isLocked(), lockMode()
+*/
+
+/*!
+ \fn bool QtLockedFile::unlock()
+
+ Releases a lock.
+
+ If the object has no lock, this function returns immediately.
+
+ This function returns \e true if, after it executes, the file is not locked by
+ this object, and \e false otherwise.
+
+ \sa lock(), isLocked(), lockMode()
+*/
+
+/*!
+ \fn QtLockedFile::~QtLockedFile()
+
+ Destroys the \e QtLockedFile object. If any locks were held, they are released.
+*/
+
+}
diff --git a/shared/qtlockedfile/qtlockedfile.h b/shared/qtlockedfile/qtlockedfile.h
new file mode 100644
index 0000000000..b8357d491b
--- /dev/null
+++ b/shared/qtlockedfile/qtlockedfile.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTLOCKEDFILE_H
+#define QTLOCKEDFILE_H
+
+#include <QtCore/QFile>
+
+#if defined(Q_WS_WIN)
+# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
+# define QT_QTLOCKEDFILE_EXPORT
+# elif defined(QT_QTLOCKEDFILE_IMPORT)
+# if defined(QT_QTLOCKEDFILE_EXPORT)
+# undef QT_QTLOCKEDFILE_EXPORT
+# endif
+# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
+# elif defined(QT_QTLOCKEDFILE_EXPORT)
+# undef QT_QTLOCKEDFILE_EXPORT
+# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
+# endif
+#else
+# define QT_QTLOCKEDFILE_EXPORT
+#endif
+
+namespace SharedTools {
+
+class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
+{
+public:
+ enum LockMode { NoLock = 0, ReadLock, WriteLock };
+
+ QtLockedFile();
+ QtLockedFile(const QString &name);
+ ~QtLockedFile();
+
+ bool lock(LockMode mode, bool block = true);
+ bool unlock();
+ bool isLocked() const;
+ LockMode lockMode() const;
+
+private:
+#ifdef Q_OS_WIN
+ Qt::HANDLE m_semaphore_hnd;
+ Qt::HANDLE m_mutex_hnd;
+#endif
+ LockMode m_lock_mode;
+};
+
+}
+
+#endif
diff --git a/shared/qtlockedfile/qtlockedfile.pri b/shared/qtlockedfile/qtlockedfile.pri
new file mode 100644
index 0000000000..46d1f1a12a
--- /dev/null
+++ b/shared/qtlockedfile/qtlockedfile.pri
@@ -0,0 +1,13 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += $$PWD/qtlockedfile.h
+SOURCES += $$PWD/qtlockedfile.cpp
+
+unix:SOURCES += $$PWD/qtlockedfile_unix.cpp
+win32:SOURCES += $$PWD/qtlockedfile_win.cpp
+
+win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+ DEFINES += QT_QTLOCKEDFILE_EXPORT=__declspec(dllexport)
+}
+
+
diff --git a/shared/qtlockedfile/qtlockedfile_unix.cpp b/shared/qtlockedfile/qtlockedfile_unix.cpp
new file mode 100644
index 0000000000..0a9ba5ab47
--- /dev/null
+++ b/shared/qtlockedfile/qtlockedfile_unix.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "qtlockedfile.h"
+
+namespace SharedTools {
+
+bool QtLockedFile::lock(LockMode mode, bool block)
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::lock(): file is not opened");
+ return false;
+ }
+
+ if (mode == NoLock)
+ return unlock();
+
+ if (mode == m_lock_mode)
+ return true;
+
+ if (m_lock_mode != NoLock)
+ unlock();
+
+ struct flock fl;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
+ int cmd = block ? F_SETLKW : F_SETLK;
+ int ret = fcntl(handle(), cmd, &fl);
+
+ if (ret == -1) {
+ if (errno != EINTR && errno != EAGAIN)
+ qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
+ return false;
+ }
+
+
+ m_lock_mode = mode;
+ return true;
+}
+
+
+bool QtLockedFile::unlock()
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::unlock(): file is not opened");
+ return false;
+ }
+
+ if (!isLocked())
+ return true;
+
+ struct flock fl;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_type = F_UNLCK;
+ int ret = fcntl(handle(), F_SETLKW, &fl);
+
+ if (ret == -1) {
+ qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
+ return false;
+ }
+
+ m_lock_mode = NoLock;
+ return true;
+}
+
+QtLockedFile::~QtLockedFile()
+{
+ if (isOpen())
+ unlock();
+}
+
+}
diff --git a/shared/qtlockedfile/qtlockedfile_win.cpp b/shared/qtlockedfile/qtlockedfile_win.cpp
new file mode 100644
index 0000000000..01e3f76e75
--- /dev/null
+++ b/shared/qtlockedfile/qtlockedfile_win.cpp
@@ -0,0 +1,205 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtlockedfile.h"
+#include <qt_windows.h>
+#include <QtCore/QFileInfo>
+
+namespace SharedTools {
+
+#define SEMAPHORE_PREFIX "QtLockedFile semaphore "
+#define MUTEX_PREFIX "QtLockedFile mutex "
+#define SEMAPHORE_MAX 100
+
+static QString errorCodeToString(DWORD errorCode)
+{
+ QString result;
+ char *data = 0;
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, errorCode, 0,
+ (char*)&data, 0, 0);
+ result = QString::fromLocal8Bit(data);
+ if (data != 0)
+ LocalFree(data);
+
+ if (result.endsWith("\n"))
+ result.truncate(result.length() - 1);
+
+ return result;
+}
+
+bool QtLockedFile::lock(LockMode mode, bool block)
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::lock(): file is not opened");
+ return false;
+ }
+
+ if (mode == m_lock_mode)
+ return true;
+
+ if (m_lock_mode != 0)
+ unlock();
+
+ if (m_semaphore_hnd == 0) {
+ QFileInfo fi(*this);
+ QString sem_name = QString::fromLatin1(SEMAPHORE_PREFIX)
+ + fi.absoluteFilePath().toLower();
+
+ QT_WA( {
+ m_semaphore_hnd = CreateSemaphoreW(0, SEMAPHORE_MAX, SEMAPHORE_MAX,
+ (TCHAR*)sem_name.utf16());
+ } , {
+ m_semaphore_hnd = CreateSemaphoreA(0, SEMAPHORE_MAX, SEMAPHORE_MAX,
+ sem_name.toLocal8Bit().constData());
+ } );
+
+ if (m_semaphore_hnd == 0) {
+ qWarning("QtLockedFile::lock(): CreateSemaphore: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ }
+
+ bool gotMutex = false;
+ int decrement;
+ if (mode == ReadLock) {
+ decrement = 1;
+ } else {
+ decrement = SEMAPHORE_MAX;
+ if (m_mutex_hnd == 0) {
+ QFileInfo fi(*this);
+ QString mut_name = QString::fromLatin1(MUTEX_PREFIX)
+ + fi.absoluteFilePath().toLower();
+ QT_WA( {
+ m_mutex_hnd = CreateMutexW(NULL, FALSE, (TCHAR*)mut_name.utf16());
+ } , {
+ m_mutex_hnd = CreateMutexA(NULL, FALSE, mut_name.toLocal8Bit().constData());
+ } );
+
+ if (m_mutex_hnd == 0) {
+ qWarning("QtLockedFile::lock(): CreateMutex: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ }
+ DWORD res = WaitForSingleObject(m_mutex_hnd, block ? INFINITE : 0);
+ if (res == WAIT_TIMEOUT)
+ return false;
+ if (res == WAIT_FAILED) {
+ qWarning("QtLockedFile::lock(): WaitForSingleObject (mutex): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ gotMutex = true;
+ }
+
+ for (int i = 0; i < decrement; ++i) {
+ DWORD res = WaitForSingleObject(m_semaphore_hnd, block ? INFINITE : 0);
+ if (res == WAIT_TIMEOUT) {
+ if (i) {
+ // A failed nonblocking rw locking. Undo changes to semaphore.
+ if (ReleaseSemaphore(m_semaphore_hnd, i, NULL) == 0) {
+ qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ // Fall through
+ }
+ }
+ if (gotMutex)
+ ReleaseMutex(m_mutex_hnd);
+ return false;
+ }
+ if (res != WAIT_OBJECT_0) {
+ if (gotMutex)
+ ReleaseMutex(m_mutex_hnd);
+ qWarning("QtLockedFile::lock(): WaitForSingleObject (semaphore): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ }
+
+ m_lock_mode = mode;
+ if (gotMutex)
+ ReleaseMutex(m_mutex_hnd);
+ return true;
+}
+
+bool QtLockedFile::unlock()
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::unlock(): file is not opened");
+ return false;
+ }
+
+ if (!isLocked())
+ return true;
+
+ int increment;
+ if (m_lock_mode == ReadLock)
+ increment = 1;
+ else
+ increment = SEMAPHORE_MAX;
+
+ DWORD ret = ReleaseSemaphore(m_semaphore_hnd, increment, 0);
+ if (ret == 0) {
+ qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+
+ m_lock_mode = QtLockedFile::NoLock;
+ return true;
+}
+
+QtLockedFile::~QtLockedFile()
+{
+ if (isOpen())
+ unlock();
+ if (m_mutex_hnd != 0) {
+ DWORD ret = CloseHandle(m_mutex_hnd);
+ if (ret == 0) {
+ qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (mutex): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ }
+ m_mutex_hnd = 0;
+ }
+ if (m_semaphore_hnd != 0) {
+ DWORD ret = CloseHandle(m_semaphore_hnd);
+ if (ret == 0) {
+ qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (semaphore): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ }
+ m_semaphore_hnd = 0;
+ }
+}
+
+}
diff --git a/shared/qtsingleapplication/README.txt b/shared/qtsingleapplication/README.txt
new file mode 100644
index 0000000000..1909a33fca
--- /dev/null
+++ b/shared/qtsingleapplication/README.txt
@@ -0,0 +1,10 @@
+This is the src directory of the QtSingleApplication solution
+integrated over from addons/main/utils/qtsingleapplication/src .
+
+namespace.patch was applied to introduce the SharedTools namespace.
+
+It additionally requires the QtLockedFile solution.
+
+History:
+
+16.05.2008 Integrated
diff --git a/shared/qtsingleapplication/namespace.patch b/shared/qtsingleapplication/namespace.patch
new file mode 100644
index 0000000000..2876e3a378
--- /dev/null
+++ b/shared/qtsingleapplication/namespace.patch
@@ -0,0 +1,133 @@
+
+--- qtlocalpeer.cpp 1970-01-01 01:00:00.000000000
++++ qtlocalpeer.cpp 2008/05/16 10:36:53.000000000
+@@ -13,6 +13,8 @@
+ #include <time.h>
+ #endif
+
++namespace SharedTools {
++
+ const char* QtLocalPeer::ack = "ack";
+
+ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
+@@ -139,3 +141,5 @@
+ delete socket;
+ emit messageReceived(message); // ##(might take a long time to return)
+ }
++
++}
+
+--- qtlocalpeer.h 1970-01-01 01:00:00.000000000
++++ qtlocalpeer.h 2008/05/16 10:36:53.000000000
+@@ -1,9 +1,11 @@
+
++
+ #include <QtNetwork/QLocalServer>
+ #include <QtNetwork/QLocalSocket>
+ #include <QtCore/QDir>
+ #include <qtlockedfile.h>
+
++namespace SharedTools {
+
+ class QtLocalPeer : public QObject
+ {
+@@ -31,3 +33,5 @@
+ private:
+ static const char* ack;
+ };
++
++} // SharedTools
+
+--- qtsingleapplication.cpp 1970-01-01 01:00:00.000000000
++++ qtsingleapplication.cpp 2008/05/16 10:36:53.000000000
+@@ -3,6 +3,8 @@
+ #include "qtlocalpeer.h"
+ #include <QtGui/QWidget>
+
++namespace SharedTools {
++
+ void QtSingleApplication::sysInit(const QString &appId)
+ {
+ actWin = 0;
+@@ -95,3 +97,5 @@
+ actWin->activateWindow();
+ }
+ }
++
++}
+
+--- qtsingleapplication.h 1970-01-01 01:00:00.000000000
++++ qtsingleapplication.h 2008/05/16 10:36:53.000000000
+@@ -1,6 +1,8 @@
+
+ #include <QtGui/QApplication>
+
++namespace SharedTools {
++
+ class QtLocalPeer;
+
+ class QtSingleApplication : public QApplication
+@@ -47,3 +49,5 @@
+ QtLocalPeer *peer;
+ QWidget *actWin;
+ };
++
++}
+
+--- qtsingleapplication.pri 1970-01-01 01:00:00.000000000
++++ qtsingleapplication.pri 2008/05/16 10:36:53.000000000
+@@ -6,7 +6,7 @@
+ QT *= network
+
+ gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+-isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri)
++isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+ win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+
+--- qtsinglecoreapplication.cpp 1970-01-01 01:00:00.000000000
++++ qtsinglecoreapplication.cpp 2008/05/16 10:36:53.000000000
+@@ -2,6 +2,7 @@
+ #include "qtsinglecoreapplication.h"
+ #include "qtlocalpeer.h"
+
++namespace SharedTools {
+
+ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+@@ -36,3 +37,4 @@
+ return peer->applicationId();
+ }
+
++}
+
+--- qtsinglecoreapplication.h 1970-01-01 01:00:00.000000000
++++ qtsinglecoreapplication.h 2008/05/16 10:36:53.000000000
+@@ -1,6 +1,8 @@
+
+ #include <QtCore/QCoreApplication>
+
++namespace SharedTools {
++
+ class QtLocalPeer;
+
+ class QtSingleCoreApplication : public QCoreApplication
+@@ -25,3 +27,5 @@
+ private:
+ QtLocalPeer* peer;
+ };
++
++}
+
+--- qtsinglecoreapplication.pri 1970-01-01 01:00:00.000000000
++++ qtsinglecoreapplication.pri 2008/05/16 10:36:53.000000000
+@@ -6,7 +6,7 @@
+ QT *= network
+
+ gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+-isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri)
++isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+ win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
diff --git a/shared/qtsingleapplication/qtlocalpeer.cpp b/shared/qtsingleapplication/qtlocalpeer.cpp
new file mode 100644
index 0000000000..30a195f908
--- /dev/null
+++ b/shared/qtsingleapplication/qtlocalpeer.cpp
@@ -0,0 +1,179 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtlocalpeer.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTime>
+
+#if defined(Q_OS_WIN)
+#include <QtCore/QLibrary>
+#include <QtCore/qt_windows.h>
+typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
+static PProcessIdToSessionId pProcessIdToSessionId = 0;
+#endif
+
+#if defined(Q_OS_UNIX)
+#include <time.h>
+#include <unistd.h>
+#endif
+
+namespace SharedTools {
+
+const char* QtLocalPeer::ack = "ack";
+
+QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
+ : QObject(parent), id(appId)
+{
+ if (id.isEmpty())
+ id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
+
+ QByteArray idc = id.toUtf8();
+ quint16 idNum = qChecksum(idc.constData(), idc.size());
+ //### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
+
+ socketName = QLatin1String("qtsingleapplication-")
+ + QString::number(idNum, 16);
+#if defined(Q_OS_WIN)
+ if (!pProcessIdToSessionId) {
+ QLibrary lib("kernel32");
+ pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
+ }
+ if (pProcessIdToSessionId) {
+ DWORD sessionId = 0;
+ pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
+ socketName += QLatin1Char('-') + QString::number(sessionId, 16);
+ }
+#else
+ socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
+#endif
+
+ server = new QLocalServer(this);
+ QString lockName = QDir(QDir::tempPath()).absolutePath()
+ + QLatin1Char('/') + socketName
+ + QLatin1String("-lockfile");
+ lockFile.setFileName(lockName);
+ lockFile.open(QIODevice::ReadWrite);
+}
+
+
+
+bool QtLocalPeer::isClient()
+{
+ if (lockFile.isLocked())
+ return false;
+
+ if (!lockFile.lock(QtLockedFile::WriteLock, false))
+ return true;
+
+ bool res = server->listen(socketName);
+ if (!res && server->serverError() == QAbstractSocket::AddressInUseError)
+ res = server->listen(socketName); // ### Workaround 4.4.0tp bug
+ if (!res)
+ qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
+ QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
+ return false;
+}
+
+
+bool QtLocalPeer::sendMessage(const QString &message, int timeout)
+{
+ if (!isClient())
+ return false;
+
+ QLocalSocket socket;
+ bool connOk = false;
+ for(int i = 0; i < 2; i++) {
+ // Try twice, in case the other instance is just starting up
+ socket.connectToServer(socketName);
+ connOk = socket.waitForConnected(timeout/2);
+ if (connOk || i)
+ break;
+ int ms = 250;
+#if defined(Q_OS_WIN)
+ Sleep(DWORD(ms));
+#else
+ struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
+ nanosleep(&ts, NULL);
+#endif
+ }
+ if (!connOk)
+ return false;
+
+ QByteArray uMsg(message.toUtf8());
+ QDataStream ds(&socket);
+ ds.writeBytes(uMsg.constData(), uMsg.size());
+ bool res = socket.waitForBytesWritten(timeout);
+ res &= socket.waitForReadyRead(timeout); // wait for ack
+ res &= (socket.read(qstrlen(ack)) == ack);
+ return res;
+}
+
+
+void QtLocalPeer::receiveConnection()
+{
+ QLocalSocket* socket = server->nextPendingConnection();
+ if (!socket)
+ return;
+
+ // Why doesn't Qt have a blocking stream that takes care of this shait???
+ while (socket->bytesAvailable() < sizeof(quint32))
+ socket->waitForReadyRead();
+ QDataStream ds(socket);
+ QByteArray uMsg;
+ quint32 remaining;
+ ds >> remaining;
+ uMsg.resize(remaining);
+ int got = 0;
+ char* uMsgBuf = uMsg.data();
+ //qDebug() << "RCV: remaining" << remaining;
+ do {
+ got = ds.readRawData(uMsgBuf, remaining);
+ remaining -= got;
+ uMsgBuf += got;
+ //qDebug() << "RCV: got" << got << "remaining" << remaining;
+ } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
+ //### error check: got<0
+ if (got < 0) {
+ qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString();
+ delete socket;
+ return;
+ }
+ // ### async this
+ QString message(QString::fromUtf8(uMsg));
+ socket->write(ack, qstrlen(ack));
+ socket->waitForBytesWritten(1000);
+ delete socket;
+ emit messageReceived(message); // ##(might take a long time to return)
+}
+
+}
diff --git a/shared/qtsingleapplication/qtlocalpeer.h b/shared/qtsingleapplication/qtlocalpeer.h
new file mode 100644
index 0000000000..bac571bd28
--- /dev/null
+++ b/shared/qtsingleapplication/qtlocalpeer.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+
+#include <QtNetwork/QLocalServer>
+#include <QtNetwork/QLocalSocket>
+#include <QtCore/QDir>
+#include <qtlockedfile.h>
+
+namespace SharedTools {
+
+class QtLocalPeer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
+ bool isClient();
+ bool sendMessage(const QString &message, int timeout);
+ QString applicationId() const
+ { return id; }
+
+Q_SIGNALS:
+ void messageReceived(const QString &message);
+
+protected Q_SLOTS:
+ void receiveConnection();
+
+protected:
+ QString id;
+ QString socketName;
+ QLocalServer* server;
+ QtLockedFile lockFile;
+
+private:
+ static const char* ack;
+};
+
+} // SharedTools
diff --git a/shared/qtsingleapplication/qtsingleapplication.cpp b/shared/qtsingleapplication/qtsingleapplication.cpp
new file mode 100644
index 0000000000..ff437e039e
--- /dev/null
+++ b/shared/qtsingleapplication/qtsingleapplication.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtsingleapplication.h"
+#include "qtlocalpeer.h"
+#include <QtGui/QWidget>
+#include <QtGui/QFileOpenEvent>
+
+namespace SharedTools {
+
+void QtSingleApplication::sysInit(const QString &appId)
+{
+ actWin = 0;
+ peer = new QtLocalPeer(this, appId);
+ connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
+}
+
+
+QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
+ : QApplication(argc, argv, GUIenabled)
+{
+ sysInit();
+}
+
+
+QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
+ : QApplication(argc, argv)
+{
+ sysInit(appId);
+}
+
+
+QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
+ : QApplication(argc, argv, type)
+{
+ sysInit();
+}
+
+
+#if defined(Q_WS_X11)
+QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
+ : QApplication(dpy, visual, colormap)
+{
+ sysInit();
+}
+
+QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
+ : QApplication(dpy, argc, argv, visual, cmap)
+{
+ sysInit();
+}
+
+QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE colormap)
+ : QApplication(dpy, argc, argv, visual, colormap)
+{
+ sysInit(appId);
+}
+#endif
+
+bool QtSingleApplication::event(QEvent *event)
+{
+ if (event->type() == QEvent::FileOpen) {
+ QFileOpenEvent *foe = static_cast<QFileOpenEvent*>(event);
+ emit fileOpenRequest(foe->file());
+ return true;
+ }
+ return QApplication::event(event);
+}
+
+bool QtSingleApplication::isRunning()
+{
+ return peer->isClient();
+}
+
+
+bool QtSingleApplication::sendMessage(const QString &message, int timeout)
+{
+ return peer->sendMessage(message, timeout);
+}
+
+
+QString QtSingleApplication::id() const
+{
+ return peer->applicationId();
+}
+
+
+void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
+{
+ actWin = aw;
+ if (activateOnMessage)
+ connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
+ else
+ disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
+}
+
+
+QWidget* QtSingleApplication::activationWindow() const
+{
+ return actWin;
+}
+
+
+void QtSingleApplication::activateWindow()
+{
+ if (actWin) {
+ actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
+ actWin->raise();
+ actWin->activateWindow();
+ }
+}
+
+}
diff --git a/shared/qtsingleapplication/qtsingleapplication.h b/shared/qtsingleapplication/qtsingleapplication.h
new file mode 100644
index 0000000000..f56e3f1c35
--- /dev/null
+++ b/shared/qtsingleapplication/qtsingleapplication.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtGui/QApplication>
+
+namespace SharedTools {
+
+class QtLocalPeer;
+
+class QtSingleApplication : public QApplication
+{
+ Q_OBJECT
+
+public:
+ QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
+ QtSingleApplication(const QString &id, int &argc, char **argv);
+ QtSingleApplication(int &argc, char **argv, Type type);
+#if defined(Q_WS_X11)
+ QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
+ QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
+#endif
+
+ bool isRunning();
+ QString id() const;
+
+ void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
+ QWidget* activationWindow() const;
+ bool event(QEvent *event);
+
+
+public Q_SLOTS:
+ bool sendMessage(const QString &message, int timeout = 5000);
+ void activateWindow();
+
+//Obsolete methods:
+public:
+ void initialize(bool = true)
+ { isRunning(); }
+
+#if defined(Q_WS_X11)
+ QtSingleApplication(Display* dpy, const QString &id, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
+#endif
+// end obsolete methods
+
+Q_SIGNALS:
+ void messageReceived(const QString &message);
+ void fileOpenRequest(const QString &file);
+
+private:
+ void sysInit(const QString &appId = QString());
+ QtLocalPeer *peer;
+ QWidget *actWin;
+};
+
+}
diff --git a/shared/qtsingleapplication/qtsingleapplication.pri b/shared/qtsingleapplication/qtsingleapplication.pri
new file mode 100644
index 0000000000..f6d8462619
--- /dev/null
+++ b/shared/qtsingleapplication/qtsingleapplication.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
+SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
+
+QT *= network
+
+gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+ DEFINES += QT_QTSINGLEAPPLICATION_EXPORT=__declspec(dllexport)
+}
diff --git a/shared/qtsingleapplication/qtsinglecoreapplication.cpp b/shared/qtsingleapplication/qtsinglecoreapplication.cpp
new file mode 100644
index 0000000000..d3c636641d
--- /dev/null
+++ b/shared/qtsingleapplication/qtsinglecoreapplication.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtsinglecoreapplication.h"
+#include "qtlocalpeer.h"
+
+namespace SharedTools {
+
+QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+{
+ peer = new QtLocalPeer(this);
+ connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
+}
+
+
+QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+{
+ peer = new QtLocalPeer(this, appId);
+ connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
+}
+
+
+bool QtSingleCoreApplication::isRunning()
+{
+ return peer->isClient();
+}
+
+
+bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
+{
+ return peer->sendMessage(message, timeout);
+}
+
+
+QString QtSingleCoreApplication::id() const
+{
+ return peer->applicationId();
+}
+
+}
diff --git a/shared/qtsingleapplication/qtsinglecoreapplication.h b/shared/qtsingleapplication/qtsinglecoreapplication.h
new file mode 100644
index 0000000000..185a82a0b3
--- /dev/null
+++ b/shared/qtsingleapplication/qtsinglecoreapplication.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtCore/QCoreApplication>
+
+namespace SharedTools {
+
+class QtLocalPeer;
+
+class QtSingleCoreApplication : public QCoreApplication
+{
+ Q_OBJECT
+
+public:
+ QtSingleCoreApplication(int &argc, char **argv);
+ QtSingleCoreApplication(const QString &id, int &argc, char **argv);
+
+ bool isRunning();
+ QString id() const;
+
+public Q_SLOTS:
+ bool sendMessage(const QString &message, int timeout = 5000);
+
+
+Q_SIGNALS:
+ void messageReceived(const QString &message);
+
+
+private:
+ QtLocalPeer* peer;
+};
+
+}
diff --git a/shared/qtsingleapplication/qtsinglecoreapplication.pri b/shared/qtsingleapplication/qtsinglecoreapplication.pri
new file mode 100644
index 0000000000..3d6301b29c
--- /dev/null
+++ b/shared/qtsingleapplication/qtsinglecoreapplication.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
+SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
+
+QT *= network
+
+gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+ DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
+}
diff --git a/shared/scriptwrapper/README b/shared/scriptwrapper/README
new file mode 100644
index 0000000000..dd7f4bf14a
--- /dev/null
+++ b/shared/scriptwrapper/README
@@ -0,0 +1,58 @@
+Some wrap helpers for Script support.
+
+How to wrap an interface:
+=========================
+
+1) Prototypes (preferred)
+-------------------------
+
+- Interface must inherit QObjectInterface and be qvariant-castable, that is,
+ declared as Q-MetaType.
+
+- Register a prototype with the engine for each interface:
+ - Provide an informative toString()-slot.
+ - Use properties and slots for everything, can be non-void as well
+ - Accessors to interfaces should be properties.
+
+- In the toScriptValue() function passed on to qScriptRegisterMetaType, create
+ an newQObject on the QObject obtained from the QObjectInterface and assign it the prototype
+ registered for the interface (obtained from the engine) using QScriptValue::setDefaultPrototype
+ The prototype can then qobject (-extension)-cast to the interface as each
+ implementing class returns 'this' as qObject() of QObjectInterface.
+
+- If sequences of the interface are used, declare them as Q-MetaType
+ and do qScriptRegisterSequenceMetaType().
+
+The template registerQObjectInterface does the magic.
+
+2) Manually bless a script value with properties
+------------------------------------------------
+
+Typically, a qobject-derived wrapper will be used
+that provides an accessor to the wrapped class.
+The wrapper contains a QScriptValue 'm_self' which
+typically is initialized using:
+
+- engine.newQObject(this, QScriptEngine::ScriptOwnership))
+ for interfaces that are always present.
+
+- m_self(engine.newQObject(this, QScriptEngine::QtOwnership)),
+ can be used when setting the qObject() of an QObjectInterface
+ as parent of the qobject-derived wrapper. If the QObject goes
+ out of scope while running the script, the script object
+ will stop working.
+
+A conversion cast to QScriptValue can then be provided.
+
+How to wrap functions:
+
+Most functions can then be implemented as slots, property-like
+things as such.
+
+The other functions have to be implemented via script-callbacks.
+(Parameter checking required).
+
+The templates in here can help in writing the wrapper
+objects. For examples, see
+
+src/plugins/core/scriptmanager/qworkbench_wrapper.h
diff --git a/shared/scriptwrapper/interface_wrap_helpers.h b/shared/scriptwrapper/interface_wrap_helpers.h
new file mode 100644
index 0000000000..eb1f4b37ac
--- /dev/null
+++ b/shared/scriptwrapper/interface_wrap_helpers.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INTERFACE_WRAP_HELPERS_H
+#define INTERFACE_WRAP_HELPERS_H
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <QtScript/QScriptEngine>
+
+ namespace SharedTools {
+
+// Convert a QObjectInterface to Scriptvalue
+// To be registered as a magic creation function with qScriptRegisterMetaType().
+// (see registerQObjectInterface)
+
+template <class QObjectInterface>
+static QScriptValue qObjectInterfaceToScriptValue(QScriptEngine *engine, QObjectInterface* const &qoif)
+{
+ if (!qoif)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QObject *qObject = const_cast<QObjectInterface *>(qoif);
+
+ const QScriptEngine::QObjectWrapOptions wrapOptions =
+ QScriptEngine::ExcludeChildObjects|QScriptEngine::ExcludeSuperClassMethods|QScriptEngine::ExcludeSuperClassProperties;
+ return engine->newQObject(qObject, QScriptEngine::QtOwnership, wrapOptions);
+}
+
+// Convert Scriptvalue back to QObjectInterface
+// To be registered as a magic conversion function with qScriptRegisterMetaType().
+// (see registerQObjectInterface)
+
+template <class QObjectInterface>
+static void scriptValueToQObjectInterface(const QScriptValue &sv, QObjectInterface *&p)
+{
+ QObject *qObject = sv.toQObject();
+ p = qobject_cast<QObjectInterface*>(qObject);
+}
+
+// Magically register a Workbench interface derived from
+// ExtensionSystem::QObjectInterface class with the engine.
+// To avoid lifecycle issues, the script value is created on the QObject returned
+// by ExtensionSystem::QObjectInterface::qObject() and given the specified
+// prototype. By convention, ExtensionSystem::QObjectInterface::qObject() returns an
+// QObject that implements the interface, so it can be casted to it.
+
+template <class QObjectInterface, class Prototype>
+static void registerQObjectInterface(QScriptEngine &engine)
+{
+ Prototype *protoType = new Prototype(&engine);
+ const QScriptValue scriptProtoType = engine.newQObject(protoType);
+
+ const int metaTypeId = qScriptRegisterMetaType<QObjectInterface*>(
+ &engine,
+ qObjectInterfaceToScriptValue<QObjectInterface>,
+ scriptValueToQObjectInterface<QObjectInterface>,
+ scriptProtoType);
+ Q_UNUSED(metaTypeId);
+}
+
+}
+
+#endif
diff --git a/shared/scriptwrapper/scriptwrapper.pri b/shared/scriptwrapper/scriptwrapper.pri
new file mode 100644
index 0000000000..49c7d607cf
--- /dev/null
+++ b/shared/scriptwrapper/scriptwrapper.pri
@@ -0,0 +1,3 @@
+INCLUDEPATH *= $$PWD
+
+HEADERS += $$PWD/wrap_helpers.h
diff --git a/shared/scriptwrapper/wrap_helpers.h b/shared/scriptwrapper/wrap_helpers.h
new file mode 100644
index 0000000000..cb7f68dddb
--- /dev/null
+++ b/shared/scriptwrapper/wrap_helpers.h
@@ -0,0 +1,334 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WRAP_HELPERS_H
+#define WRAP_HELPERS_H
+
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptContext>
+#include <QtScript/QScriptValue>
+
+namespace SharedTools {
+
+// Strip a const ref from a type via template specialization trick.
+// Use for determining function call args
+
+template <class T>
+ struct RemoveConstRef {
+ typedef T Result;
+ };
+
+template <class T>
+ struct RemoveConstRef<const T &> {
+ typedef T Result;
+ };
+
+// Template that retrieves a QObject-derived class from a QScriptValue.
+
+template <class QObjectDerived>
+ QObjectDerived *qObjectFromScriptValue(const QScriptValue &v)
+{
+ if (!v.isQObject())
+ return 0;
+ QObject *o = v.toQObject();
+ return qobject_cast<QObjectDerived *>(o);
+}
+
+// Template that retrieves a wrapped object from a QScriptValue.
+// The wrapped object is accessed through an accessor of
+// the QObject-derived wrapper.
+
+template <class Wrapper, class Wrapped>
+ Wrapped *wrappedFromScriptValue(const QScriptValue &v,
+ Wrapped * (Wrapper::*wrappedAccessor) () const)
+{
+ Wrapper *wrapper = qObjectFromScriptValue<Wrapper>(v);
+ if (!wrapper)
+ return 0;
+ return (wrapper->*wrappedAccessor)();
+}
+
+// Template that retrieves a wrapped object from
+// a QObject-derived script wrapper object that is set as 'this' in
+// a script context via accessor.
+
+template <class Wrapper, class Wrapped>
+ static inline Wrapped *wrappedThisFromContext(QScriptContext *context,
+ Wrapped * (Wrapper::*wrappedAccessor) () const)
+{
+ Wrapped *wrapped = wrappedFromScriptValue(context->thisObject(), wrappedAccessor);
+ Q_ASSERT(wrapped);
+ return wrapped;
+}
+
+// Template that retrieves an object contained in a wrapped object
+// in a script getter call (namely the interfaces returned by
+// the core interface accessors). Mangles out the wrapper object from
+// thisObject(), accesses the wrapped object and returns the contained object.
+
+template <class Contained, class Wrapper, class Wrapped>
+ static inline Contained *containedFromContext(QScriptContext *context,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Contained * (Wrapped::*containedAccessor)() const)
+{
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ return (wrapped->*containedAccessor)();
+}
+
+// Template that retrieves a contained QObject-type object
+// in a script getter call and creates a new script-object via engine->newQObject().
+// To be called from a script getter callback.
+
+template <class Contained, class Wrapper, class Wrapped>
+ static inline QScriptValue containedQObjectFromContextToScriptValue(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Contained * (Wrapped::*containedAccessor)() const)
+{
+ return engine->newQObject(containedFromContext(context, wrappedAccessor, containedAccessor));
+}
+
+// Template that retrieves a contained Non-QObject-type object
+// in a script getter call and creates a new script-object by wrapping it into
+// a new instance of ContainedWrapper (which casts to QScriptValue).
+// To be called from a script getter callback.
+
+template <class ContainedWrapper, class Contained, class Wrapper, class Wrapped>
+ static inline QScriptValue wrapContainedFromContextAsScriptValue(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Contained * (Wrapped::*containedAccessor)() const)
+{
+ Contained *c = containedFromContext(context, wrappedAccessor, containedAccessor);
+ if (!c)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ ContainedWrapper *cw = new ContainedWrapper(*engine, c);
+ return *cw; // cast to QScriptValue
+}
+
+// Template that retrieves a wrapped object from context (this)
+// and calls a const-member function with no parameters.
+// To be called from a script getter callback.
+
+template <class Ret, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallConstMember_0(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)() const)
+{
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ return engine->toScriptValue( (wrapped->*member)() );
+}
+
+// Ditto for non-const
+
+template <class Ret, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallMember_0(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)())
+{
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ return engine->toScriptValue( (wrapped->*member)() );
+}
+
+// Template that retrieves a wrapped object from context (this)
+// and calls a const-member function with 1 parameter on it.
+// To be called from a script getter callback.
+
+template <class Ret, class Argument, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallConstMember_1(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)(Argument a1) const)
+{
+ const int argumentCount = context->argumentCount();
+ if ( argumentCount != 1)
+ return QScriptValue (engine, QScriptValue::NullValue);
+
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ // call member. If the argument is a const ref, strip it.
+ typedef typename RemoveConstRef<Argument>::Result ArgumentBase;
+ ArgumentBase a = qscriptvalue_cast<ArgumentBase>(context->argument(0));
+ return engine->toScriptValue( (wrapped->*member)(a) );
+}
+
+// Template that retrieves a wrapped object
+// and calls a member function with 1 parameter on it.
+// To be called from a script getter callback.
+
+template <class Ret, class Argument, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallMember_1(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)(Argument a1))
+{
+ const int argumentCount = context->argumentCount();
+ if ( argumentCount != 1)
+ return QScriptValue (engine, QScriptValue::NullValue);
+
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ // call member. If the argument is a const ref, strip it.
+ typedef typename RemoveConstRef<Argument>::Result ArgumentBase;
+ ArgumentBase a = qscriptvalue_cast<ArgumentBase>(context->argument(0));
+ return engine->toScriptValue( (wrapped->*member)(a) );
+}
+
+// Template that retrieves a wrapped object
+// and calls a void member function with 1 parameter that is a wrapper of
+// of some interface.
+// Typically used for something like 'setCurrentEditor(Editor*)'
+// To be called from a script callback.
+
+template <class ThisWrapper, class ThisWrapped, class ArgumentWrapper, class ArgumentWrapped>
+static QScriptValue scriptCallVoidMember_Wrapped1(QScriptContext *context, QScriptEngine *engine,
+ ThisWrapped * (ThisWrapper::*thisWrappedAccessor) () const,
+ ArgumentWrapped *(ArgumentWrapper::*argumentWrappedAccessor)() const,
+ void (ThisWrapped::*member)(ArgumentWrapped *a1),
+ bool acceptNullArgument = false)
+{
+ const QScriptValue voidRC = QScriptValue(engine, QScriptValue::UndefinedValue);
+ if (context->argumentCount() < 1)
+ return voidRC;
+
+ ThisWrapped *thisWrapped = wrappedThisFromContext(context, thisWrappedAccessor);
+ ArgumentWrapped *aw = wrappedFromScriptValue(context->argument(0), argumentWrappedAccessor);
+ if (acceptNullArgument || aw)
+ (thisWrapped->*member)(aw);
+ return voidRC;
+}
+
+// Macros that define the static functions to call members
+
+#define SCRIPT_CALL_CONST_MEMBER_0(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallConstMember_0(context, engine, accessor, member); }
+
+#define SCRIPT_CALL_MEMBER_0(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallMember_0(context, engine, accessor, member); }
+
+#define SCRIPT_CALL_CONST_MEMBER_1(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallConstMember_1(context, engine, accessor, member); }
+
+#define SCRIPT_CALL_MEMBER_1(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallMember_1(context, engine, accessor, member); }
+
+// Create a script list of wrapped non-qobjects by wrapping them.
+// Wrapper must cast to QScriptValue.
+
+template <class Wrapper, class Iterator>
+ static inline QScriptValue wrapObjectList( QScriptEngine *engine, Iterator i1, Iterator i2)
+{
+ QScriptValue rc = engine->newArray(i2 - i1); // Grrr!
+ quint32 i = 0;
+ for ( ; i1 != i2 ; ++i1, i++) {
+ Wrapper * wrapper = new Wrapper(*engine, *i1);
+ rc.setProperty(i, *wrapper);
+ }
+ return rc;
+}
+
+// Unwrap a list of wrapped objects from a script list.
+
+template <class Wrapper, class Wrapped>
+ static inline QList<Wrapped*> unwrapObjectList(const QScriptValue &v,
+ Wrapped *(Wrapper::*wrappedAccessor)() const)
+{
+ QList<Wrapped*> rc;
+
+ if (!v.isArray())
+ return rc;
+
+ const quint32 len = v.property(QLatin1String("length")).toUInt32();
+ if (!len)
+ return rc;
+
+ for (quint32 i = 0; i < len; i++) {
+ const QScriptValue e = v.property(i);
+ if (e.isQObject()) {
+ QObject *o = e.toQObject();
+ if (Wrapper * wrapper = qobject_cast<Wrapper *>(o))
+ rc.push_back((wrapper->*wrappedAccessor)());
+ }
+ }
+ return rc;
+}
+
+// Traditional registration of a prototype for an interface.
+// that can be converted via script value casts via Q_DECLARE_METATYPE.
+
+template <class Interface, class Prototype>
+ static void registerInterfaceWithDefaultPrototype(QScriptEngine &engine)
+{
+ Prototype *protoType = new Prototype(&engine);
+ const QScriptValue scriptProtoType = engine.newQObject(protoType);
+
+ engine.setDefaultPrototype(qMetaTypeId<Interface*>(), scriptProtoType);
+}
+
+// Convert a class derived from QObject to Scriptvalue via engine->newQObject() to make
+// the signals, slots and properties visible.
+// To be registered as a magic creation function with qScriptRegisterMetaType().
+// (see registerQObject()
+
+template <class SomeQObject>
+static QScriptValue qObjectToScriptValue(QScriptEngine *engine, SomeQObject * const &qo)
+{
+ return engine->newQObject(qo, QScriptEngine::QtOwnership, QScriptEngine::ExcludeChildObjects);
+}
+
+// Convert Scriptvalue back to a class derived from QObject via QScriptValue::toQObject()
+// To be registered as a magic conversion function with qScriptRegisterMetaType().
+// (see registerQObject)
+
+template <class SomeQObject>
+static void scriptValueToQObject(const QScriptValue &sv, SomeQObject * &p)
+{
+ QObject *qObject = sv.toQObject();
+ p = qobject_cast<SomeQObject*>(qObject);
+ Q_ASSERT(p);
+}
+
+// Register a QObject-derived class which has Q_DECLARE_METATYPE(Ptr*)
+// with the engine using qObjectToScriptValue/scriptValueToQObject as
+// conversion functions to make it possible to use for example
+// Q_PROPERTY(QMainWindow*).
+
+template <class SomeQObject>
+static void registerQObject(QScriptEngine &engine)
+{
+ qScriptRegisterMetaType<SomeQObject*>(&engine,
+ qObjectToScriptValue<SomeQObject>,
+ scriptValueToQObject<SomeQObject>);
+}
+
+}
+
+#endif
diff --git a/src/app/Info.plist b/src/app/Info.plist
new file mode 100644
index 0000000000..dbd50d35ee
--- /dev/null
+++ b/src/app/Info.plist
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleTypeIconFile</key>
+ <string>qtcreator.icns</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>pro</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Qt Project File</string>
+ <key>LSHandlerRank</key>
+ <string>Default</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>pri</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Qt Project Include File</string>
+ <key>LSHandlerRank</key>
+ <string>Default</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>qrc</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Qt Resource File</string>
+ <key>LSHandlerRank</key>
+ <string>Default</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>pri</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Qt UI File</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>h</string>
+ <string>hpp</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Header File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ <string>utxt</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>cc</string>
+ <string>CC</string>
+ <string>cp</string>
+ <string>CP</string>
+ <string>cpp</string>
+ <string>CPP</string>
+ <string>cxx</string>
+ <string>CXX</string>
+ <string>c++</string>
+ <string>C++</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>C++ Source File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ <string>utxt</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>mm</string>
+ <string>MM</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Objective-C++ Source File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ <string>utxt</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>m</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Objective-C Source File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ <string>utxt</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>c</string>
+ <string>C</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>C Source File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ <string>utxt</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>txt</string>
+ <string>text</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Text File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>*</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>NSStringPboardType</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>****</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ </array>
+ <key>CFBundleGetInfoString</key>
+ <string>Qt Creator; Copyright Nokia Corporation</string>
+ <key>CFBundleIconFile</key>
+ <string>@ICON@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>@TYPEINFO@</string>
+ <key>CFBundleExecutable</key>
+ <string>@EXECUTABLE@</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.nokia.qtcreator</string>
+ <key>CFBundleVersion</key>
+ <string>0.9.1</string>
+ <key>CFBundleShortVersionString</key>
+ <string>0.9.1</string>
+</dict>
+</plist>
diff --git a/src/app/app.pro b/src/app/app.pro
new file mode 100644
index 0000000000..67bb37e4ef
--- /dev/null
+++ b/src/app/app.pro
@@ -0,0 +1,82 @@
+IDE_BUILD_TREE = $$OUT_PWD/../../
+
+include(../qworkbench.pri)
+include(../../shared/qtsingleapplication/qtsingleapplication.pri)
+
+macx {
+ CONFIG(debug, debug|release):LIBS *= -lExtensionSystem_debug -lAggregation_debug
+ else:LIBS *= -lExtensionSystem -lAggregation
+}
+win32 {
+ CONFIG(debug, debug|release):LIBS *= -lExtensionSystemd -lAggregationd
+ else:LIBS *= -lExtensionSystem -lAggregation
+}
+linux-* {
+ LIBS *= -lExtensionSystem -lAggregation
+}
+
+TEMPLATE = app
+TARGET = $$IDE_APP_TARGET
+DESTDIR = ../../bin
+
+SOURCES += main.cpp
+
+macx {
+ SNIPPETS.path = Contents/Resources
+ SNIPPETS.files = $$IDE_SOURCE_TREE/bin/snippets
+ TEMPLATES.path = Contents/Resources
+ TEMPLATES.files = $$IDE_SOURCE_TREE/bin/templates
+ DESIGNER.path = Contents/Resources
+ DESIGNER.files = $$IDE_SOURCE_TREE/bin/designer
+ SCHEMES.path = Contents/Resources
+ SCHEMES.files = $$IDE_SOURCE_TREE/bin/schemes
+ GDBDEBUGGER.path = Contents/Resources
+ GDBDEBUGGER.files = $$IDE_SOURCE_TREE/bin/gdbmacros
+ DOC.path = Contents/Resources/doc
+ DOC.files = $$IDE_SOURCE_TREE/doc/qtcreator.qch
+ LICENSE.path = Contents/Resources
+ LICENSE.files = $$IDE_SOURCE_TREE/bin/license.txt
+ RUNINTERMINAL.path = Contents/Resources
+ RUNINTERMINAL.files = $$IDE_SOURCE_TREE/bin/runInTerminal.command
+ QMAKE_BUNDLE_DATA += SNIPPETS TEMPLATES DESIGNER SCHEMES GDBDEBUGGER DOC LICENSE RUNINTERMINAL
+ QMAKE_INFO_PLIST = $$PWD/Info.plist
+}
+!macx {
+ # make sure the resources are in place
+ !exists($$OUT_PWD/app.pro) {
+ unix:SEPARATOR = ;
+ win32:SEPARATOR = &
+ # we are shadow build
+ COPYSRC = snippets \
+ templates \
+ designer \
+ schemes \
+ gdbmacros
+ COPYDEST = $${OUT_PWD}/../../bin
+ win32:COPYDEST ~= s|/+|\|
+ for(tmp,COPYSRC) {
+ REALSRC = $$IDE_SOURCE_TREE/bin/$$tmp
+ REALDEST = $$COPYDEST/$$tmp
+ win32:tmp ~= s|/+|\|
+ win32:REALSRC ~= s|/+|\|
+ win32:REALDEST ~= s|/+|\|
+ QMAKE_POST_LINK += $${QMAKE_COPY_DIR} $${REALSRC} $${REALDEST} $$SEPARATOR
+ }
+ }
+}
+
+linux-* {
+ #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ QMAKE_RPATHDIR += \$\$ORIGIN/../lib
+ IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":")
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\'
+ QMAKE_RPATHDIR =
+}
+
+win32 {
+ RC_FILE = qtcreator.rc
+}
+
+macx {
+ ICON = qtcreator.icns
+}
diff --git a/src/app/main.cpp b/src/app/main.cpp
new file mode 100644
index 0000000000..0247b1dde3
--- /dev/null
+++ b/src/app/main.cpp
@@ -0,0 +1,285 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtsingleapplication.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginspec.h>
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+
+#ifdef Q_OS_DARWIN
+# include <sys/resource.h>
+#endif
+
+enum { OptionIndent =4, DescriptionIndent = 24 };
+
+static const char *appNameC = "Qt Creator";
+static const char *corePluginNameC = "Core";
+static const char *fixedOptionsC =
+" [OPTION]... [FILE]...\n"
+"Options:\n"
+" -help Display this help\n"
+" -version Display program version\n"
+" -client Attempt to connect to already running instance\n";
+
+static const char *HELP_OPTION1 = "-h";
+static const char *HELP_OPTION2 = "-help";
+static const char *HELP_OPTION3 = "/h";
+static const char *HELP_OPTION4 = "--help";
+static const char *VERSION_OPTION = "-version";
+static const char *CLIENT_OPTION = "-client";
+
+typedef QSet<ExtensionSystem::PluginSpec *> PluginSpecSet;
+
+// Helpers for displaying messages. Note that there is no console on Windows.
+#ifdef Q_WS_WIN
+// Format as <pre> HTML
+static inline void toHtml(QString &t)
+{
+ t.replace(QLatin1Char('&'), QLatin1String("&amp;"));
+ t.replace(QLatin1Char('<'), QLatin1String("&lt;"));
+ t.replace(QLatin1Char('>'), QLatin1String("&gt;"));
+ t.insert(0, QLatin1String("<html><pre>"));
+ t.append(QLatin1String("</pre></html>"));
+}
+
+static void displayHelpText(QString t) // No console on Windows.
+{
+ toHtml(t);
+ QMessageBox::information(0, QLatin1String(appNameC), t);
+}
+
+static void displayError(const QString &t) // No console on Windows.
+{
+ QMessageBox::critical(0, QLatin1String(appNameC), t);
+}
+
+#else
+
+static void displayHelpText(const QString &t)
+{
+ qWarning(t.toUtf8().constData());
+}
+
+static void displayError(const QString &t)
+{
+ qCritical(t.toUtf8().constData());
+}
+
+#endif
+
+static void printVersion(const ExtensionSystem::PluginSpec *coreplugin,
+ const ExtensionSystem::PluginManager &pm)
+{
+ QString version;
+ QTextStream str(&version);
+ str << '\n' << appNameC << ' ' << coreplugin->version()<< " based on Qt " << qVersion() << "\n\n";
+ pm.formatPluginVersions(str);
+ str << '\n' << coreplugin->copyright() << '\n';
+ displayHelpText(version);
+}
+
+static void printHelp(const QString &a0, const ExtensionSystem::PluginManager &pm)
+{
+ QString help;
+ QTextStream str(&help);
+ str << "Usage: " << a0 << fixedOptionsC;
+ ExtensionSystem::PluginManager::formatOptions(str, OptionIndent, DescriptionIndent);
+ pm.formatPluginOptions(str, OptionIndent, DescriptionIndent);
+ displayHelpText(help);
+}
+
+static inline QString msgCoreLoadFailure(const QString &why)
+{
+ return QCoreApplication::translate("Application", "Failed to load core: %1").arg(why);
+}
+
+static inline QString msgSendArgumentFailed()
+{
+ return QCoreApplication::translate("Application", "Unable to send command line arguments to the already running instance. It appears to be not responding.");
+}
+
+// Prepare a remote argument: If it is a relative file, add the current directory
+// since the the central instance might be running in a different directory.
+
+static inline QString prepareRemoteArgument(const QString &a)
+{
+ QFileInfo fi(a);
+ if (!fi.exists())
+ return a;
+ if (fi.isRelative())
+ return fi.absoluteFilePath();
+ return a;
+}
+
+// Send the arguments to an already running instance of Qt Creator
+static bool sendArguments(SharedTools::QtSingleApplication &app, const QStringList &arguments)
+{
+ if (!arguments.empty()) {
+ // Send off arguments
+ const QStringList::const_iterator acend = arguments.constEnd();
+ for (QStringList::const_iterator it = arguments.constBegin(); it != acend; ++it) {
+ if (!app.sendMessage(prepareRemoteArgument(*it))) {
+ displayError(msgSendArgumentFailed());
+ return false;
+ }
+ }
+ }
+ // Special empty argument means: Show and raise (the slot just needs to be triggered)
+ if (!app.sendMessage(QString())) {
+ displayError(msgSendArgumentFailed());
+ return false;
+ }
+ return true;
+}
+
+static inline QStringList getPluginPaths()
+{
+ QStringList rc;
+ // Figure out root: Up one from 'bin'
+ QDir rootDir = QApplication::applicationDirPath();
+ rootDir.cdUp();
+ const QString rootDirPath = rootDir.canonicalPath();
+ // 1) "lib" dir
+ QString pluginPath = rootDirPath;
+ pluginPath += QDir::separator();
+ pluginPath += QLatin1String("lib");
+ rc.push_back(pluginPath);
+ // 2) "PlugIns"
+ pluginPath = rootDirPath;
+ pluginPath += QDir::separator();
+ pluginPath += QLatin1String("PlugIns");
+ rc.push_back(pluginPath);
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+#ifdef Q_OS_DARWIN
+ // increase the number of file that can be opened in Qt Creator.
+ struct rlimit rl;
+ getrlimit(RLIMIT_NOFILE, &rl);
+ rl.rlim_cur = rl.rlim_max;
+ setrlimit(RLIMIT_NOFILE, &rl);
+#endif
+
+ SharedTools::QtSingleApplication app((QLatin1String(appNameC)), argc, argv);
+ // Load
+ ExtensionSystem::PluginManager pluginManager;
+ pluginManager.setFileExtension(QLatin1String("pluginspec"));
+
+ const QStringList pluginPaths = getPluginPaths();
+ pluginManager.setPluginPaths(pluginPaths);
+
+ const QStringList arguments = app.arguments();
+ QMap<QString,QString> foundAppOptions;
+ if (arguments.size() > 1) {
+ QMap<QString,bool> appOptions;
+ appOptions.insert(QLatin1String(HELP_OPTION1), false);
+ appOptions.insert(QLatin1String(HELP_OPTION2), false);
+ appOptions.insert(QLatin1String(HELP_OPTION3), false);
+ appOptions.insert(QLatin1String(HELP_OPTION4), false);
+ appOptions.insert(QLatin1String(VERSION_OPTION), false);
+ appOptions.insert(QLatin1String(CLIENT_OPTION), false);
+ QString errorMessage;
+ if (!pluginManager.parseOptions(arguments,
+ appOptions,
+ &foundAppOptions,
+ &errorMessage)) {
+ displayError(errorMessage);
+ printHelp(QFileInfo(app.applicationFilePath()).baseName(), pluginManager);
+ return -1;
+ }
+ }
+
+ const PluginSpecSet plugins = pluginManager.plugins();
+ ExtensionSystem::PluginSpec *coreplugin = 0;
+ foreach (ExtensionSystem::PluginSpec *spec, plugins) {
+ if (spec->name() == QLatin1String(corePluginNameC)) {
+ coreplugin = spec;
+ break;
+ }
+ }
+ if (!coreplugin) {
+ const QString reason = QCoreApplication::translate("Application", "Couldn't find 'Core.pluginspec' in %1").arg(pluginPaths.join(QLatin1String(",")));
+ displayError(msgCoreLoadFailure(reason));
+ return 1;
+ }
+ if (coreplugin->hasError()) {
+ displayError(msgCoreLoadFailure(coreplugin->errorString()));
+ return 1;
+ }
+ if (foundAppOptions.contains(QLatin1String(VERSION_OPTION))) {
+ printVersion(coreplugin, pluginManager);
+ return 0;
+ }
+ if (foundAppOptions.contains(QLatin1String(HELP_OPTION1))
+ || foundAppOptions.contains(QLatin1String(HELP_OPTION2))
+ || foundAppOptions.contains(QLatin1String(HELP_OPTION3))
+ || foundAppOptions.contains(QLatin1String(HELP_OPTION4))) {
+ printHelp(QFileInfo(app.applicationFilePath()).baseName(), pluginManager);
+ return 0;
+ }
+
+ const bool isFirstInstance = !app.isRunning();
+ if (!isFirstInstance && foundAppOptions.contains(QLatin1String(CLIENT_OPTION)))
+ return sendArguments(app, pluginManager.arguments()) ? 0 : -1;
+
+ pluginManager.loadPlugins();
+ if (coreplugin->hasError()) {
+ displayError(msgCoreLoadFailure(coreplugin->errorString()));
+ return 1;
+ }
+ if (isFirstInstance) {
+ // Set up lock and remote arguments for the first instance only.
+ // Silently fallback to unconnected instances for any subsequent
+ // instances.
+ app.initialize();
+ QObject::connect(&app, SIGNAL(messageReceived(QString)), coreplugin->plugin(), SLOT(remoteArgument(QString)));
+ }
+ QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(remoteArgument(QString)));
+
+ // Do this after the event loop has started
+ QTimer::singleShot(100, &pluginManager, SLOT(startTests()));
+ return app.exec();
+}
diff --git a/src/app/qtcreator.icns b/src/app/qtcreator.icns
new file mode 100644
index 0000000000..9d309e683e
--- /dev/null
+++ b/src/app/qtcreator.icns
Binary files differ
diff --git a/src/app/qtcreator.ico b/src/app/qtcreator.ico
new file mode 100644
index 0000000000..4aaeed0873
--- /dev/null
+++ b/src/app/qtcreator.ico
Binary files differ
diff --git a/src/app/qtcreator.rc b/src/app/qtcreator.rc
new file mode 100644
index 0000000000..5f337b2c57
--- /dev/null
+++ b/src/app/qtcreator.rc
@@ -0,0 +1 @@
+ IDI_ICON1 ICON DISCARDABLE "qtcreator.ico"
diff --git a/src/libs/aggregation/aggregate.cpp b/src/libs/aggregation/aggregate.cpp
new file mode 100644
index 0000000000..bfd9e0f4dc
--- /dev/null
+++ b/src/libs/aggregation/aggregate.cpp
@@ -0,0 +1,265 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "aggregate.h"
+
+#include <QtCore/QWriteLocker>
+
+/*!
+ \namespace Aggregation
+ \brief Contains support for bundling related components, such that
+ each component exposes the properties and behavior of the
+ other components to the outside.
+
+ Components that are bundled to an Aggregate can be "cast" to each other
+ and have a coupled life cycle. See the documentation of Aggregate for
+ details and examples.
+*/
+
+/*!
+ \class Aggregation::Aggregate
+ \mainclass
+ \threadsafe
+
+ \brief Defines a collection of related components that can be viewed as a unit.
+
+ An Aggregate is a collection of components that are handled as a unit,
+ such that each component exposes the properties and behavior of the
+ other components in the Aggregate to the outside.
+ Specifically that means:
+ \list
+ \o They can be "cast" to each other (using query and query_all methods).
+ \o Their life cycle is coupled, i.e. whenever one is deleted all of them are.
+ \endlist
+ Components can be of any QObject derived type.
+
+ You can use an Aggregate to simulate multiple inheritance by aggregation. Assume we have
+ \code
+ using namespace Aggregation;
+ class MyInterface : public QObject { ........ };
+ class MyInterfaceEx : public QObject { ........ };
+ [...]
+ MyInterface *object = new MyInterface; // this is single inheritance
+ \endcode
+ The query method works like a qobject_cast with normal objects:
+ \code
+ Q_ASSERT(query<MyInterface>(object) == object);
+ Q_ASSERT(query<MyInterfaceEx>(object) == 0);
+ \endcode
+ If we want 'object' to also implement the class MyInterfaceEx,
+ but don't want to or cannot use multiple inheritance, we can do it
+ at any point using an Aggregate:
+ \code
+ MyInterfaceEx *objectEx = new MyInterfaceEx;
+ Aggregate *aggregate = new Aggregate;
+ aggregate->add(object);
+ aggregate->add(objectEx);
+ \endcode
+ The Aggregate bundles the two objects together.
+ If we have any part of the collection we get all parts:
+ \code
+ Q_ASSERT(query<MyInterface>(object) == object);
+ Q_ASSERT(query<MyInterfaceEx>(object) == objectEx);
+ Q_ASSERT(query<MyInterface>(objectEx) == object);
+ Q_ASSERT(query<MyInterfaceEx>(objectEx) == objectEx);
+ \endcode
+ The following deletes all three: object, objectEx and aggregate:
+ \code
+ delete objectEx;
+ // or delete object;
+ // or delete aggregate;
+ \endcode
+
+ Aggregation aware code never uses qobject_cast, but always uses
+ Aggregation::query which behaves like a qobject_cast as a fallback.
+*/
+
+/*!
+ \fn T *Aggregate::component()
+
+ Template method that returns the component with the given type, if there is one.
+ If there are multiple components with that type a random one is returned.
+
+ \sa Aggregate::components()
+ \sa Aggregate::add()
+*/
+
+/*!
+ \fn QList<T *> Aggregate::components()
+
+ Template method that returns all components with the given type, if there are any.
+
+ \sa Aggregate::component()
+ \sa Aggregate::add()
+*/
+
+/*!
+ \fn T *Aggregation::query<T *>(Aggregate *obj)
+ \internal
+*/
+
+/*!
+ \fn QList<T *> Aggregation::query_all<T *>(Aggregate *obj)
+ \internal
+*/
+
+/*!
+ \relates Aggregation::Aggregate
+ \fn T *Aggregation::query<T *>(QObject *obj)
+
+ Performs a dynamic cast that is aware of a possible Aggregate that \a obj
+ might belong to. If \a obj itself is of the requested type then it is simply cast
+ and returned. Otherwise, if \a obj belongs to an Aggregate all its components are
+ checked, or if it doesn't belong to an Aggregate null is returned.
+
+ \sa Aggregate::component()
+*/
+
+/*!
+ \relates Aggregation::Aggregate
+ \fn QList<T *> Aggregation::query_all<T *>(QObject *obj)
+
+ If \a obj belongs to an Aggregate, all components that can be cast to the given
+ type are returned. Otherwise, \a obj is returned if it is of the requested type.
+
+ \sa Aggregate::components()
+*/
+
+using namespace Aggregation;
+
+/*!
+ \fn Aggregate *Aggregate::parentAggregate(QObject *obj)
+
+ Returns the Aggregate object of \a obj if there is one. Otherwise returns 0.
+*/
+Aggregate *Aggregate::parentAggregate(QObject *obj)
+{
+ QReadLocker locker(&lock());
+ return aggregateMap().value(obj);
+}
+
+QHash<QObject *, Aggregate *> &Aggregate::aggregateMap()
+{
+ static QHash<QObject *, Aggregate *> map;
+ return map;
+}
+
+/*!
+ \fn QReadWriteLock &Aggregate::lock()
+ \internal
+*/
+QReadWriteLock &Aggregate::lock()
+{
+ static QReadWriteLock lock;
+ return lock;
+}
+
+/*!
+ \fn Aggregate::Aggregate(QObject *parent)
+
+ Creates a new Aggregate with the given \a parent.
+ The \a parent is passed directly passed to the QObject part
+ of the class and is not used beside that.
+*/
+Aggregate::Aggregate(QObject *parent)
+ : QObject(parent)
+{
+ QWriteLocker locker(&lock());
+ aggregateMap().insert(this, this);
+}
+
+/*!
+ \fn Aggregate::~Aggregate()
+
+ Deleting the aggregate automatically deletes all its components.
+*/
+Aggregate::~Aggregate()
+{
+ QWriteLocker locker(&lock());
+ foreach (QObject *component, m_components) {
+ disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
+ aggregateMap().remove(component);
+ }
+ qDeleteAll(m_components);
+ m_components.clear();
+ aggregateMap().remove(this);
+}
+
+void Aggregate::deleteSelf(QObject *obj)
+{
+ {
+ QWriteLocker locker(&lock());
+ aggregateMap().remove(obj);
+ m_components.removeAll(obj);
+ }
+ delete this;
+}
+
+/*!
+ \fn void Aggregate::add(QObject *component)
+
+ Adds the \a component to the aggregate.
+
+ \sa Aggregate::remove()
+*/
+void Aggregate::add(QObject *component)
+{
+ if (!component)
+ return;
+ QWriteLocker locker(&lock());
+ Aggregate *parentAggregation = aggregateMap().value(component);
+ if (parentAggregation == this)
+ return;
+ if (parentAggregation)
+ parentAggregation->remove(component);
+ m_components.append(component);
+ connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
+ aggregateMap().insert(component, this);
+}
+
+/*!
+ \fn void Aggregate::remove(QObject *component)
+
+ Removes the \a component from the aggregate.
+
+ \sa Aggregate::add()
+*/
+void Aggregate::remove(QObject *component)
+{
+ if (!component)
+ return;
+ QWriteLocker locker(&lock());
+ aggregateMap().remove(component);
+ m_components.removeAll(component);
+ disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
+}
+
diff --git a/src/libs/aggregation/aggregate.h b/src/libs/aggregation/aggregate.h
new file mode 100644
index 0000000000..5040aec8b2
--- /dev/null
+++ b/src/libs/aggregation/aggregate.h
@@ -0,0 +1,134 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QAGGREGATION_H
+#define QAGGREGATION_H
+
+#include "aggregation_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QReadWriteLock>
+#include <QtCore/QReadLocker>
+
+namespace Aggregation {
+
+class AGGREGATION_EXPORT Aggregate : public QObject
+{
+ Q_OBJECT
+
+public:
+ Aggregate(QObject *parent = 0);
+ virtual ~Aggregate();
+
+ void add(QObject *component);
+ void remove(QObject *component);
+
+ template <typename T> T *component() {
+ QReadLocker(&lock());
+ foreach (QObject *component, m_components) {
+ if (T *result = qobject_cast<T *>(component))
+ return result;
+ }
+ return (T *)0;
+ }
+
+ template <typename T> QList<T *> components() {
+ QReadLocker(&lock());
+ QList<T *> results;
+ foreach (QObject *component, m_components) {
+ if (T *result = qobject_cast<T *>(component)) {
+ results << result;
+ }
+ }
+ return results;
+ }
+
+ static Aggregate *parentAggregate(QObject *obj);
+ static QReadWriteLock &lock();
+
+private slots:
+ void deleteSelf(QObject *obj);
+
+private:
+ static QHash<QObject *, Aggregate *> &aggregateMap();
+
+ QList<QObject *> m_components;
+};
+
+// get a component via global template function
+template <typename T> T *query(Aggregate *obj)
+{
+ if (!obj)
+ return (T *)0;
+ return obj->template component<T>();
+}
+
+template <typename T> T *query(QObject *obj)
+{
+ if (!obj)
+ return (T *)0;
+ T *result = qobject_cast<T *>(obj);
+ if (!result) {
+ QReadLocker(&lock());
+ Aggregate *parentAggregation = Aggregate::parentAggregate(obj);
+ result = (parentAggregation ? query<T>(parentAggregation) : 0);
+ }
+ return result;
+}
+
+// get all components of a specific type via template function
+template <typename T> QList<T *> query_all(Aggregate *obj)
+{
+ if (!obj)
+ return QList<T *>();
+ return obj->template components<T>();
+}
+
+template <typename T> QList<T *> query_all(QObject *obj)
+{
+ if (!obj)
+ return QList<T *>();
+ QReadLocker(&lock());
+ Aggregate *parentAggregation = Aggregate::parentAggregate(obj);
+ QList<T *> results;
+ if (parentAggregation)
+ results = query_all<T>(parentAggregation);
+ else if (T *result = qobject_cast<T *>(obj))
+ results.append(result);
+ return results;
+}
+
+} // namespace Aggregation
+
+#endif // header guard
diff --git a/src/libs/aggregation/aggregation.pri b/src/libs/aggregation/aggregation.pri
new file mode 100644
index 0000000000..a6c48c59cb
--- /dev/null
+++ b/src/libs/aggregation/aggregation.pri
@@ -0,0 +1 @@
+LIBS *= -l$$qtLibraryTarget(Aggregation)
diff --git a/src/libs/aggregation/aggregation.pro b/src/libs/aggregation/aggregation.pro
new file mode 100644
index 0000000000..c970be0ed1
--- /dev/null
+++ b/src/libs/aggregation/aggregation.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+TARGET = Aggregation
+
+include(../../qworkbenchlibrary.pri)
+
+DEFINES += AGGREGATION_LIBRARY
+
+HEADERS = aggregate.h \
+ aggregation_global.h
+
+SOURCES = aggregate.cpp
+
diff --git a/src/libs/aggregation/aggregation_global.h b/src/libs/aggregation/aggregation_global.h
new file mode 100644
index 0000000000..cae0917d65
--- /dev/null
+++ b/src/libs/aggregation/aggregation_global.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef AGGREGATION_GLOBAL_H
+#define AGGREGATION_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(AGGREGATION_LIBRARY)
+# define AGGREGATION_EXPORT Q_DECL_EXPORT
+#else
+# define AGGREGATION_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // header
diff --git a/src/libs/aggregation/examples/examples.pro b/src/libs/aggregation/examples/examples.pro
new file mode 100644
index 0000000000..7389255366
--- /dev/null
+++ b/src/libs/aggregation/examples/examples.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS = text
diff --git a/src/libs/aggregation/examples/text/main.cpp b/src/libs/aggregation/examples/text/main.cpp
new file mode 100644
index 0000000000..1a0ecac816
--- /dev/null
+++ b/src/libs/aggregation/examples/text/main.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "main.h"
+
+#include <QtGui/QApplication>
+
+MyMain::MyMain(QWidget *parent, Qt::WFlags flags)
+ : QWidget(parent, flags)
+{
+ ui.setupUi(this);
+ connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(select(int)));
+}
+
+void MyMain::add(IComboEntry *obj)
+{
+ m_entries.append(obj);
+ ui.comboBox->addItem(obj->title());
+}
+
+void MyMain::select(int index)
+{
+ IComboEntry *entry = m_entries.at(index);
+ // with multiple inheritance we would use qobject_cast here
+ // instead we use query, to get the components if they exist
+ IText1 *t1 = Aggregation::query<IText1>(entry);
+ IText2 *t2 = Aggregation::query<IText2>(entry);
+ IText3 *t3 = Aggregation::query<IText3>(entry);
+ // set the label texts and enable/disable, depending on whether
+ // the respective interface implementations exist
+ ui.text1->setText(t1 ? t1->text() : tr("N/A"));
+ ui.text2->setText(t2 ? t2->text() : tr("N/A"));
+ ui.text3->setText(t3 ? t3->text() : tr("N/A"));
+ ui.text1->setEnabled(t1);
+ ui.text2->setEnabled(t2);
+ ui.text3->setEnabled(t3);
+}
+
+MyMain::~MyMain()
+{
+ // the following deletes all the Aggregate and IComboEntry and ITextX
+ // objects, as well as any other components we might have added
+ qDeleteAll(m_entries);
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MyMain w;
+ // create and set up some objects
+
+ // the first does only implement the required IComboEntry
+ // we don't need an aggregation for this
+ IComboEntry *obj1 = new IComboEntry("Entry without text");
+
+ // the second additionally provides an IText2 implementation
+ // adding a component to the aggregation is done by setting the aggregation as the parent of the component
+ Aggregation::Aggregate *obj2 = new Aggregation::Aggregate;
+ obj2->add(new IComboEntry("Entry with text 2"));
+ obj2->add(new IText2("This is a text for label 2"));
+
+ // and so on... two more objects...
+ Aggregation::Aggregate *obj3 = new Aggregation::Aggregate;
+ obj3->add(new IComboEntry("Entry with text 1 and 2"));
+ obj3->add(new IText1("I love Qt!"));
+ obj3->add(new IText2("There are software companies..."));
+ Aggregation::Aggregate *obj4 = new Aggregation::Aggregate;
+ obj4->add(new IComboEntry("Entry with text 1 and 3"));
+ obj4->add(new IText1("Some text written here."));
+ obj4->add(new IText3("I'm a troll."));
+
+ // the API takes IComboEntries, so we convert the them to it
+ // the MyMain object takes the ownership of the whole aggregations
+ w.add(Aggregation::query<IComboEntry>(obj1));
+ w.add(Aggregation::query<IComboEntry>(obj2));
+ w.add(Aggregation::query<IComboEntry>(obj3));
+ w.add(Aggregation::query<IComboEntry>(obj4));
+ w.show();
+ return app.exec();
+}
+
diff --git a/src/libs/aggregation/examples/text/main.h b/src/libs/aggregation/examples/text/main.h
new file mode 100644
index 0000000000..3a458923b4
--- /dev/null
+++ b/src/libs/aggregation/examples/text/main.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MAIN_H
+#define MAIN_H
+
+#include "myinterfaces.h"
+
+#include <aggregate.h>
+
+#include <QtGui/QWidget>
+#include "ui_main.h"
+
+class MyMain : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MyMain(QWidget *parent = 0, Qt::WFlags flags = 0);
+ ~MyMain();
+
+ void add(IComboEntry *obj);
+
+private slots:
+ void select(int index);
+
+private:
+ Ui::mainClass ui;
+
+ QList<IComboEntry *> m_entries;
+};
+
+#endif // MAIN_H
diff --git a/src/libs/aggregation/examples/text/main.ui b/src/libs/aggregation/examples/text/main.ui
new file mode 100644
index 0000000000..32d39511ee
--- /dev/null
+++ b/src/libs/aggregation/examples/text/main.ui
@@ -0,0 +1,128 @@
+<ui version="4.0" >
+ <class>mainClass</class>
+ <widget class="QWidget" name="mainClass" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>176</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>main</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QComboBox" name="comboBox" />
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Text1:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="text1" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Text2:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="text2" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Text3:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="text3" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/aggregation/examples/text/myinterfaces.h b/src/libs/aggregation/examples/text/myinterfaces.h
new file mode 100644
index 0000000000..62dad429e2
--- /dev/null
+++ b/src/libs/aggregation/examples/text/myinterfaces.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MYINTERFACES_H
+#define MYINTERFACES_H
+
+#include <aggregate.h>
+
+#include <QtCore/QString>
+
+class IComboEntry : public QObject
+{
+ Q_OBJECT
+
+public:
+ IComboEntry(QString title) : m_title(title) {}
+ virtual ~IComboEntry() {}
+ QString title() const { return m_title; }
+private:
+ QString m_title;
+};
+
+class IText1 : public QObject
+{
+ Q_OBJECT
+
+public:
+ IText1(QString text) : m_text(text) {}
+ virtual ~IText1() {}
+ QString text() const { return m_text; }
+private:
+ QString m_text;
+};
+
+class IText2 : public QObject
+{
+ Q_OBJECT
+
+public:
+ IText2(QString text) : m_text(text) {}
+ QString text() const { return m_text; }
+private:
+ QString m_text;
+};
+
+class IText3 : public QObject
+{
+ Q_OBJECT
+
+public:
+ IText3(QString text) : m_text(text) {}
+ virtual ~IText3() {}
+ QString text() const { return m_text; }
+private:
+ QString m_text;
+};
+
+#endif // MYINTERFACES_H
diff --git a/src/libs/aggregation/examples/text/text.pro b/src/libs/aggregation/examples/text/text.pro
new file mode 100644
index 0000000000..3893c5e95f
--- /dev/null
+++ b/src/libs/aggregation/examples/text/text.pro
@@ -0,0 +1,14 @@
+TARGET = text
+TEMPLATE = app
+QT += core \
+ gui
+DEFINES += AGGREGATION_LIBRARY
+INCLUDEPATH += ../../
+SOURCES += main.cpp \
+ ../../aggregate.cpp
+HEADERS += main.h \
+ myinterfaces.h \
+ ../../aggregate.h \
+ ../../aggregation_global.h
+FORMS += main.ui
+
diff --git a/src/libs/aggregation/test/test.pro b/src/libs/aggregation/test/test.pro
new file mode 100644
index 0000000000..6143ca9805
--- /dev/null
+++ b/src/libs/aggregation/test/test.pro
@@ -0,0 +1,12 @@
+CONFIG += qtestlib
+TEMPLATE = app
+CONFIG -= app_bundle
+DEFINES += AGGREGATION_LIBRARY
+
+INCLUDEPATH += ../
+# Input
+SOURCES += tst_aggregate.cpp \
+ ../aggregate.cpp
+HEADERS += ../aggregate.h \
+ ../aggregation_global.h
+
diff --git a/src/libs/aggregation/test/tst_aggregate.cpp b/src/libs/aggregation/test/tst_aggregate.cpp
new file mode 100644
index 0000000000..098cc723af
--- /dev/null
+++ b/src/libs/aggregation/test/tst_aggregate.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtTest/QtTest>
+
+#include <aggregate.h>
+
+class tst_Aggregate : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void deleteAggregation();
+ void queryAggregation();
+ void queryAll();
+ void parentAggregate();
+};
+
+class Interface1 : public QObject
+{
+ Q_OBJECT
+};
+
+class Interface11 : public Interface1
+{
+ Q_OBJECT
+};
+
+class Interface2 : public QObject
+{
+ Q_OBJECT
+};
+
+class Interface3 : public QObject
+{
+ Q_OBJECT
+};
+
+void tst_Aggregate::deleteAggregation()
+{
+ QPointer<Aggregation::Aggregate> aggregation;
+ QPointer<QObject> component1;
+ QPointer<QObject> component2;
+
+ aggregation = new Aggregation::Aggregate;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ aggregation->add(component1);
+ aggregation->add(component2);
+ delete aggregation;
+ QVERIFY(aggregation == 0);
+ QVERIFY(component1 == 0);
+ QVERIFY(component2 == 0);
+
+ aggregation = new Aggregation::Aggregate;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ aggregation->add(component1);
+ aggregation->add(component2);
+ delete component1;
+ QVERIFY(aggregation == 0);
+ QVERIFY(component1 == 0);
+ QVERIFY(component2 == 0);
+
+ aggregation = new Aggregation::Aggregate;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ aggregation->add(component1);
+ aggregation->add(component2);
+ delete component2;
+ QVERIFY(aggregation == 0);
+ QVERIFY(component1 == 0);
+ QVERIFY(component2 == 0);
+
+ // if a component doesn't belong to an aggregation, it should simply delete itself
+ component1 = new Interface1;
+ delete component1;
+ QVERIFY(component1 == 0);
+}
+
+void tst_Aggregate::queryAggregation()
+{
+ Aggregation::Aggregate aggregation;
+ QObject *aggObject = &aggregation;
+ QObject *component1 = new Interface11;
+ QObject *component2 = new Interface2;
+ aggregation.add(component1);
+ aggregation.add(component2);
+ QCOMPARE(Aggregation::query<Interface1>(&aggregation), component1);
+ QCOMPARE(Aggregation::query<Interface2>(&aggregation), component2);
+ QCOMPARE(Aggregation::query<Interface11>(&aggregation), component1);
+ QCOMPARE(Aggregation::query<Interface3>(&aggregation), (Interface3 *)0);
+
+ QCOMPARE(Aggregation::query<Interface1>(aggObject), component1);
+ QCOMPARE(Aggregation::query<Interface2>(aggObject), component2);
+ QCOMPARE(Aggregation::query<Interface11>(aggObject), component1);
+ QCOMPARE(Aggregation::query<Interface3>(aggObject), (Interface3 *)0);
+
+ QCOMPARE(Aggregation::query<Interface1>(component1), component1);
+ QCOMPARE(Aggregation::query<Interface2>(component1), component2);
+ QCOMPARE(Aggregation::query<Interface11>(component1), component1);
+ QCOMPARE(Aggregation::query<Interface3>(component1), (Interface3 *)0);
+
+ QCOMPARE(Aggregation::query<Interface1>(component2), component1);
+ QCOMPARE(Aggregation::query<Interface2>(component2), component2);
+ QCOMPARE(Aggregation::query<Interface11>(component2), component1);
+ QCOMPARE(Aggregation::query<Interface3>(component2), (Interface3 *)0);
+
+ // components that don't belong to an aggregation should be query-able to itself only
+ QObject *component3 = new Interface3;
+ QCOMPARE(Aggregation::query<Interface1>(component3), (Interface1 *)0);
+ QCOMPARE(Aggregation::query<Interface2>(component3), (Interface2 *)0);
+ QCOMPARE(Aggregation::query<Interface11>(component3), (Interface11 *)0);
+ QCOMPARE(Aggregation::query<Interface3>(component3), component3);
+ delete component3;
+}
+
+void tst_Aggregate::queryAll()
+{
+ Aggregation::Aggregate aggregation;
+ QObject *aggObject = &aggregation;
+ Interface1 *component1 = new Interface1;
+ Interface11 *component11 = new Interface11;
+ Interface2 *component2 = new Interface2;
+ aggregation.add(component1);
+ aggregation.add(component11);
+ aggregation.add(component2);
+ QCOMPARE(Aggregation::query_all<Interface1>(&aggregation), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(&aggregation), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(&aggregation), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(&aggregation), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(aggObject), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(aggObject), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(aggObject), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(aggObject), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(component1), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(component1), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(component1), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(component1), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(component11), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(component11), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(component11), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(component11), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(component2), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(component2), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(component2), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(component2), QList<Interface3 *>());
+}
+
+void tst_Aggregate::parentAggregate()
+{
+ Aggregation::Aggregate aggregation;
+ Interface1 *component1 = new Interface1;
+ Interface11 *component11 = new Interface11;
+ QObject *component2 = new QObject;
+ aggregation.add(component1);
+ aggregation.add(component11);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(&aggregation), &aggregation);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(component1), &aggregation);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(component11), &aggregation);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(component2), (Aggregation::Aggregate *)0);
+}
+
+QTEST_MAIN(tst_Aggregate)
+#include "tst_aggregate.moc"
diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp
new file mode 100644
index 0000000000..b2e0ca4be1
--- /dev/null
+++ b/src/libs/cplusplus/CppDocument.cpp
@@ -0,0 +1,242 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "CppDocument.h"
+#include <Control.h>
+#include <TranslationUnit.h>
+#include <DiagnosticClient.h>
+#include <Semantic.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <AST.h>
+#include <Scope.h>
+#include <QByteArray>
+#include <QFile>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+namespace {
+ class DocumentDiagnosticClient: public DiagnosticClient
+ {
+ enum { MAX_MESSAGE_COUNT = 10 };
+
+ public:
+ DocumentDiagnosticClient(Document *doc, QList<Document::DiagnosticMessage> *messages)
+ : doc(doc),
+ messages(messages)
+ { }
+
+ virtual void report(int level,
+ StringLiteral *fileId,
+ unsigned line, unsigned column,
+ const char *format, va_list ap)
+ {
+ if (messages->count() == MAX_MESSAGE_COUNT)
+ return;
+
+ const QString fileName = QString::fromUtf8(fileId->chars(), fileId->size());
+
+ if (fileName != doc->fileName())
+ return;
+
+ QString message;
+ message.vsprintf(format, ap);
+
+ Document::DiagnosticMessage m(convertLevel(level), doc->fileName(),
+ line, column, message);
+ messages->append(m);
+ }
+
+ static int convertLevel(int level) {
+ switch (level) {
+ case Warning: return Document::DiagnosticMessage::Warning;
+ case Error: return Document::DiagnosticMessage::Error;
+ case Fatal: return Document::DiagnosticMessage::Fatal;
+ default: return Document::DiagnosticMessage::Error;
+ }
+ }
+
+ Document *doc;
+ QList<Document::DiagnosticMessage> *messages;
+ };
+} // end of anonymous namespace
+
+Document::Document(const QString &fileName)
+ : _fileName(fileName),
+ _globalNamespace(0)
+{
+ _control = new Control();
+
+ _control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages));
+
+ const QByteArray localFileName = fileName.toUtf8();
+ StringLiteral *fileId = _control->findOrInsertFileName(localFileName.constData(),
+ localFileName.size());
+ _translationUnit = new TranslationUnit(_control, fileId);
+ _translationUnit->setQtMocRunEnabled(true);
+ (void) _control->switchTranslationUnit(_translationUnit);
+}
+
+Document::~Document()
+{
+ delete _translationUnit;
+ delete _control->diagnosticClient();
+ delete _control;
+}
+
+Control *Document::control() const
+{ return _control; }
+
+QString Document::fileName() const
+{ return _fileName; }
+
+QStringList Document::includedFiles() const
+{ return _includedFiles; }
+
+void Document::addIncludeFile(const QString &fileName)
+{ _includedFiles.append(fileName); }
+
+QByteArray Document::definedMacros() const
+{ return _definedMacros; }
+
+void Document::appendMacro(const QByteArray &macroName, const QByteArray &text)
+{
+ int index = macroName.indexOf('(');
+ if (index == -1)
+ _macroNames.insert(macroName);
+ else
+ _macroNames.insert(macroName.left(index));
+ _definedMacros += text;
+}
+
+TranslationUnit *Document::translationUnit() const
+{ return _translationUnit; }
+
+bool Document::skipFunctionBody() const
+{ return _translationUnit->skipFunctionBody(); }
+
+void Document::setSkipFunctionBody(bool skipFunctionBody)
+{ _translationUnit->setSkipFunctionBody(skipFunctionBody); }
+
+unsigned Document::globalSymbolCount() const
+{
+ if (! _globalNamespace)
+ return 0;
+
+ return _globalNamespace->memberCount();
+}
+
+Symbol *Document::globalSymbolAt(unsigned index) const
+{ return _globalNamespace->memberAt(index); }
+
+Scope *Document::globalSymbols() const
+{
+ if (! _globalNamespace)
+ return 0;
+
+ return _globalNamespace->members();
+}
+
+Namespace *Document::globalNamespace() const
+{ return _globalNamespace; }
+
+Symbol *Document::findSymbolAt(unsigned line, unsigned column) const
+{ return findSymbolAt(line, column, globalSymbols()); }
+
+Symbol *Document::findSymbolAt(unsigned line, unsigned column, Scope *scope) const
+{
+ Symbol *previousSymbol = 0;
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+ if (symbol->line() > line)
+ break;
+
+ previousSymbol = symbol;
+ }
+
+ if (previousSymbol) {
+ if (ScopedSymbol *scoped = previousSymbol->asScopedSymbol()) {
+ if (Symbol *member = findSymbolAt(line, column, scoped->members()))
+ return member;
+ }
+ }
+
+ return previousSymbol;
+}
+
+Document::Ptr Document::create(const QString &fileName)
+{
+ Document::Ptr doc(new Document(fileName));
+ return doc;
+}
+
+void Document::setSource(const QByteArray &source)
+{ _translationUnit->setSource(source.constBegin(), source.size()); }
+
+void Document::startSkippingBlocks(unsigned start)
+{ _skippedBlocks.append(Block(start, 0)); }
+
+void Document::stopSkippingBlocks(unsigned stop)
+{
+ unsigned start = _skippedBlocks.back().begin();
+ if (start > stop)
+ _skippedBlocks.removeLast(); // Ignore this block, it's invalid.
+ else
+ _skippedBlocks.back() = Block(start, stop);
+}
+
+QSet<QByteArray> Document::macroNames() const
+{ return _macroNames; }
+
+void Document::parse()
+{ _translationUnit->parse(); }
+
+void Document::check()
+{
+ Q_ASSERT(! _globalNamespace);
+
+ Semantic semantic(_control);
+
+ _globalNamespace = _control->newNamespace(0);
+ Scope *globals = _globalNamespace->members();
+ if (TranslationUnitAST *ast = _translationUnit->ast()) {
+ for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) {
+ semantic.check(decl, globals);
+ }
+ }
+}
+
+void Document::releaseTranslationUnit()
+{ _translationUnit->release(); }
diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h
new file mode 100644
index 0000000000..47f2366ddd
--- /dev/null
+++ b/src/libs/cplusplus/CppDocument.h
@@ -0,0 +1,187 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPDOCUMENT_H
+#define CPPDOCUMENT_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <QByteArray>
+#include <QSharedPointer>
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QSet>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT Document
+{
+ Document(const Document &other);
+ void operator =(const Document &other);
+
+ Document(const QString &fileName);
+
+public:
+ typedef QSharedPointer<Document> Ptr;
+
+public:
+ ~Document();
+
+ QString fileName() const;
+
+ QStringList includedFiles() const;
+ void addIncludeFile(const QString &fileName);
+
+ QByteArray definedMacros() const;
+ QSet<QByteArray> macroNames() const;
+
+ void appendMacro(const QByteArray &macroName, const QByteArray &text);
+
+ Control *control() const;
+ TranslationUnit *translationUnit() const;
+
+ bool skipFunctionBody() const;
+ void setSkipFunctionBody(bool skipFunctionBody);
+
+ unsigned globalSymbolCount() const;
+ Symbol *globalSymbolAt(unsigned index) const;
+ Scope *globalSymbols() const; // ### deprecate?
+ Namespace *globalNamespace() const;
+
+ Symbol *findSymbolAt(unsigned line, unsigned column) const;
+
+ void setSource(const QByteArray &source);
+ void startSkippingBlocks(unsigned offset);
+ void stopSkippingBlocks(unsigned offset);
+
+ void parse(); // ### remove
+ void check();
+ void releaseTranslationUnit();
+
+ static Ptr create(const QString &fileName);
+
+ class DiagnosticMessage
+ {
+ public:
+ enum Level {
+ Warning,
+ Error,
+ Fatal
+ };
+
+ public:
+ DiagnosticMessage(int level, const QString &fileName,
+ int line, int column,
+ const QString &text)
+ : _level(level),
+ _fileName(fileName),
+ _line(line),
+ _column(column),
+ _text(text)
+ { }
+
+ int level() const
+ { return _level; }
+
+ bool isWarning() const
+ { return _level == Warning; }
+
+ bool isError() const
+ { return _level == Error; }
+
+ bool isFatal() const
+ { return _level == Fatal; }
+
+ QString fileName() const
+ { return _fileName; }
+
+ int line() const
+ { return _line; }
+
+ int column() const
+ { return _column; }
+
+ QString text() const
+ { return _text; }
+
+ private:
+ int _level;
+ QString _fileName;
+ int _line;
+ int _column;
+ QString _text;
+ };
+
+ void addDiagnosticMessage(const DiagnosticMessage &d)
+ { _diagnosticMessages.append(d); }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return _diagnosticMessages; }
+
+ class Block
+ {
+ unsigned _begin;
+ unsigned _end;
+
+ public:
+ inline Block(unsigned begin = 0, unsigned end = 0)
+ : _begin(begin), _end(end)
+ { }
+
+ inline unsigned begin() const
+ { return _begin; }
+
+ inline unsigned end() const
+ { return _end; }
+ };
+
+ QList<Block> skippedBlocks() const
+ { return _skippedBlocks; }
+
+private:
+ Symbol *findSymbolAt(unsigned line, unsigned column, Scope *scope) const;
+
+private:
+ QString _fileName;
+ QStringList _includedFiles;
+ Control *_control;
+ TranslationUnit *_translationUnit;
+ Namespace *_globalNamespace;
+ QList<DiagnosticMessage> _diagnosticMessages;
+ QByteArray _definedMacros;
+ QSet<QByteArray> _macroNames;
+ QList<Block> _skippedBlocks;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPPDOCUMENT_H
diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp
new file mode 100644
index 0000000000..92d2cd8893
--- /dev/null
+++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp
@@ -0,0 +1,242 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "ExpressionUnderCursor.h"
+#include "SimpleLexer.h"
+#include <Token.h>
+
+#include <QTextCursor>
+#include <QTextBlock>
+
+using namespace CPlusPlus;
+
+ExpressionUnderCursor::ExpressionUnderCursor()
+{ }
+
+ExpressionUnderCursor::~ExpressionUnderCursor()
+{ }
+
+int ExpressionUnderCursor::startOfMatchingBrace(const QList<SimpleToken> &tk, int index)
+{
+ if (tk[index - 1].is(T_RPAREN)) {
+ int i = index - 1;
+ int count = 0;
+ do {
+ if (tk[i].is(T_LPAREN)) {
+ if (! ++count)
+ return i;
+ } else if (tk[i].is(T_RPAREN))
+ --count;
+ --i;
+ } while (count != 0 && i > -1);
+ } else if (tk[index - 1].is(T_RBRACKET)) {
+ int i = index - 1;
+ int count = 0;
+ do {
+ if (tk[i].is(T_LBRACKET)) {
+ if (! ++count)
+ return i;
+ } else if (tk[i].is(T_RBRACKET))
+ --count;
+ --i;
+ } while (count != 0 && i > -1);
+ } else if (tk[index - 1].is(T_GREATER)) {
+ int i = index - 1;
+ int count = 0;
+ do {
+ if (tk[i].is(T_LESS)) {
+ if (! ++count)
+ return i;
+ } else if (tk[i].is(T_GREATER))
+ --count;
+ --i;
+ } while (count != 0 && i > -1);
+ }
+
+ return index;
+}
+
+int ExpressionUnderCursor::startOfExpression(const QList<SimpleToken> &tk, int index)
+{
+ // tk is a reference to a const QList. So, don't worry about [] access.
+ // ### TODO implement multiline support. It should be pretty easy.
+ if (tk[index - 1].isLiteral()) {
+ return index - 1;
+ } else if (tk[index - 1].is(T_THIS)) {
+ return index - 1;
+ } else if (tk[index - 1].is(T_TYPEID)) {
+ return index - 1;
+ } else if (tk[index - 1].is(T_SIGNAL)) {
+ if (tk[index - 2].is(T_COMMA) && !_jumpedComma) {
+ _jumpedComma = true;
+ return startOfExpression(tk, index - 2);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_SLOT)) {
+ if (tk[index - 2].is(T_COMMA) && !_jumpedComma) {
+ _jumpedComma = true;
+ return startOfExpression(tk, index - 2);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_IDENTIFIER)) {
+ if (tk[index - 2].is(T_TILDE)) {
+ if (tk[index - 3].is(T_COLON_COLON)) {
+ return startOfExpression(tk, index - 3);
+ } else if (tk[index - 3].is(T_DOT) || tk[index - 3].is(T_ARROW)) {
+ return startOfExpression(tk, index - 3);
+ }
+ return index - 2;
+ } else if (tk[index - 2].is(T_COLON_COLON)) {
+ return startOfExpression(tk, index - 1);
+ } else if (tk[index - 2].is(T_DOT) || tk[index - 2].is(T_ARROW)) {
+ return startOfExpression(tk, index - 2);
+ } else if (tk[index - 2].is(T_DOT_STAR) || tk[index - 2].is(T_ARROW_STAR)) {
+ return startOfExpression(tk, index - 2);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_RPAREN)) {
+ int rparenIndex = startOfMatchingBrace(tk, index);
+ if (rparenIndex != index) {
+ if (tk[rparenIndex - 1].is(T_GREATER)) {
+ int lessIndex = startOfMatchingBrace(tk, rparenIndex);
+ if (lessIndex != rparenIndex - 1) {
+ if (tk[lessIndex - 1].is(T_DYNAMIC_CAST) ||
+ tk[lessIndex - 1].is(T_STATIC_CAST) ||
+ tk[lessIndex - 1].is(T_CONST_CAST) ||
+ tk[lessIndex - 1].is(T_REINTERPRET_CAST))
+ return lessIndex - 1;
+ else if (tk[lessIndex - 1].is(T_IDENTIFIER))
+ return startOfExpression(tk, lessIndex);
+ else if (tk[lessIndex - 1].is(T_SIGNAL))
+ return startOfExpression(tk, lessIndex);
+ else if (tk[lessIndex - 1].is(T_SLOT))
+ return startOfExpression(tk, lessIndex);
+ }
+ }
+ return startOfExpression(tk, rparenIndex);
+ }
+ return index;
+ } else if (tk[index - 1].is(T_RBRACKET)) {
+ int rbracketIndex = startOfMatchingBrace(tk, index);
+ if (rbracketIndex != index)
+ return startOfExpression(tk, rbracketIndex);
+ return index;
+ } else if (tk[index - 1].is(T_COLON_COLON)) {
+ if (tk[index - 2].is(T_GREATER)) { // ### not exactly
+ int lessIndex = startOfMatchingBrace(tk, index - 1);
+ if (lessIndex != index - 1)
+ return startOfExpression(tk, lessIndex);
+ return index - 1;
+ } else if (tk[index - 2].is(T_IDENTIFIER)) {
+ return startOfExpression(tk, index - 1);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_DOT) || tk[index - 1].is(T_ARROW)) {
+ return startOfExpression(tk, index - 1);
+ } else if (tk[index - 1].is(T_DOT_STAR) || tk[index - 1].is(T_ARROW_STAR)) {
+ return startOfExpression(tk, index - 1);
+ }
+
+ return index;
+}
+
+bool ExpressionUnderCursor::isAccessToken(const SimpleToken &tk)
+{
+ switch (tk.kind()) {
+ case T_COLON_COLON:
+ case T_DOT: case T_ARROW:
+ case T_DOT_STAR: case T_ARROW_STAR:
+ return true;
+ default:
+ return false;
+ } // switch
+}
+
+int ExpressionUnderCursor::previousBlockState(const QTextBlock &block)
+{
+ const QTextBlock prevBlock = block.previous();
+ if (prevBlock.isValid()) {
+ int state = prevBlock.userState();
+
+ if (state != -1)
+ return state;
+ }
+ return 0;
+}
+
+QString ExpressionUnderCursor::operator()(const QTextCursor &cursor)
+{
+ enum { MAX_BLOCK_COUNT = 5 };
+
+ QTextBlock block = cursor.block();
+ QTextBlock initialBlock = block;
+ for (int i = 0; i < MAX_BLOCK_COUNT; ++i) {
+ if (! initialBlock.previous().isValid())
+ break;
+
+ initialBlock = initialBlock.previous();
+ }
+
+ QString text;
+
+ QTextBlock it = initialBlock;
+ for (; it.isValid(); it = it.next()) {
+ QString textBlock = it.text();
+
+ if (it == block)
+ textBlock = textBlock.left(cursor.position() - cursor.block().position());
+
+ text += textBlock;
+
+ if (it == block)
+ break;
+
+ text += QLatin1Char('\n');
+ }
+
+ SimpleLexer tokenize;
+ tokenize.setSkipComments(true);
+ QList<SimpleToken> tokens = tokenize(text, previousBlockState(initialBlock));
+ tokens.prepend(SimpleToken()); // sentinel
+
+ _jumpedComma = false;
+
+ const int i = startOfExpression(tokens, tokens.size());
+ if (i == tokens.size())
+ return QString();
+
+ return text.mid(tokens.at(i).position(),
+ tokens.last().position() + tokens.last().length()
+ - tokens.at(i).position());
+}
+
diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h
new file mode 100644
index 0000000000..e3fa442326
--- /dev/null
+++ b/src/libs/cplusplus/ExpressionUnderCursor.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EXPRESSIONUNDERCURSOR_H
+#define EXPRESSIONUNDERCURSOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QTextCursor;
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace CPlusPlus {
+
+class SimpleToken;
+
+class CPLUSPLUS_EXPORT ExpressionUnderCursor
+{
+public:
+ ExpressionUnderCursor();
+ ~ExpressionUnderCursor();
+
+ QString operator()(const QTextCursor &cursor);
+
+private:
+ int startOfMatchingBrace(const QList<SimpleToken> &tk, int index);
+ int startOfExpression(const QList<SimpleToken> &tk, int index);
+ int previousBlockState(const QTextBlock &block);
+ bool isAccessToken(const SimpleToken &tk);
+
+ bool _jumpedComma;
+};
+
+} // namespace CPlusPlus
+
+#endif // EXPRESSIONUNDERCURSOR_H
diff --git a/src/libs/cplusplus/Icons.cpp b/src/libs/cplusplus/Icons.cpp
new file mode 100644
index 0000000000..70c4214259
--- /dev/null
+++ b/src/libs/cplusplus/Icons.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "Icons.h"
+
+#include <FullySpecifiedType.h>
+#include <Scope.h>
+#include <Symbols.h>
+#include <Type.h>
+
+using namespace CPlusPlus;
+using CPlusPlus::Icons;
+
+Icons::Icons()
+ : _classIcon(QLatin1String(":/codemodel/images/class.png")),
+ _enumIcon(QLatin1String(":/codemodel/images/enum.png")),
+ _enumeratorIcon(QLatin1String(":/codemodel/images/enumerator.png")),
+ _funcPublicIcon(QLatin1String(":/codemodel/images/func.png")),
+ _funcProtectedIcon(QLatin1String(":/codemodel/images/func_prot.png")),
+ _funcPrivateIcon(QLatin1String(":/codemodel/images/func_priv.png")),
+ _namespaceIcon(QLatin1String(":/codemodel/images/namespace.png")),
+ _varPublicIcon(QLatin1String(":/codemodel/images/var.png")),
+ _varProtectedIcon(QLatin1String(":/codemodel/images/var_prot.png")),
+ _varPrivateIcon(QLatin1String(":/codemodel/images/var_priv.png")),
+ _signalIcon(QLatin1String(":/codemodel/images/signal.png")),
+ _slotPublicIcon(QLatin1String(":/codemodel/images/slot.png")),
+ _slotProtectedIcon(QLatin1String(":/codemodel/images/slot_prot.png")),
+ _slotPrivateIcon(QLatin1String(":/codemodel/images/slot_priv.png")),
+ _keywordIcon(QLatin1String(":/codemodel/images/keyword.png")),
+ _macroIcon(QLatin1String(":/codemodel/images/macro.png"))
+{
+}
+
+QIcon Icons::iconForSymbol(Symbol *symbol) const
+{
+ if (symbol->isFunction() || (symbol->isDeclaration() && symbol->type()->isFunction()))
+ {
+ Function *function = symbol->asFunction();
+ if (!function)
+ function = symbol->type()->asFunction();
+
+ if (function->isSlot()) {
+ if (function->isPublic()) {
+ return _slotPublicIcon;
+ } else if (function->isProtected()) {
+ return _slotProtectedIcon;
+ } else if (function->isPrivate()) {
+ return _slotPrivateIcon;
+ }
+ } else if (function->isSignal()) {
+ return _signalIcon;
+ } else if (symbol->isPublic()) {
+ return _funcPublicIcon;
+ } else if (symbol->isProtected()) {
+ return _funcProtectedIcon;
+ } else if (symbol->isPrivate()) {
+ return _funcPrivateIcon;
+ }
+ } else if (symbol->scope()->isEnumScope()) {
+ return _enumeratorIcon;
+ } else if (symbol->isDeclaration() || symbol->isArgument()) {
+ if (symbol->isPublic()) {
+ return _varPublicIcon;
+ } else if (symbol->isProtected()) {
+ return _varProtectedIcon;
+ } else if (symbol->isPrivate()) {
+ return _varPrivateIcon;
+ }
+ } else if (symbol->isEnum()) {
+ return _enumIcon;
+ } else if (symbol->isClass()) {
+ return _classIcon;
+ } else if (symbol->isNamespace()) {
+ return _namespaceIcon;
+ } else if (symbol->isUsingNamespaceDirective() ||
+ symbol->isUsingDeclaration()) {
+ // TODO: Might be nice to have a different icons for these things
+ return _namespaceIcon;
+ }
+
+ return QIcon();
+}
+
+QIcon Icons::keywordIcon() const
+{
+ return _keywordIcon;
+}
+
+QIcon Icons::macroIcon() const
+{
+ return _macroIcon;
+}
diff --git a/src/libs/cplusplus/Icons.h b/src/libs/cplusplus/Icons.h
new file mode 100644
index 0000000000..c549c1c429
--- /dev/null
+++ b/src/libs/cplusplus/Icons.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_ICONS_H
+#define CPLUSPLUS_ICONS_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+#include <QIcon>
+
+namespace CPlusPlus {
+
+class Symbol;
+
+class CPLUSPLUS_EXPORT Icons
+{
+public:
+ Icons();
+
+ QIcon iconForSymbol(Symbol *symbol) const;
+
+ QIcon keywordIcon() const;
+ QIcon macroIcon() const;
+
+private:
+ QIcon _classIcon;
+ QIcon _enumIcon;
+ QIcon _enumeratorIcon;
+ QIcon _funcPublicIcon;
+ QIcon _funcProtectedIcon;
+ QIcon _funcPrivateIcon;
+ QIcon _namespaceIcon;
+ QIcon _varPublicIcon;
+ QIcon _varProtectedIcon;
+ QIcon _varPrivateIcon;
+ QIcon _signalIcon;
+ QIcon _slotPublicIcon;
+ QIcon _slotProtectedIcon;
+ QIcon _slotPrivateIcon;
+ QIcon _keywordIcon;
+ QIcon _macroIcon;
+};
+
+} // namespace CPlusPlus
+
+#endif // CPLUSPLUS_ICONS_H
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
new file mode 100644
index 0000000000..027cfb577d
--- /dev/null
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "LookupContext.h"
+#include <CoreTypes.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <Names.h>
+#include <Scope.h>
+#include <Control.h>
+#include <cplusplus/Overview.h>
+#include <QFile>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+/////////////////////////////////////////////////////////////////////
+// LookupUtils
+/////////////////////////////////////////////////////////////////////
+bool LookupUtils::isNameCompatibleWithIdentifier(Name *name, Identifier *id)
+{
+ if (! name) {
+ return false;
+ } else if (NameId *nameId = name->asNameId()) {
+ Identifier *identifier = nameId->identifier();
+ return identifier->isEqualTo(id);
+ } else if (DestructorNameId *nameId = name->asDestructorNameId()) {
+ Identifier *identifier = nameId->identifier();
+ return identifier->isEqualTo(id);
+ } else if (TemplateNameId *templNameId = name->asTemplateNameId()) {
+ Identifier *identifier = templNameId->identifier();
+ return identifier->isEqualTo(id);
+ }
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////
+// LookupContext
+/////////////////////////////////////////////////////////////////////
+LookupContext::LookupContext(Control *control)
+ : _control(control),
+ _symbol(0)
+{ }
+
+LookupContext::LookupContext(Symbol *symbol,
+ Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const QMap<QString, Document::Ptr> &documents)
+ : _symbol(symbol),
+ _expressionDocument(expressionDocument),
+ _thisDocument(thisDocument),
+ _documents(documents)
+{
+ _control = _expressionDocument->control();
+ _visibleScopes = buildVisibleScopes();
+}
+
+LookupContext::LookupContext(Symbol *symbol,
+ const LookupContext &context)
+ : _control(context._control),
+ _symbol(symbol),
+ _expressionDocument(context._expressionDocument),
+ _documents(context._documents)
+{
+ const QString fn = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
+ _thisDocument = _documents.value(fn);
+ _visibleScopes = buildVisibleScopes();
+}
+
+LookupContext::LookupContext(Symbol *symbol,
+ Document::Ptr thisDocument,
+ const LookupContext &context)
+ : _control(context._control),
+ _symbol(symbol),
+ _expressionDocument(context._expressionDocument),
+ _thisDocument(thisDocument),
+ _documents(context._documents)
+{
+ _visibleScopes = buildVisibleScopes();
+}
+
+bool LookupContext::isValid() const
+{ return _control != 0; }
+
+LookupContext::operator bool() const
+{ return _control != 0; }
+
+Control *LookupContext::control() const
+{ return _control; }
+
+Symbol *LookupContext::symbol() const
+{ return _symbol; }
+
+Document::Ptr LookupContext::expressionDocument() const
+{ return _expressionDocument; }
+
+Document::Ptr LookupContext::thisDocument() const
+{ return _thisDocument; }
+
+Document::Ptr LookupContext::document(const QString &fileName) const
+{ return _documents.value(fileName); }
+
+Identifier *LookupContext::identifier(Name *name) const
+{
+ if (NameId *nameId = name->asNameId())
+ return nameId->identifier();
+ else if (TemplateNameId *templId = name->asTemplateNameId())
+ return templId->identifier();
+ else if (DestructorNameId *dtorId = name->asDestructorNameId())
+ return dtorId->identifier();
+ else if (QualifiedNameId *q = name->asQualifiedNameId())
+ return identifier(q->unqualifiedNameId());
+ return 0;
+}
+
+QList<Symbol *> LookupContext::resolve(Name *name, const QList<Scope *> &visibleScopes,
+ ResolveMode mode) const
+{
+ if (QualifiedNameId *q = name->asQualifiedNameId()) {
+ QList<Scope *> scopes = visibleScopes;
+ for (unsigned i = 0; i < q->nameCount(); ++i) {
+ Name *name = q->nameAt(i);
+
+ QList<Symbol *> candidates;
+ if (i + 1 == q->nameCount())
+ candidates = resolve(name, scopes, mode);
+ else
+ candidates = resolveClassOrNamespace(name, scopes);
+
+ if (candidates.isEmpty() || i + 1 == q->nameCount())
+ return candidates;
+
+ scopes.clear();
+ foreach (Symbol *candidate, candidates) {
+ if (ScopedSymbol *scoped = candidate->asScopedSymbol()) {
+ expand(scoped->members(), visibleScopes, &scopes);
+ }
+ }
+ }
+
+ return QList<Symbol *>();
+ }
+
+ QList<Symbol *> candidates;
+ if (Identifier *id = identifier(name)) {
+ 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;
+ else if (symbol->name()->isQualifiedNameId())
+ continue;
+ else if (! isNameCompatibleWithIdentifier(symbol->name(), id))
+ continue;
+ else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId())
+ continue;
+ else if ((((mode & ResolveNamespace) && symbol->isNamespace()) ||
+ ((mode & ResolveClass) && symbol->isClass()) ||
+ (mode & ResolveSymbol)) && ! candidates.contains(symbol)) {
+ candidates.append(symbol);
+ }
+ }
+ }
+ } else if (OperatorNameId *opId = name->asOperatorNameId()) {
+ 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;
+ else if (! candidates.contains(symbol))
+ candidates.append(symbol);
+ }
+ }
+ }
+
+ return candidates;
+}
+
+QList<Scope *> LookupContext::buildVisibleScopes()
+{
+ QList<Scope *> scopes;
+
+ if (_symbol) {
+ for (Scope *scope = _symbol->scope(); scope; scope = scope->enclosingScope()) {
+ scopes.append(scope);
+ }
+ }
+
+ QSet<QString> processed;
+ processed.insert(_thisDocument->fileName());
+
+ QList<QString> todo = _thisDocument->includedFiles();
+ while (! todo.isEmpty()) {
+ QString fn = todo.last();
+ todo.removeLast();
+
+ if (processed.contains(fn))
+ continue;
+
+ processed.insert(fn);
+ if (Document::Ptr doc = document(fn)) {
+ scopes.append(doc->globalNamespace()->members());
+ todo += doc->includedFiles();
+ }
+ }
+
+ while (true) {
+ QList<Scope *> expandedScopes;
+ expand(scopes, &expandedScopes);
+
+ if (expandedScopes.size() == scopes.size())
+ return expandedScopes;
+
+ scopes = expandedScopes;
+ }
+
+ return scopes;
+}
+
+QList<Scope *> LookupContext::visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const
+{
+ Symbol *symbol = result.second;
+ QList<Scope *> scopes;
+ for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
+ scopes.append(scope);
+ scopes += visibleScopes();
+ scopes = expand(scopes);
+ return scopes;
+}
+
+QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
+{
+ QList<Scope *> expanded;
+ expand(scopes, &expanded);
+ return expanded;
+}
+
+void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
+{
+ for (int i = 0; i < scopes.size(); ++i) {
+ expand(scopes.at(i), scopes, expandedScopes);
+ }
+}
+
+void LookupContext::expand(Scope *scope,
+ const QList<Scope *> &visibleScopes,
+ QList<Scope *> *expandedScopes) const
+{
+ Overview overview;
+
+ if (expandedScopes->contains(scope)) {
+ //qDebug() << "skipped:" << overview.prettyName(scope->owner()->name());
+ return;
+ }
+
+ expandedScopes->append(scope);
+
+ if (scope->isNamespaceScope()) {
+ Namespace *ns = scope->owner()->asNamespace();
+ Name *nsName = ns->name();
+ if (nsName) {
+ QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
+ foreach (Symbol *otherNs, namespaceList) {
+ if (otherNs == ns)
+ continue;
+ expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
+ }
+ //qDebug() << "*** found:" << namespaceList.count() << "namespace aliases";
+ }
+ //qDebug() << "namespace scope" << overview.prettyName(ns->name())
+ //<< ns->fileName() << ns->line();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) { // ### make me fast
+ Symbol *symbol = scope->symbolAt(i);
+ if (Namespace *ns = symbol->asNamespace()) {
+ if (! ns->name()) {
+ expand(ns->members(), visibleScopes, expandedScopes);
+ }
+ } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
+ QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
+ //qDebug() << "found:" << candidates.count() << "namespaces to import for:"
+ //<< overview.prettyName(u->name());
+ 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);
+ }
+ }
+ } else if (scope->isClassScope()) {
+ Class *klass = scope->owner()->asClass();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(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()) {
+ 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);
+ Name *baseClassName = baseClass->name();
+ QList<Symbol *> baseClassCandidates = resolveClass(baseClassName, classVisibleScopes);
+ if (baseClassCandidates.isEmpty()) {
+ Overview overview;
+ qDebug() << "unresolved base class:" << overview.prettyName(baseClassName);
+ }
+ for (int j = 0; j < baseClassCandidates.size(); ++j) {
+ Class *baseClassSymbol = baseClassCandidates.at(j)->asClass();
+ expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
+ }
+ }
+ }
+ } else if (scope->isBlockScope()) {
+ //qDebug() << "block scope" << overview.prettyName(scope->owner()->name());
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+ if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
+ QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
+ //qDebug() << "found:" << candidates.count() << "namespaces to import for:"
+ //<< overview.prettyName(u->name());
+ for (int j = 0; j < candidates.size(); ++j) {
+ expand(candidates.at(j)->asNamespace()->members(),
+ visibleScopes, expandedScopes);
+ }
+ }
+
+ }
+ } else if (scope->isFunctionScope()) {
+ Function *function = scope->owner()->asFunction();
+ //qDebug() << "function scope" << overview.prettyName(function->name());
+ if (! expandedScopes->contains(function->arguments()))
+ expandedScopes->append(function->arguments());
+ if (QualifiedNameId *q = function->name()->asQualifiedNameId()) {
+ //qDebug() << "**** here:" << overview.prettyName(function->name());
+ Name *nestedNameSpec = 0;
+ if (q->nameCount() == 1 && q->isGlobal())
+ nestedNameSpec = q->nameAt(0);
+ else
+ nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
+ q->isGlobal());
+ QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
+ //qDebug() << "**** found:" << candidates.count() << "class or namespace for:"
+ //<< overview.prettyName(nestedNameSpec);
+ for (int j = 0; j < candidates.size(); ++j) {
+ expand(candidates.at(j)->asScopedSymbol()->members(),
+ visibleScopes, expandedScopes);
+ }
+ }
+ } else if (scope->isPrototypeScope()) {
+ //qDebug() << "prototype scope" << overview.prettyName(scope->owner()->name());
+ }
+}
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
new file mode 100644
index 0000000000..d2fe8b7bef
--- /dev/null
+++ b/src/libs/cplusplus/LookupContext.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_LOOKUPCONTEXT_H
+#define CPLUSPLUS_LOOKUPCONTEXT_H
+
+#include <SymbolVisitor.h>
+#include <cplusplus/CppDocument.h>
+
+#include <QList>
+#include <QSet>
+#include <QMap>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT LookupUtils
+{
+public:
+ static bool isNameCompatibleWithIdentifier(Name *name,
+ Identifier *id);
+};
+
+class CPLUSPLUS_EXPORT LookupContext: LookupUtils
+{
+public:
+ LookupContext(Control *control = 0);
+
+ LookupContext(Symbol *symbol,
+ Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const QMap<QString, Document::Ptr> &documents);
+
+ LookupContext(Symbol *symbol,
+ const LookupContext &context);
+
+ LookupContext(Symbol *symbol,
+ Document::Ptr thisDocument,
+ const LookupContext &context);
+
+ bool isValid() const;
+ operator bool() const;
+
+ Control *control() const;
+ Symbol *symbol() const;
+ Document::Ptr expressionDocument() const;
+ Document::Ptr thisDocument() const;
+ Document::Ptr document(const QString &fileName) const;
+
+ QList<Symbol *> resolve(Name *name) const
+ { return resolve(name, visibleScopes()); }
+
+ QList<Symbol *> resolveNamespace(Name *name) const
+ { return resolveNamespace(name, visibleScopes()); }
+
+ QList<Symbol *> resolveClass(Name *name) const
+ { return resolveClass(name, visibleScopes()); }
+
+ QList<Symbol *> resolveClassOrNamespace(Name *name) const
+ { return resolveClassOrNamespace(name, visibleScopes()); }
+
+ QMap<QString, Document::Ptr> documents() const
+ { return _documents; }
+
+ enum ResolveMode {
+ ResolveSymbol = 0x01,
+ ResolveClass = 0x02,
+ ResolveNamespace = 0x04,
+ ResolveClassOrNamespace = ResolveClass | ResolveNamespace,
+ ResolveAll = ResolveSymbol | ResolveClassOrNamespace
+ };
+
+ Identifier *identifier(Name *name) const;
+
+ QList<Symbol *> resolve(Name *name, const QList<Scope *> &visibleScopes,
+ ResolveMode mode = ResolveAll) const;
+
+ QList<Symbol *> resolveNamespace(Name *name, const QList<Scope *> &visibleScopes) const
+ { return resolve(name, visibleScopes, ResolveNamespace); }
+
+ QList<Symbol *> resolveClass(Name *name, const QList<Scope *> &visibleScopes) const
+ { return resolve(name, visibleScopes, ResolveClass); }
+
+ QList<Symbol *> resolveClassOrNamespace(Name *name, const QList<Scope *> &visibleScopes) const
+ { return resolve(name, visibleScopes, ResolveClassOrNamespace); }
+
+ QList<Scope *> visibleScopes() const
+ { return _visibleScopes; }
+
+ QList<Scope *> visibleScopes(const QPair<FullySpecifiedType, Symbol *> &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;
+
+private:
+ QList<Scope *> buildVisibleScopes();
+
+private:
+ Control *_control;
+
+ // The current symbol.
+ Symbol *_symbol;
+
+ // The current expression.
+ Document::Ptr _expressionDocument;
+
+ // The current document.
+ Document::Ptr _thisDocument;
+
+ // All documents.
+ QMap<QString, Document::Ptr> _documents;
+
+ // Visible scopes.
+ QList<Scope *> _visibleScopes;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_LOOKUPCONTEXT_H
diff --git a/src/libs/cplusplus/NameOfExpression.cpp b/src/libs/cplusplus/NameOfExpression.cpp
new file mode 100644
index 0000000000..d54e7f5521
--- /dev/null
+++ b/src/libs/cplusplus/NameOfExpression.cpp
@@ -0,0 +1,438 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "NameOfExpression.h"
+#include "LookupContext.h"
+
+#include <cplusplus/Overview.h>
+#include <Control.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Names.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <CoreTypes.h>
+#include <TypeVisitor.h>
+#include <NameVisitor.h>
+#include <QList>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+NameOfExpression::NameOfExpression(const LookupContext &context)
+ : ASTVisitor(context.expressionDocument()->control()),
+ _context(context),
+ sem(_context.control())
+{ }
+
+NameOfExpression::~NameOfExpression()
+{ }
+
+QList<FullySpecifiedType> ResolveExpression::operator()(ExpressionAST *ast)
+{
+ QList<FullySpecifiedType> previousResolvedSymbols = switchResolvedSymbols(QList<FullySpecifiedType>());
+ accept(ast);
+ return switchResolvedSymbols(previousResolvedSymbols);
+}
+
+QList<FullySpecifiedType> ResolveExpression::switchResolvedSymbols(const QList<FullySpecifiedType> &symbols)
+{
+ QList<FullySpecifiedType> previousResolvedSymbols = _resolvedSymbols;
+ _resolvedSymbols = symbols;
+ return previousResolvedSymbols;
+}
+
+bool ResolveExpression::visit(ExpressionListAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(BinaryExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CastExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionalExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CppCastExpressionAST *)
+{
+ // ### resolve ast->type_id
+ return false;
+}
+
+bool ResolveExpression::visit(DeleteExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayInitializerAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(NewExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(TypeidExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(TypenameCallExpressionAST *)
+{
+ // nothing to do
+ return false;
+}
+
+bool ResolveExpression::visit(TypeConstructorCallAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(PostfixExpressionAST *ast)
+{
+ accept(ast->base_expression);
+
+ for (PostfixAST *fx = ast->postfix_expressions; fx; fx = fx->next) {
+ accept(fx);
+ }
+
+ return false;
+}
+
+bool ResolveExpression::visit(SizeofExpressionAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Int));
+ ty.setUnsigned(true);
+ _resolvedSymbols.append(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(NumericLiteralAST *)
+{
+ _resolvedSymbols.append(control()->integerType(IntegerType::Int)); // ### handle short, long, floats, ...
+ return false;
+}
+
+bool ResolveExpression::visit(BoolLiteralAST *)
+{
+ _resolvedSymbols.append(control()->integerType(IntegerType::Bool));
+ return false;
+}
+
+bool ResolveExpression::visit(ThisExpressionAST *)
+{
+ if (! _context.symbol())
+ return false;
+
+ Scope *scope = _context.symbol()->scope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->isFunctionScope()) {
+ Function *fun = scope->owner()->asFunction();
+ if (Scope *cscope = scope->enclosingClassScope()) {
+ Class *klass = cscope->owner()->asClass();
+ FullySpecifiedType classTy(control()->namedType(klass->name()));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ _resolvedSymbols.append(ptrTy);
+ break;
+ } else if (QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
+ Name *nestedNameSpecifier = 0;
+ if (q->nameCount() == 2)
+ nestedNameSpecifier = q->nameAt(0);
+ else
+ nestedNameSpecifier = control()->qualifiedNameId(&q->names()[0], q->nameCount() - 1);
+ FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ _resolvedSymbols.append(ptrTy);
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(NestedExpressionAST *ast)
+{
+ accept(ast->expression);
+ return false;
+}
+
+bool ResolveExpression::visit(StringLiteralAST *)
+{
+ FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
+ charTy.setConst(true);
+ FullySpecifiedType ty(control()->pointerType(charTy));
+ _resolvedSymbols.append(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(ThrowExpressionAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(TypeIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(UnaryExpressionAST *ast)
+{
+ accept(ast->expression);
+ unsigned unaryOp = tokenKind(ast->unary_op_token);
+ if (unaryOp == T_AMPER) {
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ ty.setType(control()->pointerType(ty));
+ it.setValue(ty);
+ }
+ } else if (unaryOp == T_STAR) {
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ it.setValue(ptrTy->elementType());
+ } else {
+ it.remove();
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(QualifiedNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols) {
+ if (symbol->isTypedef()) {
+ if (NamedType *namedTy = symbol->type()->asNamedType()) {
+ LookupContext symbolContext(symbol, _context);
+ QList<Symbol *> resolvedClasses = symbolContext.resolveClass(namedTy->name());
+ if (resolvedClasses.count()) {
+ foreach (Symbol *s, resolvedClasses) {
+ _resolvedSymbols.append(s->type());
+ }
+ continue;
+ }
+ }
+ }
+ _resolvedSymbols.append(symbol->type());
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(OperatorFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(ConversionFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(SimpleNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ _resolvedSymbols.append(symbol->type());
+
+ return false;
+}
+
+bool ResolveExpression::visit(DestructorNameAST *)
+{
+ FullySpecifiedType ty(control()->voidType());
+ _resolvedSymbols.append(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(TemplateIdAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ _resolvedSymbols.append(symbol->type());
+
+ return false;
+}
+
+bool ResolveExpression::visit(CallAST *)
+{
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ if (Function *funTy = ty->asFunction()) {
+ it.setValue(funTy->returnType());
+ } else {
+ it.remove();
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayAccessAST * /* ast */)
+{
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ it.setValue(ptrTy->elementType());
+ } else {
+ it.remove();
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(MemberAccessAST *ast)
+{
+ Scope dummy;
+ Name *memberName = sem.check(ast->member_name, &dummy);
+ unsigned accessOp = tokenKind(ast->access_token);
+
+ Overview overview;
+
+ QList<FullySpecifiedType> candidates = _resolvedSymbols;
+ _resolvedSymbols.clear();
+
+ foreach (FullySpecifiedType ty, candidates) {
+ NamedType *namedTy = 0;
+
+ if (accessOp == T_ARROW) {
+ if (PointerType *ptrTy = ty->asPointerType())
+ namedTy = ptrTy->elementType()->asNamedType();
+ } else if (accessOp == T_DOT) {
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+ namedTy = ty->asNamedType();
+ if (! namedTy) {
+ Function *fun = ty->asFunction();
+ if (fun && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()))
+ namedTy = fun->returnType()->asNamedType();
+ }
+ }
+
+ if (namedTy) {
+ QList<Symbol *> symbols = _context.resolveClass(namedTy->name());
+ if (symbols.isEmpty())
+ return false;
+
+ Class *klass = symbols.first()->asClass();
+ QList<Scope *> allScopes;
+ QSet<Class *> processed;
+ QList<Class *> todo;
+ todo.append(klass);
+
+ while (! todo.isEmpty()) {
+ Class *klass = todo.last();
+ todo.removeLast();
+
+ if (processed.contains(klass))
+ continue;
+
+ processed.insert(klass);
+ allScopes.append(klass->members());
+
+ for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
+ BaseClass *baseClass = klass->baseClassAt(i);
+ Name *baseClassName = baseClass->name();
+ QList<Symbol *> baseClasses = _context.resolveClass(baseClassName/*, allScopes*/);
+ if (baseClasses.isEmpty())
+ qWarning() << "unresolved base class:" << overview.prettyName(baseClassName);
+ foreach (Symbol *symbol, baseClasses) {
+ todo.append(symbol->asClass());
+ }
+ }
+ }
+
+ QList<Symbol *> candidates = _context.resolve(memberName, allScopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ if (TemplateNameId *templId = namedTy->name()->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+ _resolvedSymbols.append(ty);
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(PostIncrDecrAST *)
+{
+ return false;
+}
diff --git a/src/libs/cplusplus/NameOfExpression.h b/src/libs/cplusplus/NameOfExpression.h
new file mode 100644
index 0000000000..f68795cea0
--- /dev/null
+++ b/src/libs/cplusplus/NameOfExpression.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_NAMEOFEXPRESSION_H
+#define CPLUSPLUS_NAMEOFEXPRESSION_H
+
+#include "LookupContext.h"
+#include <ASTVisitor.h>
+#include <Semantic.h>
+#include <FullySpecifiedType.h>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT NameOfExpression : protected ASTVisitor
+{
+public:
+ NameOfExpression(const LookupContext &context);
+ virtual ~NameOfExpression();
+
+ Name* operator()(ExpressionAST *ast);
+
+protected:
+ QList<FullySpecifiedType> switchResolvedSymbols(const QList<FullySpecifiedType> &symbols);
+
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+
+ //names
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+ // postfix expressions
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+
+private:
+ LookupContext _context;
+ Semantic sem;
+ QList<FullySpecifiedType> _resolvedSymbols;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_NAMEOFEXPRESSION_H
diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp
new file mode 100644
index 0000000000..5d6fddfb63
--- /dev/null
+++ b/src/libs/cplusplus/NamePrettyPrinter.cpp
@@ -0,0 +1,255 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "NamePrettyPrinter.h"
+#include <Names.h>
+#include <Overview.h>
+#include <NameVisitor.h>
+#include <Literals.h>
+
+using namespace CPlusPlus;
+
+NamePrettyPrinter::NamePrettyPrinter(const Overview *overview)
+ : _overview(overview)
+{ }
+
+NamePrettyPrinter::~NamePrettyPrinter()
+{ }
+
+const Overview *NamePrettyPrinter::overview() const
+{ return _overview; }
+
+QString NamePrettyPrinter::operator()(Name *name)
+{
+ QString previousName = switchName();
+ accept(name);
+ return switchName(previousName);
+}
+
+QString NamePrettyPrinter::switchName(const QString &name)
+{
+ QString previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+void NamePrettyPrinter::visit(NameId *name)
+{
+ Identifier *id = name->identifier();
+ if (id)
+ _name = QString::fromLatin1(id->chars(), id->size());
+ else
+ _name = QLatin1String("anonymous");
+}
+
+void NamePrettyPrinter::visit(TemplateNameId *name)
+{
+ Identifier *id = name->identifier();
+ if (id)
+ _name = QString::fromLatin1(id->chars(), id->size());
+ else
+ _name = QLatin1String("anonymous");
+ _name += QLatin1Char('<');
+ for (unsigned index = 0; index < name->templateArgumentCount(); ++index) {
+ if (index != 0)
+ _name += QLatin1String(", ");
+
+ FullySpecifiedType argTy = name->templateArgumentAt(index);
+ QString arg = overview()->prettyType(argTy);
+ if (arg.isEmpty())
+ _name += QString::fromLatin1("_Tp%1").arg(index + 1);
+ else
+ _name += arg;
+ }
+ _name += QLatin1Char('>');
+}
+
+void NamePrettyPrinter::visit(DestructorNameId *name)
+{
+ Identifier *id = name->identifier();
+ _name += QLatin1Char('~');
+ _name += QString::fromLatin1(id->chars(), id->size());
+}
+
+void NamePrettyPrinter::visit(OperatorNameId *name)
+{
+ _name += QLatin1String("operator ");
+ switch (name->kind()) { // ### i should probably do this in OperatorNameId
+ case OperatorNameId::InvalidOp:
+ _name += QLatin1String("<invalid>");
+ break;
+ case OperatorNameId::NewOp:
+ _name += QLatin1String("new");
+ break;
+ case OperatorNameId::DeleteOp:
+ _name += QLatin1String("delete");
+ break;
+ case OperatorNameId::NewArrayOp:
+ _name += QLatin1String("new[]");
+ break;
+ case OperatorNameId::DeleteArrayOp:
+ _name += QLatin1String("delete[]");
+ break;
+ case OperatorNameId::PlusOp:
+ _name += QLatin1String("+");
+ break;
+ case OperatorNameId::MinusOp:
+ _name += QLatin1String("-");
+ break;
+ case OperatorNameId::StarOp:
+ _name += QLatin1String("*");
+ break;
+ case OperatorNameId::SlashOp:
+ _name += QLatin1String("/");
+ break;
+ case OperatorNameId::PercentOp:
+ _name += QLatin1String("%");
+ break;
+ case OperatorNameId::CaretOp:
+ _name += QLatin1String("^");
+ break;
+ case OperatorNameId::AmpOp:
+ _name += QLatin1String("&");
+ break;
+ case OperatorNameId::PipeOp:
+ _name += QLatin1String("|");
+ break;
+ case OperatorNameId::TildeOp:
+ _name += QLatin1String("~");
+ break;
+ case OperatorNameId::ExclaimOp:
+ _name += QLatin1String("!");
+ break;
+ case OperatorNameId::EqualOp:
+ _name += QLatin1String("=");
+ break;
+ case OperatorNameId::LessOp:
+ _name += QLatin1String("<");
+ break;
+ case OperatorNameId::GreaterOp:
+ _name += QLatin1String(">");
+ break;
+ case OperatorNameId::PlusEqualOp:
+ _name += QLatin1String("+=");
+ break;
+ case OperatorNameId::MinusEqualOp:
+ _name += QLatin1String("-=");
+ break;
+ case OperatorNameId::StarEqualOp:
+ _name += QLatin1String("*=");
+ break;
+ case OperatorNameId::SlashEqualOp:
+ _name += QLatin1String("/=");
+ break;
+ case OperatorNameId::PercentEqualOp:
+ _name += QLatin1String("%=");
+ break;
+ case OperatorNameId::CaretEqualOp:
+ _name += QLatin1String("^=");
+ break;
+ case OperatorNameId::AmpEqualOp:
+ _name += QLatin1String("&=");
+ break;
+ case OperatorNameId::PipeEqualOp:
+ _name += QLatin1String("|=");
+ break;
+ case OperatorNameId::LessLessOp:
+ _name += QLatin1String("<<");
+ break;
+ case OperatorNameId::GreaterGreaterOp:
+ _name += QLatin1String(">>");
+ break;
+ case OperatorNameId::LessLessEqualOp:
+ _name += QLatin1String("<<=");
+ break;
+ case OperatorNameId::GreaterGreaterEqualOp:
+ _name += QLatin1String(">>=");
+ break;
+ case OperatorNameId::EqualEqualOp:
+ _name += QLatin1String("==");
+ break;
+ case OperatorNameId::ExclaimEqualOp:
+ _name += QLatin1String("!=");
+ break;
+ case OperatorNameId::LessEqualOp:
+ _name += QLatin1String("<=");
+ break;
+ case OperatorNameId::GreaterEqualOp:
+ _name += QLatin1String(">=");
+ break;
+ case OperatorNameId::AmpAmpOp:
+ _name += QLatin1String("&&");
+ break;
+ case OperatorNameId::PipePipeOp:
+ _name += QLatin1String("||");
+ break;
+ case OperatorNameId::PlusPlusOp:
+ _name += QLatin1String("++");
+ break;
+ case OperatorNameId::MinusMinusOp:
+ _name += QLatin1String("--");
+ break;
+ case OperatorNameId::CommaOp:
+ _name += QLatin1String(",");
+ break;
+ case OperatorNameId::ArrowStarOp:
+ _name += QLatin1String("->*");
+ break;
+ case OperatorNameId::ArrowOp:
+ _name += QLatin1String("->");
+ break;
+ case OperatorNameId::FunctionCallOp:
+ _name += QLatin1String("()");
+ break;
+ case OperatorNameId::ArrayAccessOp:
+ _name += QLatin1String("[]");
+ break;
+ } // switch
+}
+
+void NamePrettyPrinter::visit(ConversionNameId *name)
+{
+ _name += QLatin1String("operator ");
+ _name += overview()->prettyType(name->type());
+}
+
+void NamePrettyPrinter::visit(QualifiedNameId *name)
+{
+ if (name->isGlobal())
+ _name += QLatin1String("::");
+
+ for (unsigned index = 0; index < name->nameCount(); ++index) {
+ if (index != 0)
+ _name += QLatin1String("::");
+ _name += operator()(name->nameAt(index));
+ }
+}
diff --git a/src/libs/cplusplus/NamePrettyPrinter.h b/src/libs/cplusplus/NamePrettyPrinter.h
new file mode 100644
index 0000000000..3868432650
--- /dev/null
+++ b/src/libs/cplusplus/NamePrettyPrinter.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_NAMEPRETTYPRINTER_H
+#define CPLUSPLUS_NAMEPRETTYPRINTER_H
+
+#include <NameVisitor.h>
+#include <QString>
+
+namespace CPlusPlus {
+
+class Overview;
+
+class CPLUSPLUS_EXPORT NamePrettyPrinter: protected NameVisitor
+{
+public:
+ NamePrettyPrinter(const Overview *overview);
+ virtual ~NamePrettyPrinter();
+
+ const Overview *overview() const;
+ QString operator()(Name *name);
+
+protected:
+ QString switchName(const QString &name = QString());
+
+ virtual void visit(NameId *name);
+ virtual void visit(TemplateNameId *name);
+ virtual void visit(DestructorNameId *name);
+ virtual void visit(OperatorNameId *name);
+ virtual void visit(ConversionNameId *name);
+ virtual void visit(QualifiedNameId *name);
+
+private:
+ const Overview *_overview;
+ QString _name;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_NAMEPRETTYPRINTER_H
diff --git a/src/libs/cplusplus/Overview.cpp b/src/libs/cplusplus/Overview.cpp
new file mode 100644
index 0000000000..ec40f75b51
--- /dev/null
+++ b/src/libs/cplusplus/Overview.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "Overview.h"
+#include "NamePrettyPrinter.h"
+#include "TypePrettyPrinter.h"
+#include <FullySpecifiedType.h>
+
+using namespace CPlusPlus;
+
+Overview::Overview()
+ : _markArgument(0),
+ _showArgumentNames(false),
+ _showReturnTypes(false),
+ _showFunctionSignatures(true)
+{ }
+
+Overview::~Overview()
+{ }
+
+bool Overview::showArgumentNames() const
+{ return _showArgumentNames; }
+
+void Overview::setShowArgumentNames(bool showArgumentNames)
+{ _showArgumentNames = showArgumentNames; }
+
+void Overview::setShowReturnTypes(bool showReturnTypes)
+{ _showReturnTypes = showReturnTypes; }
+
+bool Overview::showReturnTypes() const
+{ return _showReturnTypes; }
+
+void Overview::setMarkArgument(unsigned position)
+{ _markArgument = position; }
+
+bool Overview::showFunctionSignatures() const
+{ return _showFunctionSignatures; }
+
+void Overview::setShowFunctionSignatures(bool showFunctionSignatures)
+{ _showFunctionSignatures = showFunctionSignatures; }
+
+QString Overview::prettyName(Name *name) const
+{
+ NamePrettyPrinter pp(this);
+ return pp(name);
+}
+
+QString Overview::prettyType(const FullySpecifiedType &ty,
+ Name *name) const
+{ return prettyType(ty, prettyName(name)); }
+
+QString Overview::prettyType(const FullySpecifiedType &ty,
+ const QString &name) const
+{
+ TypePrettyPrinter pp(this);
+ pp.setMarkArgument(_markArgument);
+ pp.setShowArgumentNames(_showArgumentNames);
+ pp.setShowReturnTypes(_showReturnTypes);
+ pp.setShowFunctionSignatures(_showFunctionSignatures);
+ return pp(ty, name);
+}
diff --git a/src/libs/cplusplus/Overview.h b/src/libs/cplusplus/Overview.h
new file mode 100644
index 0000000000..6b84a4b53f
--- /dev/null
+++ b/src/libs/cplusplus/Overview.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OVERVIEW_H
+#define OVERVIEW_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <QString>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT Overview
+{
+ Overview(const Overview &other);
+ void operator =(const Overview &other);
+
+public:
+ Overview();
+ ~Overview();
+
+ bool showArgumentNames() const;
+ void setShowArgumentNames(bool showArgumentNames);
+
+ bool showReturnTypes() const;
+ void setShowReturnTypes(bool showReturnTypes);
+
+ bool showFunctionSignatures() const;
+ void setShowFunctionSignatures(bool showFunctionSignatures);
+
+ void setMarkArgument(unsigned position); // 1-based
+
+ QString operator()(Name *name) const
+ { return prettyName(name); }
+
+ QString operator()(const FullySpecifiedType &type, Name *name = 0) const
+ { return prettyType(type, name); }
+
+ QString prettyName(Name *name) const;
+ QString prettyType(const FullySpecifiedType &type, Name *name = 0) const;
+ QString prettyType(const FullySpecifiedType &type, const QString &name) const;
+
+private:
+ unsigned _markArgument;
+ bool _showArgumentNames: 1;
+ bool _showReturnTypes: 1;
+ bool _showFunctionSignatures: 1;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // OVERVIEW_H
diff --git a/src/libs/cplusplus/OverviewModel.cpp b/src/libs/cplusplus/OverviewModel.cpp
new file mode 100644
index 0000000000..028811e6ae
--- /dev/null
+++ b/src/libs/cplusplus/OverviewModel.cpp
@@ -0,0 +1,183 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "OverviewModel.h"
+#include "Overview.h"
+#include <Scope.h>
+#include <Semantic.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <QFile>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+OverviewModel::OverviewModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{ }
+
+OverviewModel::~OverviewModel()
+{ }
+
+bool OverviewModel::hasDocument() const
+{ return _cppDocument; }
+
+Document::Ptr OverviewModel::document() const
+{ return _cppDocument; }
+
+unsigned OverviewModel::globalSymbolCount() const
+{
+ unsigned count = 0;
+ if (_cppDocument)
+ count += _cppDocument->globalSymbolCount();
+ return count;
+}
+
+Symbol *OverviewModel::globalSymbolAt(unsigned index) const
+{ return _cppDocument->globalSymbolAt(index); }
+
+QModelIndex OverviewModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (! hasDocument()) {
+ return QModelIndex();
+ } else if (! parent.isValid()) {
+ Symbol *symbol = globalSymbolAt(row);
+ return createIndex(row, column, symbol);
+ } else {
+ Symbol *parentSymbol = static_cast<Symbol *>(parent.internalPointer());
+ Q_ASSERT(parentSymbol != 0);
+
+ ScopedSymbol *scopedSymbol = parentSymbol->asScopedSymbol();
+ Q_ASSERT(scopedSymbol != 0);
+
+ Scope *scope = scopedSymbol->members();
+ Q_ASSERT(scope != 0);
+
+ return createIndex(row, 0, scope->symbolAt(row));
+ }
+}
+
+QModelIndex OverviewModel::parent(const QModelIndex &child) const
+{
+ Symbol *symbol = static_cast<Symbol *>(child.internalPointer());
+ Q_ASSERT(symbol != 0);
+
+ if (Scope *scope = symbol->scope()) {
+ Symbol *parentSymbol = scope->owner();
+ if (parentSymbol && parentSymbol->scope())
+ return createIndex(parentSymbol->index(), 0, parentSymbol);
+ }
+
+ return QModelIndex();
+}
+
+int OverviewModel::rowCount(const QModelIndex &parent) const
+{
+ if (hasDocument()) {
+ if (! parent.isValid()) {
+ return globalSymbolCount();
+ } else {
+ Symbol *parentSymbol = static_cast<Symbol *>(parent.internalPointer());
+ Q_ASSERT(parentSymbol != 0);
+
+ if (ScopedSymbol *scopedSymbol = parentSymbol->asScopedSymbol()) {
+ if (! scopedSymbol->isFunction()) {
+ Scope *parentScope = scopedSymbol->members();
+ Q_ASSERT(parentScope != 0);
+
+ return parentScope->symbolCount();
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int OverviewModel::columnCount(const QModelIndex &) const
+{ return 1; }
+
+QVariant OverviewModel::data(const QModelIndex &index, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ QString name = _overview.prettyName(symbol->name());
+ if (name.isEmpty())
+ name = QLatin1String("anonymous");
+ if (! symbol->isScopedSymbol() || symbol->isFunction()) {
+ QString type = _overview.prettyType(symbol->type());
+ if (! type.isEmpty()) {
+ if (! symbol->type()->isFunction())
+ name += QLatin1String(": ");
+ name += type;
+ }
+ }
+ return name;
+ }
+
+ case Qt::EditRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ QString name = _overview.prettyName(symbol->name());
+ if (name.isEmpty())
+ name = QLatin1String("anonymous");
+ return name;
+ }
+
+ case Qt::DecorationRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ return _icons.iconForSymbol(symbol);
+ } break;
+
+ case FileNameRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ return QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
+ }
+
+ case LineNumberRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ return symbol->line();
+ }
+
+ default:
+ return QVariant();
+ } // switch
+}
+
+Symbol *OverviewModel::symbolFromIndex(const QModelIndex &index) const
+{ return static_cast<Symbol *>(index.internalPointer()); }
+
+void OverviewModel::rebuild(Document::Ptr doc)
+{
+ _cppDocument = doc;
+ reset();
+}
diff --git a/src/libs/cplusplus/OverviewModel.h b/src/libs/cplusplus/OverviewModel.h
new file mode 100644
index 0000000000..9ff920487b
--- /dev/null
+++ b/src/libs/cplusplus/OverviewModel.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_OVERVIEWMODEL_H
+#define CPLUSPLUS_OVERVIEWMODEL_H
+
+#include "CppDocument.h"
+#include "Overview.h"
+#include "Icons.h"
+
+#include <QAbstractItemModel>
+#include <QIcon>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT OverviewModel: public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ enum Role {
+ FileNameRole = Qt::UserRole + 1,
+ LineNumberRole
+ };
+
+public:
+ OverviewModel(QObject *parent = 0);
+ virtual ~OverviewModel();
+
+ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ virtual QModelIndex parent(const QModelIndex &child) const;
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ Document::Ptr document() const;
+ Symbol *symbolFromIndex(const QModelIndex &index) const;
+
+public Q_SLOTS:
+ void rebuild(CPlusPlus::Document::Ptr doc);
+
+private:
+ bool hasDocument() const;
+ unsigned globalSymbolCount() const;
+ Symbol *globalSymbolAt(unsigned index) const;
+
+private:
+ Document::Ptr _cppDocument;
+ Overview _overview;
+ Icons _icons;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_OVERVIEWMODEL_H
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
new file mode 100644
index 0000000000..6071f235c4
--- /dev/null
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -0,0 +1,793 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "ResolveExpression.h"
+#include "LookupContext.h"
+#include "Overview.h"
+
+#include <Control.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Names.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <CoreTypes.h>
+#include <TypeVisitor.h>
+#include <NameVisitor.h>
+#include <QList>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+namespace {
+
+typedef QList< QPair<Name *, FullySpecifiedType> > Substitution;
+
+class Instantiation: protected TypeVisitor, protected NameVisitor
+{
+ Control *_control;
+ FullySpecifiedType _type;
+ const Substitution _substitution;
+
+public:
+ Instantiation(Control *control, const Substitution &substitution)
+ : _control(control),
+ _substitution(substitution)
+ { }
+
+ FullySpecifiedType operator()(const FullySpecifiedType &ty)
+ { return subst(ty); }
+
+protected:
+ FullySpecifiedType subst(Name *name)
+ {
+ for (int i = 0; i < _substitution.size(); ++i) {
+ const QPair<Name *, FullySpecifiedType> s = _substitution.at(i);
+ if (name->isEqualTo(s.first))
+ return s.second;
+ }
+
+ return _control->namedType(name);
+ }
+
+ FullySpecifiedType subst(const FullySpecifiedType &ty)
+ {
+ FullySpecifiedType previousType = switchType(ty);
+ TypeVisitor::accept(ty.type());
+ return switchType(previousType);
+ }
+
+ FullySpecifiedType switchType(const FullySpecifiedType &type)
+ {
+ FullySpecifiedType previousType = _type;
+ _type = type;
+ return previousType;
+ }
+
+ // types
+ virtual void visit(PointerToMemberType * /*ty*/)
+ {
+ Q_ASSERT(0);
+ }
+
+ virtual void visit(PointerType *ty)
+ {
+ FullySpecifiedType elementType = subst(ty->elementType());
+ _type.setType(_control->pointerType(elementType));
+ }
+
+ virtual void visit(ReferenceType *ty)
+ {
+ FullySpecifiedType elementType = subst(ty->elementType());
+ _type.setType(_control->referenceType(elementType));
+ }
+
+ virtual void visit(ArrayType *ty)
+ {
+ FullySpecifiedType elementType = subst(ty->elementType());
+ _type.setType(_control->arrayType(elementType, ty->size()));
+ }
+
+ virtual void visit(NamedType *ty)
+ { _type.setType(subst(ty->name()).type()); } // ### merge the specifiers
+
+ virtual void visit(Function *ty)
+ {
+ Name *name = ty->name();
+ FullySpecifiedType returnType = subst(ty->returnType());
+
+ Function *fun = _control->newFunction(0, name);
+ fun->setScope(ty->scope());
+ fun->setReturnType(returnType);
+ for (unsigned i = 0; i < ty->argumentCount(); ++i) {
+ Symbol *arg = ty->argumentAt(i);
+ FullySpecifiedType argTy = subst(arg->type());
+ Argument *newArg = _control->newArgument(0, arg->name());
+ newArg->setType(argTy);
+ fun->arguments()->enterSymbol(newArg);
+ }
+ _type.setType(fun);
+ }
+
+ virtual void visit(VoidType *)
+ { /* nothing to do*/ }
+
+ virtual void visit(IntegerType *)
+ { /* nothing to do*/ }
+
+ virtual void visit(FloatType *)
+ { /* nothing to do*/ }
+
+ virtual void visit(Namespace *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(Class *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(Enum *)
+ { Q_ASSERT(0); }
+
+ // names
+ virtual void visit(NameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(TemplateNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(DestructorNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(OperatorNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(ConversionNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(QualifiedNameId *)
+ { Q_ASSERT(0); }
+};
+
+} // end of anonymous namespace
+
+/////////////////////////////////////////////////////////////////////
+// ResolveExpression
+/////////////////////////////////////////////////////////////////////
+ResolveExpression::ResolveExpression(const LookupContext &context)
+ : ASTVisitor(context.expressionDocument()->control()),
+ _context(context),
+ sem(_context.control())
+{ }
+
+ResolveExpression::~ResolveExpression()
+{ }
+
+QList<ResolveExpression::Result> ResolveExpression::operator()(ExpressionAST *ast)
+{
+ const QList<Result> previousResults = switchResults(QList<Result>());
+ accept(ast);
+ return switchResults(previousResults);
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::switchResults(const QList<ResolveExpression::Result> &results)
+{
+ const QList<Result> previousResults = _results;
+ _results = results;
+ return previousResults;
+}
+
+void ResolveExpression::addResults(const QList<Result> &results)
+{
+ foreach (const Result r, results)
+ addResult(r);
+}
+
+void ResolveExpression::addResult(const FullySpecifiedType &ty, Symbol *symbol)
+{ return addResult(Result(ty, symbol)); }
+
+void ResolveExpression::addResult(const Result &r)
+{
+ Result p = r;
+ if (! p.second)
+ p.second = _context.symbol();
+
+ if (! _results.contains(p))
+ _results.append(p);
+}
+
+QList<Scope *> ResolveExpression::visibleScopes(const Result &result) const
+{ return _context.visibleScopes(result); }
+
+bool ResolveExpression::visit(ExpressionListAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(BinaryExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CastExpressionAST *ast)
+{
+ Scope dummy;
+ addResult(sem.check(ast->type_id, &dummy));
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionalExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CppCastExpressionAST *ast)
+{
+ Scope dummy;
+ addResult(sem.check(ast->type_id, &dummy));
+ return false;
+}
+
+bool ResolveExpression::visit(DeleteExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayInitializerAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(NewExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(TypeidExpressionAST *)
+{
+ Name *std_type_info[2];
+ std_type_info[0] = control()->nameId(control()->findOrInsertIdentifier("std"));
+ std_type_info[1] = control()->nameId(control()->findOrInsertIdentifier("type_info"));
+
+ Name *q = control()->qualifiedNameId(std_type_info, 2, /*global=*/ true);
+ FullySpecifiedType ty(control()->namedType(q));
+ addResult(ty);
+
+ return false;
+}
+
+bool ResolveExpression::visit(TypenameCallExpressionAST *)
+{
+ // nothing to do
+ return false;
+}
+
+bool ResolveExpression::visit(TypeConstructorCallAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(PostfixExpressionAST *ast)
+{
+ accept(ast->base_expression);
+
+ for (PostfixAST *fx = ast->postfix_expressions; fx; fx = fx->next) {
+ accept(fx);
+ }
+
+ return false;
+}
+
+bool ResolveExpression::visit(SizeofExpressionAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Int));
+ ty.setUnsigned(true);
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(NumericLiteralAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Int));
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(BoolLiteralAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Bool));
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(ThisExpressionAST *)
+{
+ if (! _context.symbol())
+ return false;
+
+ Scope *scope = _context.symbol()->scope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->isFunctionScope()) {
+ Function *fun = scope->owner()->asFunction();
+ if (Scope *cscope = scope->enclosingClassScope()) {
+ Class *klass = cscope->owner()->asClass();
+ FullySpecifiedType classTy(control()->namedType(klass->name()));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ addResult(ptrTy, fun);
+ break;
+ } else if (QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
+ Name *nestedNameSpecifier = 0;
+ if (q->nameCount() == 1 && q->isGlobal())
+ nestedNameSpecifier = q->nameAt(0);
+ else
+ nestedNameSpecifier = control()->qualifiedNameId(q->names(), q->nameCount() - 1);
+ FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ addResult(ptrTy, fun);
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(NestedExpressionAST *ast)
+{
+ accept(ast->expression);
+ return false;
+}
+
+bool ResolveExpression::visit(StringLiteralAST *)
+{
+ FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
+ charTy.setConst(true);
+ FullySpecifiedType ty(control()->pointerType(charTy));
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(ThrowExpressionAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(TypeIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(UnaryExpressionAST *ast)
+{
+ accept(ast->expression);
+ unsigned unaryOp = tokenKind(ast->unary_op_token);
+ if (unaryOp == T_AMPER) {
+ QMutableListIterator<Result > it(_results);
+ while (it.hasNext()) {
+ Result p = it.next();
+ p.first.setType(control()->pointerType(p.first));
+ it.setValue(p);
+ }
+ } else if (unaryOp == T_STAR) {
+ QMutableListIterator<Result > it(_results);
+ while (it.hasNext()) {
+ Result p = it.next();
+ if (PointerType *ptrTy = p.first->asPointerType()) {
+ p.first = ptrTy->elementType();
+ it.setValue(p);
+ } else {
+ it.remove();
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(QualifiedNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols) {
+ if (symbol->isTypedef()) {
+ if (NamedType *namedTy = symbol->type()->asNamedType()) {
+ LookupContext symbolContext(symbol, _context);
+ QList<Symbol *> resolvedClasses = symbolContext.resolveClass(namedTy->name());
+ if (resolvedClasses.count()) {
+ foreach (Symbol *s, resolvedClasses) {
+ addResult(s->type(), s);
+ }
+ continue;
+ }
+ }
+ }
+ addResult(symbol->type(), symbol);
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(OperatorFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(ConversionFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(SimpleNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ addResult(symbol->type(), symbol);
+
+ return false;
+}
+
+bool ResolveExpression::visit(DestructorNameAST *)
+{
+ FullySpecifiedType ty(control()->voidType());
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(TemplateIdAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ addResult(symbol->type(), symbol);
+
+ return false;
+}
+
+bool ResolveExpression::visit(CallAST *ast)
+{
+ // Compute the types of the actual arguments.
+ QList< QList<Result> > arguments;
+ for (ExpressionListAST *exprIt = ast->expression_list; exprIt;
+ exprIt = exprIt->next) {
+ arguments.append(operator()(exprIt->expression));
+ }
+
+ QList<Result> baseResults = _results;
+ _results.clear();
+
+ foreach (Result p, baseResults) {
+ if (Function *funTy = p.first->asFunction()) {
+ unsigned minNumberArguments = 0;
+ for (; minNumberArguments < funTy->argumentCount(); ++minNumberArguments) {
+ Argument *arg = funTy->argumentAt(minNumberArguments)->asArgument();
+ if (arg->hasInitializer())
+ break;
+ }
+ const unsigned actualArgumentCount = arguments.count();
+ if (actualArgumentCount < minNumberArguments) {
+ // not enough arguments.
+ } else if (! funTy->isVariadic() && actualArgumentCount > funTy->argumentCount()) {
+ // too many arguments.
+ } else {
+ p.first = funTy->returnType();
+ addResult(p);
+ }
+ } else if (Class *classTy = p.first->asClass()) {
+ // Constructor call
+ p.first = control()->namedType(classTy->name());
+ addResult(p);
+ }
+ }
+
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayAccessAST *ast)
+{
+ const QList<Result> baseResults = _results;
+ _results.clear();
+
+ const QList<Result> indexResults = operator()(ast->expression);
+
+ foreach (Result p, baseResults) {
+ FullySpecifiedType ty = p.first;
+ Symbol *contextSymbol = p.second;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ addResult(ptrTy->elementType(), contextSymbol);
+ } else if (ArrayType *arrTy = ty->asArrayType()) {
+ addResult(arrTy->elementType(), contextSymbol);
+ } else if (NamedType *namedTy = ty->asNamedType()) {
+ Name *className = namedTy->name();
+ const QList<Scope *> scopes = visibleScopes(p);
+ const QList<Symbol *> classObjectCandidates = _context.resolveClass(className, scopes);
+
+ foreach (Symbol *classObject, classObjectCandidates) {
+ const QList<Result> overloads = resolveArrayOperator(p, namedTy,
+ classObject->asClass());
+ foreach (Result r, overloads) {
+ FullySpecifiedType ty = r.first;
+ Function *funTy = ty->asFunction();
+ if (! funTy)
+ continue;
+
+ ty = funTy->returnType();
+ addResult(ty, funTy);
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(MemberAccessAST *ast)
+{
+ // The candidate types for the base expression are stored in
+ // _results.
+ QList<Result> baseResults = _results;
+
+ // Evaluate the expression-id that follows the access operator.
+ Scope dummy;
+ Name *memberName = sem.check(ast->member_name, &dummy);
+
+ // Remember the access operator.
+ const unsigned accessOp = tokenKind(ast->access_token);
+
+ _results = resolveMemberExpression(baseResults, accessOp, memberName);
+
+ return false;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveMemberExpression(const QList<Result> &baseResults,
+ unsigned accessOp,
+ Name *memberName) const
+{
+ QList<Result> results;
+
+ if (accessOp == T_ARROW) {
+ foreach (Result p, baseResults) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType()) {
+ Name *className = namedTy->name();
+ const QList<Scope *> scopes = visibleScopes(p);
+ const QList<Symbol *> classObjectCandidates = _context.resolveClass(className, scopes);
+
+ foreach (Symbol *classObject, classObjectCandidates) {
+ const QList<Result> overloads = resolveArrowOperator(p, namedTy,
+ classObject->asClass());
+ foreach (Result r, overloads) {
+ FullySpecifiedType ty = r.first;
+ Function *funTy = ty->asFunction();
+ if (! funTy)
+ continue;
+
+ ty = funTy->returnType();
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType())
+ results += resolveMember(r, memberName, namedTy);
+ }
+ }
+ }
+ } else if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType())
+ results += resolveMember(p, memberName, namedTy);
+ }
+ }
+ } else if (accessOp == T_DOT) {
+ // The base expression shall be a "class object" of a complete type.
+ foreach (Result p, baseResults) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType())
+ results += resolveMember(p, memberName, namedTy);
+ else if (Function *fun = ty->asFunction()) {
+ if (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()) {
+ ty = fun->returnType();
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType())
+ results += resolveMember(p, memberName, namedTy);
+ }
+ }
+
+ }
+ }
+
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveMember(const Result &p,
+ Name *memberName,
+ NamedType *namedTy) const
+{
+ QList<Result> results;
+ Name *className = namedTy->name();
+ const QList<Scope *> scopes = visibleScopes(p);
+ const QList<Symbol *> classObjectCandidates = _context.resolveClass(className, scopes);
+ foreach (Symbol *classObject, classObjectCandidates) {
+ results += resolveMember(p, memberName, namedTy, classObject->asClass());
+ }
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveMember(const Result &,
+ Name *memberName,
+ NamedType *namedTy,
+ Class *klass) const
+{
+ QList<Scope *> scopes;
+ _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+ QList<Result> results;
+
+ QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ Name *unqualifiedNameId = namedTy->name();
+ if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId())
+ unqualifiedNameId = q->unqualifiedNameId();
+ if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+
+ const Result result(ty, candidate);
+ if (! results.contains(result))
+ results.append(result);
+ }
+
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveArrowOperator(const Result &,
+ NamedType *namedTy,
+ Class *klass) const
+{
+ QList<Scope *> scopes;
+ _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+ QList<Result> results;
+
+ Name *memberName = control()->operatorNameId(OperatorNameId::ArrowOp);
+ QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ Name *unqualifiedNameId = namedTy->name();
+ if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId())
+ unqualifiedNameId = q->unqualifiedNameId();
+ if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+
+ const Result result(ty, candidate);
+ if (! results.contains(result))
+ results.append(result);
+ }
+
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveArrayOperator(const Result &,
+ NamedType *namedTy,
+ Class *klass) const
+{
+ // ### todo handle index expressions.
+
+ QList<Scope *> scopes;
+ _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+ QList<Result> results;
+
+ Name *memberName = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
+ QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ Name *unqualifiedNameId = namedTy->name();
+ if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId())
+ unqualifiedNameId = q->unqualifiedNameId();
+ if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+
+ const Result result(ty, candidate);
+ if (! results.contains(result))
+ results.append(result);
+ }
+
+ return results;
+}
+
+bool ResolveExpression::visit(PostIncrDecrAST *)
+{
+ return false;
+}
diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h
new file mode 100644
index 0000000000..75963bb2fe
--- /dev/null
+++ b/src/libs/cplusplus/ResolveExpression.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_RESOLVEEXPRESSION_H
+#define CPLUSPLUS_RESOLVEEXPRESSION_H
+
+#include "LookupContext.h"
+#include <ASTVisitor.h>
+#include <Semantic.h>
+#include <FullySpecifiedType.h>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT ResolveExpression: protected ASTVisitor
+{
+public:
+ typedef QPair<FullySpecifiedType, Symbol *> Result;
+
+public:
+ ResolveExpression(const LookupContext &context);
+ virtual ~ResolveExpression();
+
+ QList<Result> operator()(ExpressionAST *ast);
+
+ QList<Result> resolveMemberExpression(const QList<Result> &baseResults,
+ unsigned accessOp,
+ Name *memberName) const;
+
+ QList<Result> resolveMember(const Result &result,
+ Name *memberName,
+ NamedType *namedTy) const;
+
+ QList<Result> resolveMember(const Result &result,
+ Name *memberName,
+ NamedType *namedTy,
+ Class *klass) const;
+
+ QList<Result> resolveArrowOperator(const Result &result,
+ NamedType *namedTy,
+ Class *klass) const;
+
+ QList<Result> resolveArrayOperator(const Result &result,
+ NamedType *namedTy,
+ Class *klass) const;
+
+protected:
+ QList<Result> switchResults(const QList<Result> &symbols);
+
+ void addResult(const FullySpecifiedType &ty, Symbol *symbol = 0);
+ void addResult(const Result &result);
+ void addResults(const QList<Result> &results);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+
+ //names
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+ // postfix expressions
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+
+ QList<Scope *> visibleScopes(const Result &result) const;
+
+private:
+ LookupContext _context;
+ Semantic sem;
+ QList<Result> _results;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_RESOLVEEXPRESSION_H
diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp
new file mode 100644
index 0000000000..f047d540c9
--- /dev/null
+++ b/src/libs/cplusplus/SimpleLexer.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "SimpleLexer.h"
+#include <Lexer.h>
+#include <Token.h>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+bool SimpleToken::isLiteral() const
+{ return _kind >= T_FIRST_LITERAL && _kind <= T_LAST_LITERAL; }
+
+bool SimpleToken::isOperator() const
+{ return _kind >= T_FIRST_OPERATOR && _kind <= T_LAST_OPERATOR; }
+
+bool SimpleToken::isKeyword() const
+{ return _kind >= T_FIRST_KEYWORD && _kind < T_FIRST_QT_KEYWORD; }
+
+SimpleLexer::SimpleLexer()
+ : _lastState(0),
+ _skipComments(false),
+ _qtMocRunEnabled(true)
+{ }
+
+SimpleLexer::~SimpleLexer()
+{ }
+
+bool SimpleLexer::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void SimpleLexer::setQtMocRunEnabled(bool enabled)
+{ _qtMocRunEnabled = enabled; }
+
+bool SimpleLexer::skipComments() const
+{ return _skipComments; }
+
+void SimpleLexer::setSkipComments(bool skipComments)
+{ _skipComments = skipComments; }
+
+QList<SimpleToken> SimpleLexer::operator()(const QString &text, int state)
+{
+ QList<SimpleToken> tokens;
+
+ const QByteArray bytes = text.toLatin1();
+ const char *firstChar = bytes.constData();
+ const char *lastChar = firstChar + bytes.size();
+
+ Lexer lex(firstChar, lastChar);
+ lex.setQtMocRunEnabled(_qtMocRunEnabled);
+
+ if (! _skipComments)
+ lex.setScanCommentTokens(true);
+
+ if (state != -1)
+ lex.setState(state & 0xff);
+
+ bool inPreproc = false;
+
+ for (;;) {
+ Token tk;
+ lex(&tk);
+ if (tk.is(T_EOF_SYMBOL))
+ break;
+
+ SimpleToken simpleTk;
+ simpleTk._kind = int(tk.kind);
+ simpleTk._position = int(lex.tokenOffset());
+ simpleTk._length = int(lex.tokenLength());
+ simpleTk._text = text.midRef(simpleTk._position, simpleTk._length);
+
+ lex.setScanAngleStringLiteralTokens(false);
+
+ if (tk.newline && tk.is(T_POUND))
+ inPreproc = true;
+ else if (inPreproc && tokens.size() == 1 && simpleTk.is(T_IDENTIFIER) &&
+ simpleTk.text() == QLatin1String("include"))
+ lex.setScanAngleStringLiteralTokens(true);
+
+ tokens.append(simpleTk);
+ }
+
+ _lastState = lex.state();
+ return tokens;
+}
+
+
diff --git a/src/libs/cplusplus/SimpleLexer.h b/src/libs/cplusplus/SimpleLexer.h
new file mode 100644
index 0000000000..9bbba41950
--- /dev/null
+++ b/src/libs/cplusplus/SimpleLexer.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SIMPLELEXER_H
+#define SIMPLELEXER_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <QString>
+#include <QList>
+
+namespace CPlusPlus {
+
+class SimpleLexer;
+
+class CPLUSPLUS_EXPORT SimpleToken
+{
+public:
+ SimpleToken()
+ : _kind(0),
+ _position(0),
+ _length(0)
+ { }
+
+ inline int kind() const
+ { return _kind; }
+
+ inline int position() const
+ { return _position; }
+
+ inline int length() const
+ { return _length; }
+
+ inline QStringRef text() const
+ { return _text; }
+
+ inline bool is(int k) const { return _kind == k; }
+ inline bool isNot(int k) const { return _kind != k; }
+
+ bool isLiteral() const;
+ bool isOperator() const;
+ bool isKeyword() const;
+
+public:
+ int _kind;
+ int _position;
+ int _length;
+ QStringRef _text;
+
+ friend class SimpleLexer;
+};
+
+class CPLUSPLUS_EXPORT SimpleLexer
+{
+public:
+ SimpleLexer();
+ ~SimpleLexer();
+
+ bool skipComments() const;
+ void setSkipComments(bool skipComments);
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool enabled);
+
+ QList<SimpleToken> operator()(const QString &text, int state = 0);
+
+ int state() const
+ { return _lastState; }
+
+private:
+ int _lastState;
+ bool _skipComments: 1;
+ bool _qtMocRunEnabled: 1;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // SIMPLELEXER_H
diff --git a/src/libs/cplusplus/TokenUnderCursor.cpp b/src/libs/cplusplus/TokenUnderCursor.cpp
new file mode 100644
index 0000000000..84a1992244
--- /dev/null
+++ b/src/libs/cplusplus/TokenUnderCursor.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "TokenUnderCursor.h"
+#include <Token.h>
+
+#include <QTextCursor>
+#include <QTextBlock>
+#include <climits>
+
+using namespace CPlusPlus;
+
+TokenUnderCursor::TokenUnderCursor()
+{ }
+
+TokenUnderCursor::~TokenUnderCursor()
+{ }
+
+SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor) const
+{
+ SimpleLexer tokenize;
+ QTextBlock block = cursor.block();
+ int column = cursor.columnNumber();
+
+ QList<SimpleToken> tokens = tokenize(block.text(), previousBlockState(block));
+ for (int index = tokens.size() - 1; index != -1; --index) {
+ const SimpleToken &tk = tokens.at(index);
+ if (tk.position() < column)
+ return tk;
+ }
+
+ return SimpleToken();
+}
+
+int TokenUnderCursor::previousBlockState(const QTextBlock &block) const
+{
+ const QTextBlock prevBlock = block.previous();
+ if (prevBlock.isValid()) {
+ int state = prevBlock.userState();
+
+ if (state != -1)
+ return state;
+ }
+ return 0;
+}
diff --git a/src/libs/cplusplus/TokenUnderCursor.h b/src/libs/cplusplus/TokenUnderCursor.h
new file mode 100644
index 0000000000..cd08833d21
--- /dev/null
+++ b/src/libs/cplusplus/TokenUnderCursor.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TOKENUNDERCURSOR_H
+#define TOKENUNDERCURSOR_H
+
+#include "SimpleLexer.h"
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QTextCursor;
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace CPlusPlus {
+
+class SimpleToken;
+
+class CPLUSPLUS_EXPORT TokenUnderCursor
+{
+public:
+ TokenUnderCursor();
+ ~TokenUnderCursor();
+
+ SimpleToken operator()(const QTextCursor &cursor) const;
+
+private:
+ int previousBlockState(const QTextBlock &block) const;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // TOKENUNDERCURSOR_H
diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp
new file mode 100644
index 0000000000..f6ad3bdc53
--- /dev/null
+++ b/src/libs/cplusplus/TypeOfExpression.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "TypeOfExpression.h"
+
+#include <AST.h>
+#include <TranslationUnit.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/ResolveExpression.h>
+
+using namespace CPlusPlus;
+
+TypeOfExpression::TypeOfExpression():
+ m_ast(0)
+{
+}
+
+void TypeOfExpression::setDocuments(const QMap<QString, Document::Ptr> &documents)
+{
+ m_documents = documents;
+}
+
+QList<TypeOfExpression::Result> TypeOfExpression::operator()(const QString &expression,
+ Document::Ptr document,
+ Symbol *lastVisibleSymbol)
+{
+ Document::Ptr expressionDoc = documentForExpression(expression);
+ m_ast = extractExpressionAST(expressionDoc);
+
+ m_lookupContext = LookupContext(lastVisibleSymbol, expressionDoc,
+ document, m_documents);
+
+ ResolveExpression resolveExpression(m_lookupContext);
+ return resolveExpression(m_ast);
+}
+
+ExpressionAST *TypeOfExpression::ast() const
+{
+ return m_ast;
+}
+
+const LookupContext &TypeOfExpression::lookupContext() const
+{
+ return m_lookupContext;
+}
+
+ExpressionAST *TypeOfExpression::expressionAST() const
+{
+ return extractExpressionAST(m_lookupContext.expressionDocument());
+}
+
+ExpressionAST *TypeOfExpression::extractExpressionAST(Document::Ptr doc) const
+{
+ TranslationUnitAST *translationUnitAST = doc->translationUnit()->ast();
+
+ // ### evaluate the expression
+ ExpressionAST *expressionAST = 0;
+ if (translationUnitAST) {
+ DeclarationAST *declaration = translationUnitAST->declarations;
+ SimpleDeclarationAST *simpleDecl = 0;
+ if (declaration)
+ simpleDecl = declaration->asSimpleDeclaration();
+ if (simpleDecl && simpleDecl->decl_specifier_seq) {
+ if (TypeofSpecifierAST *typeOfSpec = simpleDecl->decl_specifier_seq->asTypeofSpecifier())
+ expressionAST = typeOfSpec->expression;
+ }
+ }
+ return expressionAST;
+}
+
+Document::Ptr TypeOfExpression::documentForExpression(const QString &expression) const
+{
+ // create a __typeof__ specifier
+ QByteArray declaration;
+ declaration += "__typeof__ ";
+ declaration += expression.toLatin1(); // C++ code needs to be in latin1
+ declaration += ";";
+
+ // create the expression's AST.
+ Document::Ptr doc = Document::create(QLatin1String("<completion>"));
+ doc->setSource(declaration);
+ doc->parse();
+ return doc;
+}
diff --git a/src/libs/cplusplus/TypeOfExpression.h b/src/libs/cplusplus/TypeOfExpression.h
new file mode 100644
index 0000000000..87df28f1ba
--- /dev/null
+++ b/src/libs/cplusplus/TypeOfExpression.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPLUSPLUS_TYPEOFEXPRESSION_H
+#define CPLUSPLUS_TYPEOFEXPRESSION_H
+
+#include <ASTfwd.h>
+#include <cplusplus/CppDocument.h>
+#include <cplusplus/LookupContext.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT TypeOfExpression
+{
+public:
+ typedef QPair<FullySpecifiedType, Symbol *> Result;
+
+public:
+ TypeOfExpression();
+
+ /**
+ * Sets the documents used to evaluate expressions. Should be set before
+ * calling this functor.
+ */
+ void setDocuments(const QMap<QString, Document::Ptr> &documents);
+
+ /**
+ * Returns a list of possible fully specified types associated with the
+ * given expression.
+ *
+ * NOTE: The fully specified types only stay valid for as long as this
+ * expression evaluator instance still exists, and no new call to evaluate
+ * 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.
+ */
+ QList<Result> operator()(const QString &expression, Document::Ptr document,
+ Symbol *lastVisibleSymbol);
+
+ /**
+ * Returns the AST of the last evaluated expression.
+ */
+ ExpressionAST *ast() const;
+
+ /**
+ * Returns the lookup context of the last evaluated expression.
+ */
+ const LookupContext &lookupContext() const;
+
+ ExpressionAST *expressionAST() const;
+
+private:
+ ExpressionAST *extractExpressionAST(Document::Ptr doc) const;
+ Document::Ptr documentForExpression(const QString &expression) const;
+
+ QMap<QString, Document::Ptr> m_documents;
+ ExpressionAST *m_ast;
+ LookupContext m_lookupContext;
+};
+
+} // namespace CPlusPlus
+
+#endif // CPLUSPLUS_TYPEOFEXPRESSION_H
diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp
new file mode 100644
index 0000000000..3301a8c8d1
--- /dev/null
+++ b/src/libs/cplusplus/TypePrettyPrinter.cpp
@@ -0,0 +1,309 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "Overview.h"
+#include "TypePrettyPrinter.h"
+#include <FullySpecifiedType.h>
+#include <CoreTypes.h>
+#include <Symbols.h>
+#include <Scope.h>
+
+using namespace CPlusPlus;
+
+TypePrettyPrinter::TypePrettyPrinter(const Overview *overview)
+ : _overview(overview),
+ _name(0),
+ _markArgument(0),
+ _showArgumentNames(false),
+ _showReturnTypes(false),
+ _showFunctionSignatures(true)
+{ }
+
+TypePrettyPrinter::~TypePrettyPrinter()
+{ }
+
+bool TypePrettyPrinter::showArgumentNames() const
+{ return _showArgumentNames; }
+
+void TypePrettyPrinter::setShowArgumentNames(bool showArgumentNames)
+{ _showArgumentNames = showArgumentNames; }
+
+bool TypePrettyPrinter::showReturnTypes() const
+{ return _showReturnTypes; }
+
+void TypePrettyPrinter::setShowReturnTypes(bool showReturnTypes)
+{ _showReturnTypes = showReturnTypes; }
+
+bool TypePrettyPrinter::showFunctionSignatures() const
+{ return _showFunctionSignatures; }
+
+void TypePrettyPrinter::setShowFunctionSignatures(bool showFunctionSignatures)
+{ _showFunctionSignatures = showFunctionSignatures; }
+
+void TypePrettyPrinter::setMarkArgument(unsigned position)
+{ _markArgument = position; }
+
+const Overview *TypePrettyPrinter::overview() const
+{ return _overview; }
+
+QString TypePrettyPrinter::operator()(const FullySpecifiedType &ty)
+{
+ QString previousName = switchText();
+ acceptType(ty);
+ return switchText(previousName).trimmed();
+}
+
+QString TypePrettyPrinter::operator()(const FullySpecifiedType &type, const QString &name)
+{
+ QString previousName = switchName(name);
+ QString text = operator()(type);
+ if (! _name.isEmpty() && ! text.isEmpty()) {
+ QChar ch = text.at(text.size() - 1);
+ if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
+ text += QLatin1Char(' ');
+ text += _name;
+ }
+ (void) switchName(previousName);
+ return text;
+}
+
+
+void TypePrettyPrinter::acceptType(const FullySpecifiedType &ty)
+{
+ if (ty.isConst())
+ _text += QLatin1String("const ");
+ if (ty.isVolatile())
+ _text += QLatin1String("volatile ");
+ if (ty.isSigned())
+ _text += QLatin1String("signed ");
+ if (ty.isUnsigned())
+ _text += QLatin1String("unsigned ");
+ accept(ty.type());
+}
+
+QString TypePrettyPrinter::switchName(const QString &name)
+{
+ const QString previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+QString TypePrettyPrinter::switchText(const QString &name)
+{
+ QString previousName = _text;
+ _text = name;
+ return previousName;
+}
+
+QList<Type *> TypePrettyPrinter::switchPtrOperators(const QList<Type *> &ptrOperators)
+{
+ QList<Type *> previousPtrOperators = _ptrOperators;
+ _ptrOperators = ptrOperators;
+ return previousPtrOperators;
+}
+
+void TypePrettyPrinter::applyPtrOperators(bool wantSpace)
+{
+ for (int i = _ptrOperators.size() - 1; i != -1; --i) {
+ Type *op = _ptrOperators.at(i);
+
+ if (i == 0 && wantSpace)
+ _text += QLatin1Char(' ');
+
+ if (PointerType *ptrTy = op->asPointerType()) {
+ _text += QLatin1Char('*');
+ if (ptrTy->elementType().isConst())
+ _text += " const";
+ if (ptrTy->elementType().isVolatile())
+ _text += " volatile";
+ } else if (op->isReferenceType()) {
+ _text += QLatin1Char('&');
+ } else if (PointerToMemberType *memPtrTy = op->asPointerToMemberType()) {
+ _text += QLatin1Char(' ');
+ _text += _overview->prettyName(memPtrTy->memberName());
+ _text += QLatin1Char('*');
+ }
+ }
+}
+
+void TypePrettyPrinter::visit(VoidType *)
+{
+ _text += QLatin1String("void");
+
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(IntegerType *type)
+{
+ switch (type->kind()) {
+ case IntegerType::Char:
+ _text += QLatin1String("char");
+ break;
+ case IntegerType::WideChar:
+ _text += QLatin1String("wchar_t");
+ break;
+ case IntegerType::Bool:
+ _text += QLatin1String("bool");
+ break;
+ case IntegerType::Short:
+ _text += QLatin1String("short");
+ break;
+ case IntegerType::Int:
+ _text += QLatin1String("int");
+ break;
+ case IntegerType::Long:
+ _text += QLatin1String("long");
+ break;
+ case IntegerType::LongLong:
+ _text += QLatin1String("long long");
+ break;
+ }
+
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(FloatType *type)
+{
+ switch (type->kind()) {
+ case FloatType::Float:
+ _text += QLatin1String("float");
+ break;
+ case FloatType::Double:
+ _text += QLatin1String("double");
+ break;
+ case FloatType::LongDouble:
+ _text += QLatin1String("long double");
+ break;
+ }
+
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(PointerToMemberType *type)
+{
+ _ptrOperators.append(type);
+ acceptType(type->elementType());
+}
+
+void TypePrettyPrinter::visit(PointerType *type)
+{
+ _ptrOperators.append(type);
+ acceptType(type->elementType());
+}
+
+void TypePrettyPrinter::visit(ReferenceType *type)
+{
+ _ptrOperators.append(type);
+ acceptType(type->elementType());
+}
+
+void TypePrettyPrinter::visit(ArrayType *type)
+{
+ _text += overview()->prettyType(type->elementType());
+ if (! _ptrOperators.isEmpty()) {
+ _text += QLatin1Char('(');
+ applyPtrOperators(false);
+ if (! _name.isEmpty()) {
+ _text += _name;
+ _name.clear();
+ }
+ _text += QLatin1Char(')');
+ }
+ _text += QLatin1String("[]");
+}
+
+void TypePrettyPrinter::visit(NamedType *type)
+{
+ _text += overview()->prettyName(type->name());
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(Function *type)
+{
+ if (_showReturnTypes)
+ _text += _overview->prettyType(type->returnType());
+
+ if (! _ptrOperators.isEmpty()) {
+ _text += QLatin1Char('(');
+ applyPtrOperators(false);
+ if (! _name.isEmpty()) {
+ _text += _name;
+ _name.clear();
+ }
+ _text += QLatin1Char(')');
+ } else if (! _name.isEmpty() && _showFunctionSignatures) {
+ _text += QLatin1Char(' '); // ### fixme
+ _text += _name;
+ _name.clear();
+ }
+
+ if (_showFunctionSignatures) {
+ Overview argumentText;
+ _text += QLatin1Char('(');
+ for (unsigned index = 0; index < type->argumentCount(); ++index) {
+ if (index != 0)
+ _text += QLatin1String(", ");
+
+ if (Argument *arg = type->argumentAt(index)->asArgument()) {
+ if (index + 1 == _markArgument)
+ _text += QLatin1String("<b>");
+ Name *name = 0;
+ if (_showArgumentNames)
+ name = arg->name();
+ _text += argumentText(arg->type(), name);
+ if (index + 1 == _markArgument)
+ _text += QLatin1String("</b>");
+ }
+ }
+
+ if (type->isVariadic())
+ _text += QLatin1String("...");
+
+ _text += QLatin1Char(')');
+
+ if (type->isConst())
+ _text += QLatin1String(" const");
+
+ if (type->isVolatile())
+ _text += QLatin1String(" volatile");
+ }
+}
+
+void TypePrettyPrinter::visit(Namespace *type)
+{ _text += overview()->prettyName(type->name()); }
+
+void TypePrettyPrinter::visit(Class *type)
+{ _text += overview()->prettyName(type->name()); }
+
+void TypePrettyPrinter::visit(Enum *type)
+{ _text += overview()->prettyName(type->name()); }
diff --git a/src/libs/cplusplus/TypePrettyPrinter.h b/src/libs/cplusplus/TypePrettyPrinter.h
new file mode 100644
index 0000000000..fd00338184
--- /dev/null
+++ b/src/libs/cplusplus/TypePrettyPrinter.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TYPEPRETTYPRINTER_H
+#define TYPEPRETTYPRINTER_H
+
+#include "TypeVisitor.h"
+#include <QString>
+#include <QList>
+
+namespace CPlusPlus {
+
+class Overview;
+class FullySpecifiedType;
+
+class CPLUSPLUS_EXPORT TypePrettyPrinter: protected TypeVisitor
+{
+public:
+ TypePrettyPrinter(const Overview *overview);
+ virtual ~TypePrettyPrinter();
+
+ const Overview *overview() const;
+
+ bool showArgumentNames() const;
+ void setShowArgumentNames(bool showArgumentNames);
+
+ bool showReturnTypes() const;
+ void setShowReturnTypes(bool showReturnTypes);
+
+ bool showFunctionSignatures() const;
+ void setShowFunctionSignatures(bool showFunctionSignatures);
+
+ void setMarkArgument(unsigned position); // 1-based
+
+ QString operator()(const FullySpecifiedType &type);
+ QString operator()(const FullySpecifiedType &type, const QString &name);
+
+protected:
+ QString switchText(const QString &text = QString());
+ QList<Type *> switchPtrOperators(const QList<Type *> &ptrOperators);
+ QString switchName(const QString &name);
+
+ void applyPtrOperators(bool wantSpace = true);
+ void acceptType(const FullySpecifiedType &ty);
+
+ virtual void visit(VoidType *type);
+ virtual void visit(IntegerType *type);
+ virtual void visit(FloatType *type);
+ virtual void visit(PointerToMemberType *type);
+ virtual void visit(PointerType *type);
+ virtual void visit(ReferenceType *type);
+ virtual void visit(ArrayType *type);
+ virtual void visit(NamedType *type);
+ virtual void visit(Function *type);
+ virtual void visit(Namespace *type);
+ virtual void visit(Class *type);
+ virtual void visit(Enum *type);
+
+private:
+ const Overview *_overview;
+ QString _name;
+ QString _text;
+ QList<Type *> _ptrOperators;
+ unsigned _markArgument;
+ bool _showArgumentNames: 1;
+ bool _showReturnTypes: 1;
+ bool _showFunctionSignatures: 1;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // TYPEPRETTYPRINTER_H
diff --git a/src/libs/cplusplus/cplusplus.pri b/src/libs/cplusplus/cplusplus.pri
new file mode 100644
index 0000000000..e2d0f6f033
--- /dev/null
+++ b/src/libs/cplusplus/cplusplus.pri
@@ -0,0 +1,3 @@
+INCLUDEPATH += $$PWD/../../../shared/cplusplus
+DEFINES += HAVE_QT CPLUSPLUS_WITH_NAMESPACE
+LIBS *= -l$$qtLibraryTarget(CPlusPlus)
diff --git a/src/libs/cplusplus/cplusplus.pro b/src/libs/cplusplus/cplusplus.pro
new file mode 100644
index 0000000000..1a2b532662
--- /dev/null
+++ b/src/libs/cplusplus/cplusplus.pro
@@ -0,0 +1,40 @@
+TEMPLATE = lib
+
+TARGET = CPlusPlus
+
+DEFINES += HAVE_QT CPLUSPLUS_WITH_NAMESPACE CPLUSPLUS_BUILD_LIB
+DEFINES += NDEBUG
+unix:QMAKE_CXXFLAGS_DEBUG += -O3
+
+include(../../qworkbenchlibrary.pri)
+include(../../../shared/cplusplus/cplusplus.pri)
+
+HEADERS += \
+ SimpleLexer.h \
+ ExpressionUnderCursor.h \
+ TokenUnderCursor.h \
+ CppDocument.h \
+ Icons.h \
+ Overview.h \
+ OverviewModel.h \
+ NamePrettyPrinter.h \
+ TypeOfExpression.h \
+ TypePrettyPrinter.h \
+ ResolveExpression.h \
+ LookupContext.h
+
+SOURCES += \
+ SimpleLexer.cpp \
+ ExpressionUnderCursor.cpp \
+ TokenUnderCursor.cpp \
+ CppDocument.cpp \
+ Icons.cpp \
+ Overview.cpp \
+ OverviewModel.cpp \
+ NamePrettyPrinter.cpp \
+ TypeOfExpression.cpp \
+ TypePrettyPrinter.cpp \
+ ResolveExpression.cpp \
+ LookupContext.cpp
+
+RESOURCES += cplusplus.qrc
diff --git a/src/libs/cplusplus/cplusplus.qrc b/src/libs/cplusplus/cplusplus.qrc
new file mode 100644
index 0000000000..73d4c6395e
--- /dev/null
+++ b/src/libs/cplusplus/cplusplus.qrc
@@ -0,0 +1,20 @@
+<RCC>
+ <qresource prefix="/codemodel" >
+ <file>images/class.png</file>
+ <file>images/enum.png</file>
+ <file>images/enumerator.png</file>
+ <file>images/func.png</file>
+ <file>images/func_priv.png</file>
+ <file>images/func_prot.png</file>
+ <file>images/keyword.png</file>
+ <file>images/macro.png</file>
+ <file>images/namespace.png</file>
+ <file>images/signal.png</file>
+ <file>images/slot.png</file>
+ <file>images/slot_priv.png</file>
+ <file>images/slot_prot.png</file>
+ <file>images/var.png</file>
+ <file>images/var_priv.png</file>
+ <file>images/var_prot.png</file>
+ </qresource>
+</RCC>
diff --git a/src/libs/cplusplus/images/class.png b/src/libs/cplusplus/images/class.png
new file mode 100644
index 0000000000..88432d2cb1
--- /dev/null
+++ b/src/libs/cplusplus/images/class.png
Binary files differ
diff --git a/src/libs/cplusplus/images/enum.png b/src/libs/cplusplus/images/enum.png
new file mode 100644
index 0000000000..42a9e83bc7
--- /dev/null
+++ b/src/libs/cplusplus/images/enum.png
Binary files differ
diff --git a/src/libs/cplusplus/images/enumerator.png b/src/libs/cplusplus/images/enumerator.png
new file mode 100644
index 0000000000..25fc49c659
--- /dev/null
+++ b/src/libs/cplusplus/images/enumerator.png
Binary files differ
diff --git a/src/libs/cplusplus/images/func.png b/src/libs/cplusplus/images/func.png
new file mode 100644
index 0000000000..e515e76e61
--- /dev/null
+++ b/src/libs/cplusplus/images/func.png
Binary files differ
diff --git a/src/libs/cplusplus/images/func_priv.png b/src/libs/cplusplus/images/func_priv.png
new file mode 100644
index 0000000000..49dda7dfea
--- /dev/null
+++ b/src/libs/cplusplus/images/func_priv.png
Binary files differ
diff --git a/src/libs/cplusplus/images/func_prot.png b/src/libs/cplusplus/images/func_prot.png
new file mode 100644
index 0000000000..f8add65e07
--- /dev/null
+++ b/src/libs/cplusplus/images/func_prot.png
Binary files differ
diff --git a/src/libs/cplusplus/images/keyword.png b/src/libs/cplusplus/images/keyword.png
new file mode 100644
index 0000000000..e5a51858d9
--- /dev/null
+++ b/src/libs/cplusplus/images/keyword.png
Binary files differ
diff --git a/src/libs/cplusplus/images/macro.png b/src/libs/cplusplus/images/macro.png
new file mode 100644
index 0000000000..53e42af63d
--- /dev/null
+++ b/src/libs/cplusplus/images/macro.png
Binary files differ
diff --git a/src/libs/cplusplus/images/namespace.png b/src/libs/cplusplus/images/namespace.png
new file mode 100644
index 0000000000..18d2941572
--- /dev/null
+++ b/src/libs/cplusplus/images/namespace.png
Binary files differ
diff --git a/src/libs/cplusplus/images/signal.png b/src/libs/cplusplus/images/signal.png
new file mode 100644
index 0000000000..a4de5dddfe
--- /dev/null
+++ b/src/libs/cplusplus/images/signal.png
Binary files differ
diff --git a/src/libs/cplusplus/images/slot.png b/src/libs/cplusplus/images/slot.png
new file mode 100644
index 0000000000..5534bbfe08
--- /dev/null
+++ b/src/libs/cplusplus/images/slot.png
Binary files differ
diff --git a/src/libs/cplusplus/images/slot_priv.png b/src/libs/cplusplus/images/slot_priv.png
new file mode 100644
index 0000000000..8f585e875d
--- /dev/null
+++ b/src/libs/cplusplus/images/slot_priv.png
Binary files differ
diff --git a/src/libs/cplusplus/images/slot_prot.png b/src/libs/cplusplus/images/slot_prot.png
new file mode 100644
index 0000000000..469e9c18d0
--- /dev/null
+++ b/src/libs/cplusplus/images/slot_prot.png
Binary files differ
diff --git a/src/libs/cplusplus/images/var.png b/src/libs/cplusplus/images/var.png
new file mode 100644
index 0000000000..089cfb45e5
--- /dev/null
+++ b/src/libs/cplusplus/images/var.png
Binary files differ
diff --git a/src/libs/cplusplus/images/var_priv.png b/src/libs/cplusplus/images/var_priv.png
new file mode 100644
index 0000000000..8c6cf64fe7
--- /dev/null
+++ b/src/libs/cplusplus/images/var_priv.png
Binary files differ
diff --git a/src/libs/cplusplus/images/var_prot.png b/src/libs/cplusplus/images/var_prot.png
new file mode 100644
index 0000000000..a7496aada0
--- /dev/null
+++ b/src/libs/cplusplus/images/var_prot.png
Binary files differ
diff --git a/src/libs/extensionsystem/ExtensionSystemInterfaces b/src/libs/extensionsystem/ExtensionSystemInterfaces
new file mode 100644
index 0000000000..527148af8e
--- /dev/null
+++ b/src/libs/extensionsystem/ExtensionSystemInterfaces
@@ -0,0 +1,6 @@
+#include "extensionsystem/pluginmanager.h"
+#include "extensionsystem/pluginspec.h"
+#include "extensionsystem/iplugin.h"
+#include "extensionsystem/pluginview.h"
+#include "extensionsystem/pluginerrorview.h"
+#include "extensionsystem/plugindetailsview.h"
diff --git a/src/libs/extensionsystem/extensionsystem.pri b/src/libs/extensionsystem/extensionsystem.pri
new file mode 100644
index 0000000000..43855eb168
--- /dev/null
+++ b/src/libs/extensionsystem/extensionsystem.pri
@@ -0,0 +1,3 @@
+include(extensionsystem_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(ExtensionSystem)
diff --git a/src/libs/extensionsystem/extensionsystem.pro b/src/libs/extensionsystem/extensionsystem.pro
new file mode 100644
index 0000000000..fb26b9c59c
--- /dev/null
+++ b/src/libs/extensionsystem/extensionsystem.pro
@@ -0,0 +1,32 @@
+TEMPLATE = lib
+TARGET = ExtensionSystem
+QT += xml
+DEFINES += EXTENSIONSYSTEM_LIBRARY
+include(../../qworkbenchlibrary.pri)
+include(extensionsystem_dependencies.pri)
+
+DEFINES += IDE_TEST_DIR=\\\"$$IDE_SOURCE_TREE\\\"
+
+HEADERS += pluginerrorview.h \
+ plugindetailsview.h \
+ iplugin.h \
+ iplugin_p.h \
+ extensionsystem_global.h \
+ pluginmanager.h \
+ pluginmanager_p.h \
+ pluginspec.h \
+ pluginspec_p.h \
+ pluginview.h \
+ pluginview_p.h \
+ optionsparser.h
+SOURCES += pluginerrorview.cpp \
+ plugindetailsview.cpp \
+ iplugin.cpp \
+ pluginmanager.cpp \
+ pluginspec.cpp \
+ pluginview.cpp \
+ optionsparser.cpp
+FORMS += pluginview.ui \
+ pluginerrorview.ui \
+ plugindetailsview.ui
+RESOURCES += pluginview.qrc
diff --git a/src/libs/extensionsystem/extensionsystem_dependencies.pri b/src/libs/extensionsystem/extensionsystem_dependencies.pri
new file mode 100644
index 0000000000..63b2e339a3
--- /dev/null
+++ b/src/libs/extensionsystem/extensionsystem_dependencies.pri
@@ -0,0 +1 @@
+include(../aggregation/aggregation.pri)
diff --git a/src/libs/extensionsystem/extensionsystem_global.h b/src/libs/extensionsystem/extensionsystem_global.h
new file mode 100644
index 0000000000..ebd1f34da2
--- /dev/null
+++ b/src/libs/extensionsystem/extensionsystem_global.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EXTENSIONSYSTEM_GLOBAL_H
+#define EXTENSIONSYSTEM_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(EXTENSIONSYSTEM_LIBRARY)
+# define EXTENSIONSYSTEM_EXPORT Q_DECL_EXPORT
+#else
+# define EXTENSIONSYSTEM_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // header
diff --git a/src/libs/extensionsystem/images/error.png b/src/libs/extensionsystem/images/error.png
new file mode 100644
index 0000000000..e2f85d98eb
--- /dev/null
+++ b/src/libs/extensionsystem/images/error.png
Binary files differ
diff --git a/src/libs/extensionsystem/images/ok.png b/src/libs/extensionsystem/images/ok.png
new file mode 100644
index 0000000000..15cd35d27b
--- /dev/null
+++ b/src/libs/extensionsystem/images/ok.png
Binary files differ
diff --git a/src/libs/extensionsystem/iplugin.cpp b/src/libs/extensionsystem/iplugin.cpp
new file mode 100644
index 0000000000..47cb702e16
--- /dev/null
+++ b/src/libs/extensionsystem/iplugin.cpp
@@ -0,0 +1,325 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "iplugin.h"
+#include "iplugin_p.h"
+#include "pluginmanager.h"
+#include "pluginspec.h"
+
+/*!
+ \class ExtensionSystem::IPlugin
+ \brief Base class for all plugins.
+
+ The IPlugin class is an abstract class that must be implemented
+ once for each plugin.
+ A plugin consists of two parts: A description file, and a library
+ that at least contains the IPlugin implementation.
+
+ \tableofcontents
+
+ \section1 Plugin Specification
+ The plugin specification file is an xml file that contains all
+ information that are necessary for loading the plugin's library,
+ plus some textual descriptions. The file must be located in
+ (a subdir of) one of the plugin manager's plugin search paths,
+ and must have the \c .xml extension.
+
+ \section2 Main Tag
+ The root tag is \c plugin. It has mandatory attributes \c name
+ and \c version, and an optional \c compatVersion.
+ \table
+ \header
+ \o Tag
+ \o Meaning
+ \row
+ \o plugin
+ \o Root element in a plugin's xml file.
+ \endtable
+ \table
+ \header
+ \o Attribute
+ \o Meaning
+ \row
+ \o name
+ \o This is used as an identifier for the plugin and can e.g.
+ be referenced in other plugin's dependencies. It is
+ also used to construct the name of the plugin library
+ as \c lib[name].[dll|.so|.dylib].
+ \row
+ \o version
+ \o Version string in the form \c {"x.y.z_n"}, used for identifying
+ the plugin.
+ \row
+ \o compatVersion
+ \o Compatibility version. Optional. If not given, it is implicitly
+ set to the same value as \c version. The compatibility version
+ is used to resolve dependencies on this plugin. See
+ \l {Dependencies}{Dependencies} for details.
+ \endtable
+
+ \section2 Plugin-describing Tags
+ These are direct children of the \c plugin tag, and are solely used
+ for more detailed (user centric) description of the plugin. All of these
+ are optional.
+ \table
+ \header
+ \o Tag
+ \o Meaning
+ \row
+ \o vendor
+ \o String that describes the plugin creator/vendor,
+ like \c {MyCompany}.
+ \row
+ \o copyright
+ \o A short copyright notice, like \c {(C) 2007-2008 MyCompany}.
+ \row
+ \o license
+ \o Possibly multi-line license information about the plugin.
+ \row
+ \o description
+ \o Possibly multi-line description of what the plugin is supposed
+ to provide.
+ \row
+ \o url
+ \o Link to further information about the plugin, like
+ \c {http://www.mycompany-online.com/products/greatplugin}.
+ \endtable
+
+ \section2 Dependencies
+ A plugin can have dependencies on other plugins. These are
+ specified in the plugin's xml file as well, to ensure that
+ these other plugins are loaded before this plugin.
+ Dependency information consists of the name of the required plugin
+ (lets denote that as \c {dependencyName}),
+ and the required version of the plugin (\c {dependencyVersion}).
+ A plugin with given \c name, \c version and \c compatVersion matches
+ the dependency if
+ \list
+ \o it's \c name matches \c dependencyName, and
+ \o \c {compatVersion <= dependencyVersion <= version}.
+ \endlist
+
+ The xml element that describes dependencies is the \c dependency tag,
+ with required attributes \c name and \c version. It is an
+ optional direct child of the \c plugin tag and can appear multiple times.
+ \table
+ \header
+ \o Tag
+ \o Meaning
+ \row
+ \o dependency
+ \o Describes a dependency on another plugin.
+ \endtable
+ \table
+ \header
+ \o Attribute
+ \o Meaning
+ \row
+ \o name
+ \o The name of the plugin, on which this plugin relies.
+ \row
+ \o version
+ \o The version to which the plugin must be compatible to
+ fill the dependency, in the form \c {"x.y.z_n"}.
+ \endtable
+
+ \section2 Example \c plugin.xml
+ \code
+ <plugin name="test" version="1.0.1" compatVersion="1.0.0">
+ <vendor>MyCompany</vendor>
+ <copyright>(C) 2007 MyCompany</copyright>
+ <license>
+ This is a default license bla
+ blubbblubb
+ end of terms
+ </license>
+ <description>
+ This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.mycompany-online.com/products/greatplugin</url>
+ <dependencyList>
+ <dependency name="SomeOtherPlugin" version="2.3.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+ </plugin>
+ \endcode
+ The first dependency could for example be matched by a plugin with
+ \code
+ <plugin name="SomeOtherPlugin" version="3.1.0" compatVersion="2.2.0">
+ </plugin>
+ \endcode
+ since the name matches, and the version \c "2.3.0_2" given in the dependency tag
+ lies in the range of \c "2.2.0" and \c "3.1.0".
+
+ \section2 A Note on Plugin Versions
+ Plugin versions are in the form \c "x.y.z_n" where, x, y, z and n are
+ non-negative integer numbers. You don't have to specify the version
+ in this full form - any left-out part will implicitly be set to zero.
+ So, \c "2.10_2" is equal to \c "2.10.0_2", and "1" is the same as "1.0.0_0".
+
+ \section1 Plugin Implementation
+ Plugins must provide one implementation of the IPlugin class, located
+ in a library that matches the \c name attribute given in their
+ xml description. The IPlugin implementation must be exported and
+ made known to Qt's plugin system via the Q_EXPORT_PLUGIN macro, see the
+ Qt documentation for details on that.
+
+ After the plugins' xml files have been read, and dependencies have been
+ found, the plugin loading is done in three phases:
+ \list 1
+ \o All plugin libraries are loaded in 'root-to-leaf' order of the
+ dependency tree.
+ \o All plugins' initialize methods are called in 'root-to-leaf' order
+ of the dependency tree. This is a good place to put
+ objects in the plugin manager's object pool.
+ \o All plugins' extensionsInitialized methods are called in 'leaf-to-root'
+ order of the dependency tree. At this point, plugins can
+ be sure that all plugins that depend on this plugin have
+ been initialized completely (implying that they have put
+ objects in the object pool, if they want that during the
+ initialization sequence).
+ \endlist
+ If library loading or initialization of a plugin fails, all plugins
+ that depend on that plugin also fail.
+
+ Plugins have access to the plugin manager
+ (and it's object pool) via the PluginManager::instance()
+ method.
+*/
+
+/*!
+ \fn bool IPlugin::initialize(const QStringList &arguments, QString *errorString)
+ Called after the plugin has been loaded and the IPlugin instance
+ has been created. The initialize methods of plugins that depend
+ on this plugin are called after the initialize method of this plugin
+ has been called. Plugins should initialize their internal state in this
+ method. Returns if initialization of successful. If it wasn't successful,
+ the \a errorString should be set to a user-readable message
+ describing the reason.
+ \sa extensionsInitialized()
+*/
+
+/*!
+ \fn void IPlugin::extensionsInitialized()
+ Called after the IPlugin::initialize() method has been called,
+ and after both the IPlugin::initialize() and IPlugin::extensionsInitialized()
+ methods of plugins that depend on this plugin have been called.
+ In this method, the plugin can assume that plugins that depend on
+ this plugin are fully 'up and running'. It is a good place to
+ look in the plugin manager's object pool for objects that have
+ been provided by dependent plugins.
+ \sa initialize()
+*/
+
+/*!
+ \fn void IPlugin::shutdown()
+ Called during a shutdown sequence in the same order as initialization
+ before the plugins get deleted in reverse order.
+ This method can be used to optimize the shutdown down, e.g. to
+ disconnect from the PluginManager::aboutToRemoveObject() signal
+ if getting the signal (and probably doing lots of stuff to update
+ the internal and visible state) doesn't make sense during shutdown.
+*/
+
+using namespace ExtensionSystem;
+
+/*!
+ \fn IPlugin::IPlugin()
+ \internal
+*/
+IPlugin::IPlugin()
+ : d(new Internal::IPluginPrivate())
+{
+}
+
+/*!
+ \fn IPlugin::~IPlugin()
+ \internal
+*/
+IPlugin::~IPlugin()
+{
+ PluginManager *pm = PluginManager::instance();
+ foreach (QObject *obj, d->addedObjectsInReverseOrder)
+ pm->removeObject(obj);
+ qDeleteAll(d->addedObjectsInReverseOrder);
+ d->addedObjectsInReverseOrder.clear();
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn PluginSpec *IPlugin::pluginSpec() const
+ Returns the PluginSpec corresponding to this plugin.
+ This is not available in the constructor.
+*/
+PluginSpec *IPlugin::pluginSpec() const
+{
+ return d->pluginSpec;
+}
+
+/*!
+ \fn void IPlugin::addObject(QObject *obj)
+ Convenience method that registers \a obj in the plugin manager's
+ plugin pool by just calling PluginManager::addObject().
+*/
+void IPlugin::addObject(QObject *obj)
+{
+ PluginManager::instance()->addObject(obj);
+}
+
+/*!
+ \fn void IPlugin::addAutoReleasedObject(QObject *obj)
+ Convenience method for registering \a obj in the plugin manager's
+ plugin pool. Usually, registered objects must be removed from
+ the object pool and deleted by hand.
+ Objects added to the pool via addAutoReleasedObject are automatically
+ removed and deleted in \i reverse order of registration when
+ the IPlugin instance is destroyed.
+ \sa PluginManager::addObject()
+*/
+void IPlugin::addAutoReleasedObject(QObject *obj)
+{
+ d->addedObjectsInReverseOrder.prepend(obj);
+ PluginManager::instance()->addObject(obj);
+}
+
+/*!
+ \fn void IPlugin::removeObject(QObject *obj)
+ Convenience method that unregisters \a obj from the plugin manager's
+ plugin pool by just calling PluginManager::removeObject().
+*/
+void IPlugin::removeObject(QObject *obj)
+{
+ PluginManager::instance()->removeObject(obj);
+}
+
diff --git a/src/libs/extensionsystem/iplugin.h b/src/libs/extensionsystem/iplugin.h
new file mode 100644
index 0000000000..b263e7b0d2
--- /dev/null
+++ b/src/libs/extensionsystem/iplugin.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IPLUGIN_H
+#define IPLUGIN_H
+
+#include "extensionsystem_global.h"
+
+#include <QtCore/QObject>
+
+namespace ExtensionSystem {
+
+namespace Internal {
+ class IPluginPrivate;
+ class PluginSpecPrivate;
+}
+
+class PluginManager;
+class PluginSpec;
+
+class EXTENSIONSYSTEM_EXPORT IPlugin : public QObject
+{
+ Q_OBJECT
+
+public:
+ IPlugin();
+ virtual ~IPlugin();
+
+ virtual bool initialize(const QStringList &arguments, QString *errorString) = 0;
+ virtual void extensionsInitialized() = 0;
+ virtual void shutdown() { }
+
+ PluginSpec *pluginSpec() const;
+
+ void addObject(QObject *obj);
+ void addAutoReleasedObject(QObject *obj);
+ void removeObject(QObject *obj);
+
+private:
+ Internal::IPluginPrivate *d;
+
+ friend class Internal::PluginSpecPrivate;
+};
+
+} // namespace ExtensionSystem
+
+#endif // IPLUGIN_H
diff --git a/src/libs/extensionsystem/iplugin_p.h b/src/libs/extensionsystem/iplugin_p.h
new file mode 100644
index 0000000000..461a903a39
--- /dev/null
+++ b/src/libs/extensionsystem/iplugin_p.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IPLUGIN_P_H
+#define IPLUGIN_P_H
+
+#include "iplugin.h"
+
+#include <QtCore/QString>
+
+namespace ExtensionSystem {
+
+class PluginManager;
+class PluginSpec;
+
+namespace Internal {
+
+class IPluginPrivate
+{
+public:
+ PluginSpec *pluginSpec;
+
+ QList<QObject *> addedObjectsInReverseOrder;
+};
+
+} // namespace Internal
+} // namespace ExtensionSystem
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp
new file mode 100644
index 0000000000..77b6ed869e
--- /dev/null
+++ b/src/libs/extensionsystem/optionsparser.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "optionsparser.h"
+
+#include <QtCore/QCoreApplication>
+
+using namespace ExtensionSystem;
+using namespace ExtensionSystem::Internal;
+
+static const char *END_OF_OPTIONS = "--";
+const char *OptionsParser::NO_LOAD_OPTION = "-noload";
+const char *OptionsParser::TEST_OPTION = "-test";
+
+OptionsParser::OptionsParser(const QStringList &args,
+ const QMap<QString, bool> &appOptions,
+ QMap<QString, QString> *foundAppOptions,
+ QString *errorString,
+ PluginManagerPrivate *pmPrivate)
+ : m_args(args), m_appOptions(appOptions),
+ m_foundAppOptions(foundAppOptions),
+ m_errorString(errorString),
+ m_pmPrivate(pmPrivate),
+ m_it(m_args.constBegin()),
+ m_end(m_args.constEnd()),
+ m_isDependencyRefreshNeeded(false),
+ m_hasError(false)
+{
+ ++m_it; // jump over program name
+ if (m_errorString)
+ m_errorString->clear();
+ if (m_foundAppOptions)
+ m_foundAppOptions->clear();
+ m_pmPrivate->arguments.clear();
+}
+
+bool OptionsParser::parse()
+{
+ while (!m_hasError) {
+ if (!nextToken()) // move forward
+ break;
+ if (checkForEndOfOptions())
+ break;
+ if (checkForNoLoadOption())
+ continue;
+ if (checkForTestOption())
+ continue;
+ if (checkForAppOption())
+ continue;
+ if (checkForPluginOption())
+ continue;
+ if (checkForUnknownOption())
+ break;
+ // probably a file or something
+ m_pmPrivate->arguments << m_currentArg;
+ }
+ if (m_isDependencyRefreshNeeded)
+ m_pmPrivate->resolveDependencies();
+ return !m_hasError;
+}
+
+bool OptionsParser::checkForEndOfOptions()
+{
+ if (m_currentArg != QLatin1String(END_OF_OPTIONS))
+ return false;
+ while (nextToken()) {
+ m_pmPrivate->arguments << m_currentArg;
+ }
+ return true;
+}
+
+bool OptionsParser::checkForTestOption()
+{
+ if (m_currentArg != QLatin1String(TEST_OPTION))
+ return false;
+ if (nextToken(RequiredToken)) {
+ PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
+ if (!spec) {
+ if (m_errorString)
+ *m_errorString = QCoreApplication::translate("PluginManager",
+ "The plugin '%1' does not exist.").arg(m_currentArg);
+ m_hasError = true;
+ } else {
+ m_pmPrivate->testSpecs.append(spec);
+ }
+ }
+ return true;
+}
+
+bool OptionsParser::checkForNoLoadOption()
+{
+ if (m_currentArg != QLatin1String(NO_LOAD_OPTION))
+ return false;
+ if (nextToken(RequiredToken)) {
+ PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
+ if (!spec) {
+ if (m_errorString)
+ *m_errorString = QCoreApplication::translate("PluginManager",
+ "The plugin '%1' does not exist.").arg(m_currentArg);
+ m_hasError = true;
+ } else {
+ m_pmPrivate->pluginSpecs.remove(spec);
+ delete spec;
+ m_isDependencyRefreshNeeded = true;
+ }
+ }
+ return true;
+}
+
+bool OptionsParser::checkForAppOption()
+{
+ if (!m_appOptions.contains(m_currentArg))
+ return false;
+ QString option = m_currentArg;
+ QString argument;
+ if (m_appOptions.value(m_currentArg) && nextToken(RequiredToken)) {
+ //argument required
+ argument = m_currentArg;
+ }
+ if (m_foundAppOptions)
+ m_foundAppOptions->insert(option, argument);
+ return true;
+}
+
+bool OptionsParser::checkForPluginOption()
+{
+ bool requiresParameter;
+ PluginSpec *spec = m_pmPrivate->pluginForOption(m_currentArg, &requiresParameter);
+ if (!spec)
+ return false;
+ spec->addArgument(m_currentArg);
+ if (requiresParameter && nextToken(RequiredToken)) {
+ spec->addArgument(m_currentArg);
+ }
+ return true;
+}
+
+bool OptionsParser::checkForUnknownOption()
+{
+ if (!m_currentArg.startsWith(QLatin1Char('-')))
+ return false;
+ if (m_errorString)
+ *m_errorString = QCoreApplication::translate("PluginManager",
+ "Unknown option %1").arg(m_currentArg);
+ m_hasError = true;
+ return true;
+}
+
+bool OptionsParser::nextToken(OptionsParser::TokenType type)
+{
+ if (m_it == m_end) {
+ if (type == OptionsParser::RequiredToken) {
+ m_hasError = true;
+ if (m_errorString)
+ *m_errorString = QCoreApplication::translate("PluginManager",
+ "The option %1 requires an argument.").arg(m_currentArg);
+ }
+ return false;
+ }
+ m_currentArg = *m_it;
+ ++m_it;
+ return true;
+}
diff --git a/src/libs/extensionsystem/optionsparser.h b/src/libs/extensionsystem/optionsparser.h
new file mode 100644
index 0000000000..65ea70c9ba
--- /dev/null
+++ b/src/libs/extensionsystem/optionsparser.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OPTIONSPARSER_H
+#define OPTIONSPARSER_H
+
+#include "pluginmanager_p.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+
+namespace ExtensionSystem {
+namespace Internal {
+
+class OptionsParser
+{
+public:
+ OptionsParser(const QStringList &args,
+ const QMap<QString, bool> &appOptions,
+ QMap<QString, QString> *foundAppOptions,
+ QString *errorString,
+ PluginManagerPrivate *pmPrivate);
+
+ bool parse();
+
+ static const char *NO_LOAD_OPTION;
+ static const char *TEST_OPTION;
+private:
+ // return value indicates if the option was processed
+ // it doesn't indicate success (--> m_hasError)
+ bool checkForEndOfOptions();
+ bool checkForNoLoadOption();
+ bool checkForTestOption();
+ bool checkForAppOption();
+ bool checkForPluginOption();
+ bool checkForUnknownOption();
+
+ enum TokenType { OptionalToken, RequiredToken };
+ bool nextToken(TokenType type = OptionalToken);
+
+ const QStringList &m_args;
+ const QMap<QString, bool> &m_appOptions;
+ QMap<QString, QString> *m_foundAppOptions;
+ QString *m_errorString;
+ PluginManagerPrivate *m_pmPrivate;
+
+ // state
+ QString m_currentArg;
+ QStringList::const_iterator m_it;
+ QStringList::const_iterator m_end;
+ bool m_isDependencyRefreshNeeded;
+ bool m_hasError;
+};
+
+} // namespace Internal
+} // namespace ExtensionSystem
+
+#endif // OPTIONSPARSER_H
diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp
new file mode 100644
index 0000000000..349cc48a12
--- /dev/null
+++ b/src/libs/extensionsystem/plugindetailsview.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugindetailsview.h"
+#include "ui_plugindetailsview.h"
+
+/*!
+ \class ExtensionSystem::PluginDetailsView
+ \brief Widget that displays the contents of a PluginSpec.
+
+ Can be used for integration in the application that
+ uses the plugin manager.
+
+ \sa ExtensionSystem::PluginView
+*/
+
+using namespace ExtensionSystem;
+
+/*!
+ \fn PluginDetailsView::PluginDetailsView(QWidget *parent)
+ Constructs a new view with given \a parent widget.
+*/
+PluginDetailsView::PluginDetailsView(QWidget *parent)
+ : QWidget(parent),
+ m_ui(new Internal::Ui::PluginDetailsView())
+{
+ m_ui->setupUi(this);
+}
+
+/*!
+ \fn PluginDetailsView::~PluginDetailsView()
+ \internal
+*/
+PluginDetailsView::~PluginDetailsView()
+{
+ delete m_ui;
+}
+
+/*!
+ \fn void PluginDetailsView::update(PluginSpec *spec)
+ Reads the given \a spec and displays its values
+ in this PluginDetailsView.
+*/
+void PluginDetailsView::update(PluginSpec *spec)
+{
+ m_ui->name->setText(spec->name());
+ m_ui->version->setText(spec->version());
+ m_ui->compatVersion->setText(spec->compatVersion());
+ m_ui->vendor->setText(spec->vendor());
+ m_ui->url->setText(spec->url());
+ m_ui->location->setText(spec->filePath());
+ m_ui->description->setText(spec->description());
+ m_ui->copyright->setText(spec->copyright());
+ m_ui->license->setText(spec->license());
+ QStringList depStrings;
+ foreach (PluginDependency dep, spec->dependencies()) {
+ depStrings << QString("%1 (%2)").arg(dep.name).arg(dep.version);
+ }
+ m_ui->dependencies->addItems(depStrings);
+}
diff --git a/src/libs/extensionsystem/plugindetailsview.h b/src/libs/extensionsystem/plugindetailsview.h
new file mode 100644
index 0000000000..99386f29d0
--- /dev/null
+++ b/src/libs/extensionsystem/plugindetailsview.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINDETAILSVIEW_H_
+#define PLUGINDETAILSVIEW_H_
+
+#include "extensionsystem_global.h"
+#include "pluginspec.h"
+
+#include <QtGui/QWidget>
+
+namespace ExtensionSystem
+{
+
+namespace Internal {
+namespace Ui {
+ class PluginDetailsView;
+} // namespace Ui
+} // namespace Internal
+
+
+class EXTENSIONSYSTEM_EXPORT PluginDetailsView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PluginDetailsView(QWidget *parent = 0);
+ ~PluginDetailsView();
+
+ void update(PluginSpec *spec);
+
+private:
+ Internal::Ui::PluginDetailsView *m_ui;
+};
+
+} // namespace ExtensionSystem
+
+#endif
diff --git a/src/libs/extensionsystem/plugindetailsview.ui b/src/libs/extensionsystem/plugindetailsview.ui
new file mode 100644
index 0000000000..e73c9de39b
--- /dev/null
+++ b/src/libs/extensionsystem/plugindetailsview.ui
@@ -0,0 +1,258 @@
+<ui version="4.0" >
+ <class>ExtensionSystem::Internal::PluginDetailsView</class>
+ <widget class="QWidget" name="ExtensionSystem::Internal::PluginDetailsView" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>674</width>
+ <height>505</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>2</number>
+ </property>
+ <property name="topMargin" >
+ <number>2</number>
+ </property>
+ <property name="rightMargin" >
+ <number>2</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>2</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Name:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="name" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Version:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="version" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Compatibility Version:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="compatVersion" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Vendor:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLabel" name="vendor" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_6" >
+ <property name="text" >
+ <string>Url:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLabel" name="url" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="label_7" >
+ <property name="text" >
+ <string>Location:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" >
+ <widget class="QLabel" name="location" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" >
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Description:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="6" column="1" >
+ <widget class="QTextEdit" name="description" >
+ <property name="tabChangesFocus" >
+ <bool>true</bool>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Copyright:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1" >
+ <widget class="QLabel" name="copyright" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0" >
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_9" >
+ <property name="text" >
+ <string>License:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>17</width>
+ <height>13</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="8" column="1" >
+ <widget class="QTextEdit" name="license" >
+ <property name="tabChangesFocus" >
+ <bool>true</bool>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0" >
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_10" >
+ <property name="text" >
+ <string>Dependencies:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="9" column="1" >
+ <widget class="QListWidget" name="dependencies" />
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/extensionsystem/pluginerrorview.cpp b/src/libs/extensionsystem/pluginerrorview.cpp
new file mode 100644
index 0000000000..c1572d8829
--- /dev/null
+++ b/src/libs/extensionsystem/pluginerrorview.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "pluginerrorview.h"
+#include "ui_pluginerrorview.h"
+
+#include <QtCore/QString>
+
+/*!
+ \class ExtensionSystem::PluginErrorView
+ \brief Widget that displays the state and error message of a PluginSpec.
+
+ Can be used for integration in the application that
+ uses the plugin manager.
+
+ \sa ExtensionSystem::PluginView
+*/
+
+using namespace ExtensionSystem;
+
+/*!
+ \fn PluginErrorView::PluginErrorView(QWidget *parent)
+ Constructs a new error view with given \a parent widget.
+*/
+PluginErrorView::PluginErrorView(QWidget *parent)
+ : QWidget(parent),
+ m_ui(new Internal::Ui::PluginErrorView())
+{
+ m_ui->setupUi(this);
+}
+
+/*!
+ \fn PluginErrorView::~PluginErrorView()
+ \internal
+*/
+PluginErrorView::~PluginErrorView()
+{
+ delete m_ui;
+}
+
+/*!
+ \fn void PluginErrorView::update(PluginSpec *spec)
+ Reads the given \a spec and displays its state and
+ error information in this PluginErrorView.
+*/
+void PluginErrorView::update(PluginSpec *spec)
+{
+ QString text;
+ QString tooltip;
+ switch (spec->state()) {
+ case PluginSpec::Invalid:
+ text = tr("Invalid");
+ tooltip = tr("Description file found, but error on read");
+ break;
+ case PluginSpec::Read:
+ text = tr("Read");
+ tooltip = tr("Description successfully read");
+ break;
+ case PluginSpec::Resolved:
+ text = tr("Resolved");
+ tooltip = tr("Dependencies are successfully resolved");
+ break;
+ case PluginSpec::Loaded:
+ text = tr("Loaded");
+ tooltip = tr("Library is loaded");
+ break;
+ case PluginSpec::Initialized:
+ text = tr("Initialized");
+ tooltip = tr("Plugin's initialization method succeeded");
+ break;
+ case PluginSpec::Running:
+ text = tr("Running");
+ tooltip = tr("Plugin successfully loaded and running");
+ break;
+ case PluginSpec::Stopped:
+ text = tr("Stopped");
+ tooltip = tr("Plugin was shut down");
+ case PluginSpec::Deleted:
+ text = tr("Deleted");
+ tooltip = tr("Plugin ended it's life cycle and was deleted");
+ }
+ m_ui->state->setText(text);
+ m_ui->state->setToolTip(tooltip);
+ m_ui->errorString->setText(spec->errorString());
+}
diff --git a/src/libs/extensionsystem/pluginerrorview.h b/src/libs/extensionsystem/pluginerrorview.h
new file mode 100644
index 0000000000..87b4097d03
--- /dev/null
+++ b/src/libs/extensionsystem/pluginerrorview.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINERRORVIEW_H_
+#define PLUGINERRORVIEW_H_
+
+#include "extensionsystem_global.h"
+#include "pluginspec.h"
+
+#include <QtGui/QWidget>
+
+namespace ExtensionSystem
+{
+
+namespace Internal {
+namespace Ui {
+ class PluginErrorView;
+} // namespace Ui
+} // namespace Internal
+
+class EXTENSIONSYSTEM_EXPORT PluginErrorView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PluginErrorView(QWidget *parent = 0);
+ ~PluginErrorView();
+
+ void update(PluginSpec *spec);
+
+private:
+ Internal::Ui::PluginErrorView *m_ui;
+};
+
+} // namespace ExtensionSystem
+
+#endif /*PLUGINERRORVIEW_H_*/
diff --git a/src/libs/extensionsystem/pluginerrorview.ui b/src/libs/extensionsystem/pluginerrorview.ui
new file mode 100644
index 0000000000..69f49e53c6
--- /dev/null
+++ b/src/libs/extensionsystem/pluginerrorview.ui
@@ -0,0 +1,77 @@
+<ui version="4.0" >
+ <class>ExtensionSystem::Internal::PluginErrorView</class>
+ <widget class="QWidget" name="ExtensionSystem::Internal::PluginErrorView" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>579</width>
+ <height>342</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <property name="margin" >
+ <number>2</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>State:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="state" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Error Message:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QTextEdit" name="errorString" >
+ <property name="tabChangesFocus" >
+ <bool>true</bool>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
new file mode 100644
index 0000000000..daf4169a80
--- /dev/null
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -0,0 +1,749 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "pluginmanager.h"
+#include "pluginmanager_p.h"
+#include "pluginspec.h"
+#include "pluginspec_p.h"
+#include "optionsparser.h"
+#include "iplugin.h"
+
+#include <QtCore/QMetaProperty>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QWriteLocker>
+#include <QtDebug>
+#ifdef WITH_TESTS
+#include <QTest>
+#endif
+
+typedef QSet<ExtensionSystem::PluginSpec *> PluginSpecSet;
+
+enum { debugLeaks = 0 };
+
+/*!
+ \namespace ExtensionSystem
+ \brief Classes that belong to the core plugin system.
+
+ The basic extension system contains of the plugin manager and its supporting classes,
+ and the IPlugin interface that must be implemented by plugin providers.
+*/
+
+/*!
+ \namespace ExtensionSystem::Internal
+ \internal
+*/
+
+/*!
+ \class ExtensionSystem::PluginManager
+ \mainclass
+
+ \brief Core plugin system that manages the plugins, their life cycle and their registered objects.
+
+ The plugin manager is used for the following tasks:
+ \list
+ \o Manage plugins and their state
+ \o Manipulate a 'common object pool'
+ \endlist
+
+ \section1 Plugins
+ Plugins consist of an xml descriptor file, and of a library that contains a Qt plugin
+ (declared via Q_EXPORT_PLUGIN) that must derive from the IPlugin class.
+ The plugin manager is used to set a list of file system directories to search for
+ plugins, retrieve information about the state of these plugins, and to load them.
+
+ Usually the application creates a PluginManager instance and initiates the loading.
+ \code
+ ExtensionSystem::PluginManager *manager = new ExtensionSystem::PluginManager();
+ manager->setPluginPaths(QStringList() << "plugins"); // 'plugins' and subdirs will be searched for plugins
+ manager->loadPlugins(); // try to load all the plugins
+ \endcode
+ Additionally it is possible to directly access to the plugin specifications
+ (the information in the descriptor file), and the plugin instances (via PluginSpec),
+ and their state.
+
+ \section1 Object Pool
+ Plugins (and everybody else) can add objects to a common 'pool' that is located in
+ the plugin manager. Objects in the pool must derive from QObject, there are no other
+ prerequisites. All objects of a specified type can be retrieved from the object pool
+ via the getObjects() and getObject() methods. They are aware of Aggregation::Aggregate, i.e.
+ these methods use the Aggregation::query methods instead of a qobject_cast to determine
+ the matching objects.
+
+ Whenever the state of the object pool changes a corresponding signal is emitted by the plugin manager.
+
+ A common usecase for the object pool is that a plugin (or the application) provides
+ an "extension point" for other plugins, which is a class / interface that can
+ be implemented and added to the object pool. The plugin that provides the
+ extension point looks for implementations of the class / interface in the object pool.
+ \code
+ // plugin A provides a "MimeTypeHandler" extension point
+ // in plugin B:
+ MyMimeTypeHandler *handler = new MyMimeTypeHandler();
+ ExtensionSystem::PluginManager::instance()->addObject(handler);
+ // in plugin A:
+ QList<MimeTypeHandler *> mimeHandlers =
+ ExtensionSystem::PluginManager::instance()->getObjects<MimeTypeHandler>();
+ \endcode
+
+ \bold Note: The object pool manipulating functions are thread-safe.
+*/
+
+/*!
+ \fn void PluginManager::objectAdded(QObject *obj)
+ Signal that \a obj has been added to the object pool.
+*/
+
+/*!
+ \fn void PluginManager::aboutToRemoveObject(QObject *obj)
+ Signal that \a obj will be removed from the object pool.
+*/
+
+/*!
+ \fn void PluginManager::pluginsChanged()
+ Signal that the list of available plugins has changed.
+
+ \sa plugins()
+*/
+
+/*!
+ \fn T *PluginManager::getObject() const
+ Retrieve the object of a given type from the object pool.
+ This method is aware of Aggregation::Aggregate, i.e. it uses
+ the Aggregation::query methods instead of qobject_cast to
+ determine the type of an object.
+ If there are more than one object of the given type in
+ the object pool, this method will choose an arbitrary one of them.
+
+ \sa addObject()
+*/
+
+/*!
+ \fn QList<T *> PluginManager::getObjects() const
+ Retrieve all objects of a given type from the object pool.
+ This method is aware of Aggregation::Aggregate, i.e. it uses
+ the Aggregation::query methods instead of qobject_cast to
+ determine the type of an object.
+
+ \sa addObject()
+*/
+
+using namespace ExtensionSystem;
+using namespace ExtensionSystem::Internal;
+
+PluginManager *PluginManager::m_instance = 0;
+
+/*!
+ \fn PluginManager *PluginManager::instance()
+ Get the unique plugin manager instance.
+*/
+PluginManager *PluginManager::instance()
+{
+ return m_instance;
+}
+
+/*!
+ \fn PluginManager::PluginManager()
+ Create a plugin manager. Should be done only once per application.
+*/
+PluginManager::PluginManager()
+ : d(new PluginManagerPrivate(this))
+{
+ m_instance = this;
+}
+
+/*!
+ \fn PluginManager::~PluginManager()
+ \internal
+*/
+PluginManager::~PluginManager()
+{
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn void PluginManager::addObject(QObject *obj)
+ Add the given object \a obj to the object pool, so it can be retrieved again from the pool by type.
+ The plugin manager does not do any memory management - added objects
+ must be removed from the pool and deleted manually by whoever is responsible for the object.
+
+ Emits the objectAdded() signal.
+
+ \sa PluginManager::removeObject()
+ \sa PluginManager::getObject()
+ \sa PluginManager::getObjects()
+*/
+void PluginManager::addObject(QObject *obj)
+{
+ d->addObject(obj);
+}
+
+/*!
+ \fn void PluginManager::removeObject(QObject *obj)
+ Emits aboutToRemoveObject() and removes the object \a obj from the object pool.
+ \sa PluginManager::addObject()
+*/
+void PluginManager::removeObject(QObject *obj)
+{
+ d->removeObject(obj);
+}
+
+/*!
+ \fn QList<QObject *> PluginManager::allObjects() const
+ Retrieve the list of all objects in the pool, unfiltered.
+ Usually clients do not need to call this.
+ \sa PluginManager::getObject()
+ \sa PluginManager::getObjects()
+*/
+QList<QObject *> PluginManager::allObjects() const
+{
+ return d->allObjects;
+}
+
+/*!
+ \fn void PluginManager::loadPlugins()
+ Tries to load all the plugins that were previously found when
+ setting the plugin search paths. The plugin specs of the plugins
+ can be used to retrieve error and state information about individual plugins.
+
+ \sa setPluginPaths()
+ \sa plugins()
+*/
+void PluginManager::loadPlugins()
+{
+ return d->loadPlugins();
+}
+
+/*!
+ \fn QStringList PluginManager::pluginPaths() const
+ The list of paths were the plugin manager searches for plugins.
+
+ \sa setPluginPaths()
+*/
+QStringList PluginManager::pluginPaths() const
+{
+ return d->pluginPaths;
+}
+
+/*!
+ \fn void PluginManager::setPluginPaths(const QStringList &paths)
+ Sets the plugin search paths, i.e. the file system paths where the plugin manager
+ looks for plugin descriptions. All given \a paths and their sub directory trees
+ are searched for plugin xml description files.
+
+ \sa pluginPaths()
+ \sa loadPlugins()
+*/
+void PluginManager::setPluginPaths(const QStringList &paths)
+{
+ d->setPluginPaths(paths);
+}
+
+/*!
+ \fn QString PluginManager::fileExtension() const
+ The file extension of plugin description files.
+ The default is "xml".
+
+ \sa setFileExtension()
+*/
+QString PluginManager::fileExtension() const
+{
+ return d->extension;
+}
+
+/*!
+ \fn void PluginManager::setFileExtension(const QString &extension)
+ Sets the file extension of plugin description files.
+ The default is "xml".
+ At the moment this must be called before setPluginPaths() is called.
+ // ### TODO let this + setPluginPaths read the plugin specs lazyly whenever loadPlugins() or plugins() is called.
+*/
+void PluginManager::setFileExtension(const QString &extension)
+{
+ d->extension = extension;
+}
+
+/*!
+ \fn QStringList PluginManager::arguments() const
+ The arguments left over after parsing (Neither startup nor plugin
+ arguments). Typically, this will be the list of files to open.
+*/
+QStringList PluginManager::arguments() const
+{
+ return d->arguments;
+}
+
+/*!
+ \fn QSet<PluginSpec *> PluginManager::plugins() const
+ List of all plugin specifications that have been found in the plugin search paths.
+ This list is valid directly after the setPluginPaths() call.
+ The plugin specifications contain the information from the plugins' xml description files
+ and the current state of the plugins. If a plugin's library has been already successfully loaded,
+ the plugin specification has a reference to the created plugin instance as well.
+
+ \sa setPluginPaths()
+*/
+QSet<PluginSpec *> PluginManager::plugins() const
+{
+ return d->pluginSpecs;
+}
+
+/*!
+ \fn bool PluginManager::parseOptions(const QStringList &args, const QMap<QString, bool> &appOptions, QMap<QString, QString> *foundAppOptions, QString *errorString)
+ Takes the list of command line options in \a args and parses them.
+ The plugin manager itself might process some options itself directly (-noload <plugin>), and
+ adds options that are registered by plugins to their plugin specs.
+ The caller (the application) may register itself for options via the \a appOptions list, containing pairs
+ of "option string" and a bool that indicates if the option requires an argument.
+ Application options always override any plugin's options.
+
+ \a foundAppOptions is set to pairs of ("option string", "argument") for any application options that were found.
+ The command line options that were not processed can be retrieved via the arguments() method.
+ If an error occurred (like missing argument for an option that requires one), \a errorString contains
+ a descriptive message of the error.
+
+ Returns if there was an error.
+ */
+bool PluginManager::parseOptions(const QStringList &args,
+ const QMap<QString, bool> &appOptions,
+ QMap<QString, QString> *foundAppOptions,
+ QString *errorString)
+{
+ OptionsParser options(args, appOptions, foundAppOptions, errorString, d);
+ return options.parse();
+}
+
+
+
+static inline void indent(QTextStream &str, int indent)
+{
+ const QChar blank = QLatin1Char(' ');
+ for (int i = 0 ; i < indent; i++)
+ str << blank;
+}
+
+static inline void formatOption(QTextStream &str,
+ const QString &opt, const QString &parm, const QString &description,
+ int optionIndentation, int descriptionIndentation)
+{
+ int remainingIndent = descriptionIndentation - optionIndentation - opt.size();
+ indent(str, optionIndentation);
+ str << opt;
+ if (!parm.isEmpty()) {
+ str << " <" << parm << '>';
+ remainingIndent -= 3 + parm.size();
+ }
+ indent(str, qMax(0, remainingIndent));
+ str << description << '\n';
+}
+
+/*!
+ \fn static PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation)
+
+ Format the startup options of the plugin manager for command line help.
+*/
+
+void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation)
+{
+ formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION),
+ QLatin1String("plugin"), QLatin1String("Do not load <plugin>"),
+ optionIndentation, descriptionIndentation);
+}
+
+/*!
+ \fn PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const
+
+ Format the plugin options of the plugin specs for command line help.
+*/
+
+void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const
+{
+ typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions;
+ // Check plugins for options
+ const PluginSpecSet::const_iterator pcend = d->pluginSpecs.constEnd();
+ for (PluginSpecSet::const_iterator pit = d->pluginSpecs.constBegin(); pit != pcend; ++pit) {
+ const PluginArgumentDescriptions pargs = (*pit)->argumentDescriptions();
+ if (!pargs.empty()) {
+ str << "\nPlugin: " << (*pit)->name() << '\n';
+ const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd();
+ for (PluginArgumentDescriptions::const_iterator ait =pargs.constBegin(); ait != acend; ++ait)
+ formatOption(str, ait->name, ait->parameter, ait->description, optionIndentation, descriptionIndentation);
+ }
+ }
+}
+
+/*!
+ \fn PluginManager::formatPluginVersions(QTextStream &str) const
+
+ Format the version of the plugin specs for command line help.
+*/
+
+void PluginManager::formatPluginVersions(QTextStream &str) const
+{
+ const PluginSpecSet::const_iterator cend = d->pluginSpecs.constEnd();
+ for (PluginSpecSet::const_iterator it = d->pluginSpecs.constBegin(); it != cend; ++it) {
+ const PluginSpec *ps = *it;
+ str << " " << ps->name() << ' ' << ps->version() << ' ' << ps->description() << '\n';
+ }
+}
+
+void PluginManager::startTests()
+{
+#ifdef WITH_TESTS
+ foreach(PluginSpec *pluginSpec, d->testSpecs) {
+ const QMetaObject *mo = pluginSpec->plugin()->metaObject();
+ QStringList methods;
+ methods.append("arg0");
+ // We only want slots starting with "test"
+ for(int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
+ if (QByteArray(mo->method(i).signature()).startsWith("test")) {
+ QString method = QString::fromLatin1(mo->method(i).signature());
+ methods.append(method.left(method.size()-2));
+ }
+ }
+ QTest::qExec(pluginSpec->plugin(), methods);
+
+ }
+#endif
+}
+
+bool PluginManager::runningTests() const
+{
+ return !d->testSpecs.isEmpty();
+}
+
+QString PluginManager::testDataDirectory() const
+{
+ QString s = QString::fromLocal8Bit(qgetenv("IDETESTDIR"));
+ if (s.isEmpty()) {
+ s = IDE_TEST_DIR;
+ s.append("/tests");
+ }
+ s = QDir::cleanPath(s);
+ return s;
+}
+
+//============PluginManagerPrivate===========
+
+/*!
+ \fn PluginSpec *PluginManagerPrivate::createSpec()
+ \internal
+*/
+PluginSpec *PluginManagerPrivate::createSpec()
+{
+ return new PluginSpec();
+}
+
+/*!
+ \fn PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec)
+ \internal
+*/
+PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec)
+{
+ return spec->d;
+}
+
+/*!
+ \fn PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager)
+ \internal
+*/
+PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager)
+ : extension("xml"), q(pluginManager)
+{
+}
+
+/*!
+ \fn PluginManagerPrivate::~PluginManagerPrivate()
+ \internal
+*/
+PluginManagerPrivate::~PluginManagerPrivate()
+{
+ stopAll();
+ qDeleteAll(pluginSpecs);
+ if (!allObjects.isEmpty()) {
+ qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects;
+ }
+}
+
+void PluginManagerPrivate::stopAll()
+{
+ QList<PluginSpec *> queue = loadQueue();
+ foreach (PluginSpec *spec, queue) {
+ loadPlugin(spec, PluginSpec::Stopped);
+ }
+ QListIterator<PluginSpec *> it(queue);
+ it.toBack();
+ while (it.hasPrevious()) {
+ loadPlugin(it.previous(), PluginSpec::Deleted);
+ }
+}
+
+/*!
+ \fn void PluginManagerPrivate::addObject(QObject *obj)
+ \internal
+*/
+void PluginManagerPrivate::addObject(QObject *obj)
+{
+ {
+ QWriteLocker lock(&(q->m_lock));
+ if (obj == 0) {
+ qWarning() << "PluginManagerPrivate::addObject(): trying to add null object";
+ return;
+ }
+ if (allObjects.contains(obj)) {
+ qWarning() << "PluginManagerPrivate::addObject(): trying to add duplicate object";
+ return;
+ }
+
+ if (debugLeaks)
+ qDebug() << "PluginManagerPrivate::addObject" << obj << obj->objectName();
+
+ allObjects.append(obj);
+ }
+ emit q->objectAdded(obj);
+}
+
+/*!
+ \fn void PluginManagerPrivate::removeObject(QObject *obj)
+ \internal
+*/
+void PluginManagerPrivate::removeObject(QObject *obj)
+{
+ if (obj == 0) {
+ qWarning() << "PluginManagerPrivate::removeObject(): trying to remove null object";
+ return;
+ }
+
+ if (!allObjects.contains(obj)) {
+ qWarning() << "PluginManagerPrivate::removeObject(): object not in list:"
+ << obj << obj->objectName();
+ return;
+ }
+ if (debugLeaks)
+ qDebug() << "PluginManagerPrivate::removeObject" << obj << obj->objectName();
+
+ emit q->aboutToRemoveObject(obj);
+ QWriteLocker lock(&(q->m_lock));
+ allObjects.removeAll(obj);
+}
+
+/*!
+ \fn void PluginManagerPrivate::loadPlugins()
+ \internal
+*/
+void PluginManagerPrivate::loadPlugins()
+{
+ QList<PluginSpec *> queue = loadQueue();
+ foreach (PluginSpec *spec, queue) {
+ loadPlugin(spec, PluginSpec::Loaded);
+ }
+ foreach (PluginSpec *spec, queue) {
+ loadPlugin(spec, PluginSpec::Initialized);
+ }
+ QListIterator<PluginSpec *> it(queue);
+ it.toBack();
+ while (it.hasPrevious()) {
+ loadPlugin(it.previous(), PluginSpec::Running);
+ }
+ emit q->pluginsChanged();
+}
+
+/*!
+ \fn void PluginManagerPrivate::loadQueue()
+ \internal
+*/
+QList<PluginSpec *> PluginManagerPrivate::loadQueue()
+{
+ QList<PluginSpec *> queue;
+ foreach (PluginSpec *spec, pluginSpecs) {
+ QList<PluginSpec *> circularityCheckQueue;
+ loadQueue(spec, queue, circularityCheckQueue);
+ }
+ return queue;
+}
+
+/*!
+ \fn bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue, QList<PluginSpec *> &circularityCheckQueue)
+ \internal
+*/
+bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue,
+ QList<PluginSpec *> &circularityCheckQueue)
+{
+ if (queue.contains(spec))
+ return true;
+ // check for circular dependencies
+ if (circularityCheckQueue.contains(spec)) {
+ spec->d->hasError = true;
+ spec->d->errorString = q->tr("Circular dependency detected:\n");
+ int index = circularityCheckQueue.indexOf(spec);
+ for (int i = index; i < circularityCheckQueue.size(); ++i) {
+ spec->d->errorString.append(q->tr("%1(%2) depends on\n")
+ .arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version()));
+ }
+ spec->d->errorString.append(q->tr("%1(%2)").arg(spec->name()).arg(spec->version()));
+ return false;
+ }
+ circularityCheckQueue.append(spec);
+ // check if we have the dependencies
+ if (spec->state() == PluginSpec::Invalid || spec->state() == PluginSpec::Read) {
+ spec->d->hasError = true;
+ spec->d->errorString += "\n";
+ spec->d->errorString += q->tr("Cannot load plugin because dependencies are not resolved");
+ return false;
+ }
+ // add dependencies
+ foreach (PluginSpec *depSpec, spec->dependencySpecs()) {
+ if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
+ spec->d->hasError = true;
+ spec->d->errorString =
+ q->tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
+ .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
+ return false;
+ }
+ }
+ // add self
+ queue.append(spec);
+ return true;
+}
+
+/*!
+ \fn void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState)
+ \internal
+*/
+void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState)
+{
+ if (spec->hasError())
+ return;
+ if (destState == PluginSpec::Running) {
+ spec->d->initializeExtensions();
+ return;
+ } else if (destState == PluginSpec::Deleted) {
+ spec->d->kill();
+ return;
+ }
+ foreach (PluginSpec *depSpec, spec->dependencySpecs()) {
+ if (depSpec->state() != destState) {
+ spec->d->hasError = true;
+ spec->d->errorString =
+ q->tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
+ .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());
+ return;
+ }
+ }
+ if (destState == PluginSpec::Loaded)
+ spec->d->loadLibrary();
+ else if (destState == PluginSpec::Initialized)
+ spec->d->initializePlugin();
+ else if (destState == PluginSpec::Stopped)
+ spec->d->stop();
+}
+
+/*!
+ \fn void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
+ \internal
+*/
+void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
+{
+ pluginPaths = paths;
+ readPluginPaths();
+}
+
+/*!
+ \fn void PluginManagerPrivate::readPluginPaths()
+ \internal
+*/
+void PluginManagerPrivate::readPluginPaths()
+{
+ qDeleteAll(pluginSpecs);
+ pluginSpecs.clear();
+
+ QStringList specFiles;
+ QStringList searchPaths = pluginPaths;
+ while (!searchPaths.isEmpty()) {
+ const QDir dir(searchPaths.takeFirst());
+ const QFileInfoList files = dir.entryInfoList(QStringList() << QString("*.%1").arg(extension), QDir::Files);
+ foreach (const QFileInfo &file, files)
+ specFiles << file.absoluteFilePath();
+ const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
+ foreach (const QFileInfo &subdir, dirs)
+ searchPaths << subdir.absoluteFilePath();
+ }
+ foreach (const QString &specFile, specFiles) {
+ PluginSpec *spec = new PluginSpec;
+ spec->d->read(specFile);
+ pluginSpecs.insert(spec);
+ }
+ resolveDependencies();
+ emit q->pluginsChanged();
+}
+
+void PluginManagerPrivate::resolveDependencies()
+{
+ foreach (PluginSpec *spec, pluginSpecs) {
+ spec->d->resolveDependencies(pluginSpecs);
+ }
+}
+
+ // Look in argument descriptions of the specs for the option.
+PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const
+{
+ // Look in the plugins for an option
+ typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions;
+
+ *requiresArgument = false;
+ const PluginSpecSet::const_iterator pcend = pluginSpecs.constEnd();
+ for (PluginSpecSet::const_iterator pit = pluginSpecs.constBegin(); pit != pcend; ++pit) {
+ PluginSpec *ps = *pit;
+ const PluginArgumentDescriptions pargs = ps->argumentDescriptions();
+ if (!pargs.empty()) {
+ const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd();
+ for (PluginArgumentDescriptions::const_iterator ait = pargs.constBegin(); ait != acend; ++ait) {
+ if (ait->name == option) {
+ *requiresArgument = !ait->parameter.isEmpty();
+ return ps;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const
+{
+ foreach (PluginSpec *spec, pluginSpecs)
+ if (spec->name() == name)
+ return spec;
+ return 0;
+}
+
diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h
new file mode 100644
index 0000000000..7f003b4f89
--- /dev/null
+++ b/src/libs/extensionsystem/pluginmanager.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EXTENSIONSYSTEM_PLUGINMANAGER_H
+#define EXTENSIONSYSTEM_PLUGINMANAGER_H
+
+#include "extensionsystem_global.h"
+#include <aggregation/aggregate.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtCore/QWriteLocker>
+#include <QtCore/QReadWriteLock>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace ExtensionSystem {
+
+namespace Internal {
+ class PluginManagerPrivate;
+}
+
+class IPlugin;
+class PluginSpec;
+
+class EXTENSIONSYSTEM_EXPORT PluginManager : public QObject
+{
+ Q_DISABLE_COPY(PluginManager)
+ Q_OBJECT
+
+public:
+ static PluginManager *instance();
+
+ PluginManager();
+ virtual ~PluginManager();
+
+ // Object pool operations
+ void addObject(QObject *obj);
+ void removeObject(QObject *obj);
+ QList<QObject *> allObjects() const;
+ template <typename T> QList<T *> getObjects() const
+ {
+ QReadLocker lock(&m_lock);
+ QList<T *> results;
+ QList<QObject *> all = allObjects();
+ QList<T *> result;
+ foreach (QObject *obj, all) {
+ result = Aggregation::query_all<T>(obj);
+ if (!result.isEmpty())
+ results += result;
+ }
+ return results;
+ }
+ template <typename T> T *getObject() const
+ {
+ QReadLocker lock(&m_lock);
+ QList<QObject *> all = allObjects();
+ T *result = 0;
+ foreach (QObject *obj, all) {
+ if ((result = Aggregation::query<T>(obj)) != 0)
+ break;
+ }
+ return result;
+ }
+
+ // Plugin operations
+ void loadPlugins();
+ QStringList pluginPaths() const;
+ void setPluginPaths(const QStringList &paths);
+ QSet<PluginSpec *> plugins() const;
+ void setFileExtension(const QString &extension);
+ QString fileExtension() const;
+
+ // command line arguments
+ QStringList arguments() const;
+ bool parseOptions(const QStringList &args,
+ const QMap<QString, bool> &appOptions,
+ QMap<QString, QString> *foundAppOptions,
+ QString *errorString);
+ static void formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation);
+ void formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const;
+ void formatPluginVersions(QTextStream &str) const;
+
+ bool runningTests() const;
+ QString testDataDirectory() const;
+
+signals:
+ void objectAdded(QObject *obj);
+ void aboutToRemoveObject(QObject *obj);
+
+ void pluginsChanged();
+private slots:
+ void startTests();
+
+private:
+ Internal::PluginManagerPrivate *d;
+ static PluginManager *m_instance;
+ mutable QReadWriteLock m_lock;
+
+ friend class Internal::PluginManagerPrivate;
+};
+
+} //namespace
+
+#endif // PLUGINMANAGER_H
diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h
new file mode 100644
index 0000000000..6b8df8d2be
--- /dev/null
+++ b/src/libs/extensionsystem/pluginmanager_p.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINMANAGER_P_H
+#define PLUGINMANAGER_P_H
+
+#include "pluginspec.h"
+
+#include <QtCore/QList>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtCore/QObject>
+
+namespace ExtensionSystem {
+
+class PluginManager;
+
+namespace Internal {
+
+class PluginSpecPrivate;
+
+class EXTENSIONSYSTEM_EXPORT PluginManagerPrivate
+{
+public:
+ PluginManagerPrivate(PluginManager *pluginManager);
+ virtual ~PluginManagerPrivate();
+
+ // Object pool operations
+ void addObject(QObject *obj);
+ void removeObject(QObject *obj);
+
+ // Plugin operations
+ void loadPlugins();
+ void setPluginPaths(const QStringList &paths);
+ QList<PluginSpec *> loadQueue();
+ void loadPlugin(PluginSpec *spec, PluginSpec::State destState);
+ void resolveDependencies();
+
+ QSet<PluginSpec *> pluginSpecs;
+ QList<PluginSpec *> testSpecs;
+ QStringList pluginPaths;
+ QString extension;
+ QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ?
+
+ QStringList arguments;
+
+ // Look in argument descriptions of the specs for the option.
+ PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
+ PluginSpec *pluginByName(const QString &name) const;
+
+ // used by tests
+ static PluginSpec *createSpec();
+ static PluginSpecPrivate *privateSpec(PluginSpec *spec);
+private:
+ PluginManager *q;
+
+ void readPluginPaths();
+ bool loadQueue(PluginSpec *spec,
+ QList<PluginSpec *> &queue,
+ QList<PluginSpec *> &circularityCheckQueue);
+ void stopAll();
+};
+
+} // namespace Internal
+} // namespace ExtensionSystem
+
+#endif // PLUGINMANAGER_P_H
diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp
new file mode 100644
index 0000000000..dfa7bdbe7c
--- /dev/null
+++ b/src/libs/extensionsystem/pluginspec.cpp
@@ -0,0 +1,871 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "pluginspec.h"
+#include "pluginspec.h"
+#include "pluginspec_p.h"
+#include "iplugin.h"
+#include "iplugin_p.h"
+#include "pluginmanager.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QRegExp>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QCoreApplication>
+#include <QtDebug>
+
+/*!
+ \class ExtensionSystem::PluginDependency
+ \brief Struct that contains the name and required compatible version number of a plugin's dependency.
+
+ This reflects the data of a dependency tag in the plugin's xml description file.
+ The name and version are used to resolve the dependency, i.e. a plugin with the given name and
+ plugin \c {compatibility version <= dependency version <= plugin version} is searched for.
+
+ See also ExtensionSystem::IPlugin for more information about plugin dependencies and
+ version matching.
+*/
+
+/*!
+ \variable ExtensionSystem::PluginDependency::name
+ String identifier of the plugin.
+*/
+
+/*!
+ \variable ExtensionSystem::PluginDependency::version
+ Version string that a plugin must match to fill this dependency.
+*/
+
+/*!
+ \class ExtensionSystem::PluginSpec
+ \brief Contains the information of the plugins xml description file and
+ information about the plugin's current state.
+
+ The plugin spec is also filled with more information as the plugin
+ goes through it's loading process (see PluginSpec::State).
+ If an error occurs, the plugin spec is the place to look for the
+ error details.
+*/
+
+/*!
+ \enum ExtensionSystem::PluginSpec::State
+
+ The plugin goes through several steps while being loaded.
+ The state gives a hint on what went wrong in case of an error.
+
+ \value Invalid
+ Starting point: Even the xml description file was not read.
+ \value Read
+ The xml description file has been successfully read, and it's
+ information is available via the PluginSpec.
+ \value Resolved
+ The dependencies given in the description file have been
+ successfully found, and are available via the dependencySpecs() method.
+ \value Loaded
+ The plugin's library is loaded and the plugin instance created
+ (available through plugin()).
+ \value Initialized
+ The plugin instance's IPlugin::initialize() method has been called
+ and returned a success value.
+ \value Running
+ The plugin's dependencies are successfully initialized and
+ extensionsInitialized has been called. The loading process is
+ complete.
+ \value Stopped
+ The plugin has been shut down, i.e. the plugin's IPlugin::shutdown() method has been called.
+ \value Deleted
+ The plugin instance has been deleted.
+*/
+using namespace ExtensionSystem;
+using namespace ExtensionSystem::Internal;
+
+/*!
+ \fn bool PluginDependency::operator==(const PluginDependency &other)
+ \internal
+*/
+bool PluginDependency::operator==(const PluginDependency &other)
+{
+ return name == other.name && version == other.version;
+}
+
+/*!
+ \fn PluginSpec::PluginSpec()
+ \internal
+*/
+PluginSpec::PluginSpec()
+ : d(new PluginSpecPrivate(this))
+{
+}
+
+/*!
+ \fn PluginSpec::~PluginSpec()
+ \internal
+*/
+PluginSpec::~PluginSpec()
+{
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn QString PluginSpec::name() const
+ The plugin name. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::name() const
+{
+ return d->name;
+}
+
+/*!
+ \fn QString PluginSpec::version() const
+ The plugin version. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::version() const
+{
+ return d->version;
+}
+
+/*!
+ \fn QString PluginSpec::compatVersion() const
+ The plugin compatibility version. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::compatVersion() const
+{
+ return d->compatVersion;
+}
+
+/*!
+ \fn QString PluginSpec::vendor() const
+ The plugin vendor. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::vendor() const
+{
+ return d->vendor;
+}
+
+/*!
+ \fn QString PluginSpec::copyright() const
+ The plugin copyright. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::copyright() const
+{
+ return d->copyright;
+}
+
+/*!
+ \fn QString PluginSpec::license() const
+ The plugin license. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::license() const
+{
+ return d->license;
+}
+
+/*!
+ \fn QString PluginSpec::description() const
+ The plugin description. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::description() const
+{
+ return d->description;
+}
+
+/*!
+ \fn QString PluginSpec::url() const
+ The plugin url where you can find more information about the plugin. This is valid after the PluginSpec::Read state is reached.
+*/
+QString PluginSpec::url() const
+{
+ return d->url;
+}
+
+/*!
+ \fn QList<PluginDependency> PluginSpec::dependencies() const
+ The plugin dependencies. This is valid after the PluginSpec::Read state is reached.
+*/
+QList<PluginDependency> PluginSpec::dependencies() const
+{
+ return d->dependencies;
+}
+
+/*!
+ \fn PluginOptionDescriptions optionDescriptions() const
+ Returns a list of descriptions of command line arguments the plugin processes.
+*/
+
+PluginSpec::PluginArgumentDescriptions PluginSpec::argumentDescriptions() const
+{
+ return d->argumentDescriptions;
+}
+
+/*!
+ \fn QString PluginSpec::location() const
+ The absolute path to the directory containing the plugin xml description file
+ this PluginSpec corresponds to.
+*/
+QString PluginSpec::location() const
+{
+ return d->location;
+}
+
+/*!
+ \fn QString PluginSpec::filePath() const
+ The absolute path to the plugin xml description file (including the file name)
+ this PluginSpec corresponds to.
+*/
+QString PluginSpec::filePath() const
+{
+ return d->filePath;
+}
+
+/*!
+ \fn QStringList PluginSpec::arguments() const
+ Command line arguments specific to that plugin. Set at startup
+*/
+
+QStringList PluginSpec::arguments() const
+{
+ return d->arguments;
+}
+
+/*!
+ \fn void PluginSpec::setArguments(const QStringList &arguments)
+ Set the command line arguments specific to that plugin to \a arguments.
+*/
+
+void PluginSpec::setArguments(const QStringList &arguments)
+{
+ d->arguments = arguments;
+}
+
+/*!
+ \fn PluginSpec::addArgument(const QString &argument)
+ Adds \a argument to the command line arguments specific to that plugin.
+*/
+
+void PluginSpec::addArgument(const QString &argument)
+{
+ d->arguments.push_back(argument);
+}
+
+
+/*!
+ \fn PluginSpec::State PluginSpec::state() const
+ The state in which the plugin currently is.
+ See the description of the PluginSpec::State enum for details.
+*/
+PluginSpec::State PluginSpec::state() const
+{
+ return d->state;
+}
+
+/*!
+ \fn bool PluginSpec::hasError() const
+ Returns whether an error occurred while reading/starting the plugin.
+*/
+bool PluginSpec::hasError() const
+{
+ return d->hasError;
+}
+
+/*!
+ \fn QString PluginSpec::errorString() const
+ Detailed, possibly multi-line, error description in case of an error.
+*/
+QString PluginSpec::errorString() const
+{
+ return d->errorString;
+}
+
+/*!
+ \fn bool PluginSpec::provides(const QString &pluginName, const QString &version) const
+ Returns if this plugin can be used to fill in a dependency of the given
+ \a pluginName and \a version.
+
+ \sa PluginSpec::dependencies()
+*/
+bool PluginSpec::provides(const QString &pluginName, const QString &version) const
+{
+ return d->provides(pluginName, version);
+}
+
+/*!
+ \fn IPlugin *PluginSpec::plugin() const
+ The corresponding IPlugin instance, if the plugin library has already been successfully loaded,
+ i.e. the PluginSpec::Loaded state is reached.
+*/
+IPlugin *PluginSpec::plugin() const
+{
+ return d->plugin;
+}
+
+/*!
+ \fn QList<PluginSpec *> PluginSpec::dependencySpecs() const
+ Returns the list of dependencies, already resolved to existing plugin specs.
+ Valid if PluginSpec::Resolved state is reached.
+
+ \sa PluginSpec::dependencies()
+*/
+QList<PluginSpec *> PluginSpec::dependencySpecs() const
+{
+ return d->dependencySpecs;
+}
+
+//==========PluginSpecPrivate==================
+
+namespace {
+ const char * const PLUGIN = "plugin";
+ const char * const PLUGIN_NAME = "name";
+ const char * const PLUGIN_VERSION = "version";
+ const char * const PLUGIN_COMPATVERSION = "compatVersion";
+ const char * const VENDOR = "vendor";
+ const char * const COPYRIGHT = "copyright";
+ const char * const LICENSE = "license";
+ const char * const DESCRIPTION = "description";
+ const char * const URL = "url";
+ const char * const DEPENDENCYLIST = "dependencyList";
+ const char * const DEPENDENCY = "dependency";
+ const char * const DEPENDENCY_NAME = "name";
+ const char * const DEPENDENCY_VERSION = "version";
+ const char * const ARGUMENTLIST = "argumentList";
+ const char * const ARGUMENT = "argument";
+ const char * const ARGUMENT_NAME = "name";
+ const char * const ARGUMENT_PARAMETER = "parameter";
+}
+/*!
+ \fn PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
+ \internal
+*/
+PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
+ : plugin(0),
+ state(PluginSpec::Invalid),
+ hasError(false),
+ q(spec)
+{
+}
+
+/*!
+ \fn bool PluginSpecPrivate::read(const QString &fileName)
+ \internal
+*/
+bool PluginSpecPrivate::read(const QString &fileName)
+{
+ name
+ = version
+ = compatVersion
+ = vendor
+ = copyright
+ = license
+ = description
+ = url
+ = location
+ = "";
+ state = PluginSpec::Invalid;
+ hasError = false;
+ errorString = "";
+ dependencies.clear();
+ QFile file(fileName);
+ if (!file.exists())
+ return reportError(tr("File does not exist: %1").arg(file.fileName()));
+ if (!file.open(QIODevice::ReadOnly))
+ return reportError(tr("Could not open file for read: %1").arg(file.fileName()));
+ QFileInfo fileInfo(file);
+ location = fileInfo.absolutePath();
+ filePath = fileInfo.absoluteFilePath();
+ QXmlStreamReader reader(&file);
+ while (!reader.atEnd()) {
+ reader.readNext();
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ readPluginSpec(reader);
+ break;
+ default:
+ break;
+ }
+ }
+ if (reader.hasError())
+ return reportError(tr("Error parsing file %1: %2, at line %3, column %4")
+ .arg(file.fileName())
+ .arg(reader.errorString())
+ .arg(reader.lineNumber())
+ .arg(reader.columnNumber()));
+ state = PluginSpec::Read;
+ return true;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::reportError(const QString &err)
+ \internal
+*/
+bool PluginSpecPrivate::reportError(const QString &err)
+{
+ errorString = err;
+ hasError = true;
+ return false;
+}
+
+static inline QString msgAttributeMissing(const char *elt, const char *attribute)
+{
+ return QCoreApplication::translate("PluginSpec", "'%1' misses attribute '%2'").arg(QLatin1String(elt), QLatin1String(attribute));
+}
+
+static inline QString msgInvalidFormat(const char *content)
+{
+ return QCoreApplication::translate("PluginSpec", "'%1' has invalid format").arg(content);
+}
+
+static inline QString msgInvalidElement(const QString &name)
+{
+ return QCoreApplication::translate("PluginSpec", "Invalid element '%1'").arg(name);
+}
+
+static inline QString msgUnexpectedClosing(const QString &name)
+{
+ return QCoreApplication::translate("PluginSpec", "Unexpected closing element '%1'").arg(name);
+}
+
+static inline QString msgUnexpectedToken()
+{
+ return QCoreApplication::translate("PluginSpec", "Unexpected token");
+}
+
+/*!
+ \fn void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
+ \internal
+*/
+void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
+{
+ QString element = reader.name().toString();
+ if (element != QString(PLUGIN)) {
+ reader.raiseError(QCoreApplication::translate("PluginSpec", "Expected element '%1' as top level element").arg(PLUGIN));
+ return;
+ }
+ name = reader.attributes().value(PLUGIN_NAME).toString();
+ if (name.isEmpty()) {
+ reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_NAME));
+ return;
+ }
+ version = reader.attributes().value(PLUGIN_VERSION).toString();
+ if (version.isEmpty()) {
+ reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_VERSION));
+ return;
+ }
+ if (!isValidVersion(version)) {
+ reader.raiseError(msgInvalidFormat(PLUGIN_VERSION));
+ return;
+ }
+ compatVersion = reader.attributes().value(PLUGIN_COMPATVERSION).toString();
+ if (!compatVersion.isEmpty() && !isValidVersion(compatVersion)) {
+ reader.raiseError(msgInvalidFormat(PLUGIN_COMPATVERSION));
+ return;
+ } else if (compatVersion.isEmpty()) {
+ compatVersion = version;
+ }
+ while (!reader.atEnd()) {
+ reader.readNext();
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ element = reader.name().toString();
+ if (element == VENDOR)
+ vendor = reader.readElementText().trimmed();
+ else if (element == COPYRIGHT)
+ copyright = reader.readElementText().trimmed();
+ else if (element == LICENSE)
+ license = reader.readElementText().trimmed();
+ else if (element == DESCRIPTION)
+ description = reader.readElementText().trimmed();
+ else if (element == URL)
+ url = reader.readElementText().trimmed();
+ else if (element == DEPENDENCYLIST)
+ readDependencies(reader);
+ else if (element == ARGUMENTLIST)
+ readArgumentDescriptions(reader);
+ else
+ reader.raiseError(msgInvalidElement(name));
+ break;
+ case QXmlStreamReader::EndDocument:
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::EndElement:
+ case QXmlStreamReader::Characters:
+ break;
+ default:
+ reader.raiseError(msgUnexpectedToken());
+ break;
+ }
+ }
+}
+
+/*!
+ \fn void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
+ \internal
+*/
+
+void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
+{
+ QString element;
+ while (!reader.atEnd()) {
+ reader.readNext();
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ element = reader.name().toString();
+ if (element == ARGUMENT) {
+ readArgumentDescription(reader);
+ } else {
+ reader.raiseError(msgInvalidElement(name));
+ }
+ break;
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::Characters:
+ break;
+ case QXmlStreamReader::EndElement:
+ element = reader.name().toString();
+ if (element == ARGUMENTLIST)
+ return;
+ reader.raiseError(msgUnexpectedClosing(element));
+ break;
+ default:
+ reader.raiseError(msgUnexpectedToken());
+ break;
+ }
+ }
+}
+
+/*!
+ \fn void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
+ \internal
+*/
+void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
+{
+ PluginArgumentDescription arg;
+ arg.name = reader.attributes().value(ARGUMENT_NAME).toString();
+ if (arg.name.isEmpty()) {
+ reader.raiseError(msgAttributeMissing(ARGUMENT, ARGUMENT_NAME));
+ return;
+ }
+ arg.parameter = reader.attributes().value(ARGUMENT_PARAMETER).toString();
+ arg.description = reader.readElementText();
+ if (reader.tokenType() != QXmlStreamReader::EndElement)
+ reader.raiseError(msgUnexpectedToken());
+ argumentDescriptions.push_back(arg);
+}
+
+/*!
+ \fn void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
+ \internal
+*/
+void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
+{
+ QString element;
+ while (!reader.atEnd()) {
+ reader.readNext();
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ element = reader.name().toString();
+ if (element == DEPENDENCY) {
+ readDependencyEntry(reader);
+ } else {
+ reader.raiseError(msgInvalidElement(name));
+ }
+ break;
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::Characters:
+ break;
+ case QXmlStreamReader::EndElement:
+ element = reader.name().toString();
+ if (element == DEPENDENCYLIST)
+ return;
+ reader.raiseError(msgUnexpectedClosing(element));
+ break;
+ default:
+ reader.raiseError(msgUnexpectedToken());
+ break;
+ }
+ }
+}
+
+/*!
+ \fn void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
+ \internal
+*/
+void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
+{
+ PluginDependency dep;
+ dep.name = reader.attributes().value(DEPENDENCY_NAME).toString();
+ if (dep.name.isEmpty()) {
+ reader.raiseError(msgAttributeMissing(DEPENDENCY, DEPENDENCY_NAME));
+ return;
+ }
+ dep.version = reader.attributes().value(DEPENDENCY_VERSION).toString();
+ if (!dep.version.isEmpty() && !isValidVersion(dep.version)) {
+ reader.raiseError(msgInvalidFormat(DEPENDENCY_VERSION));
+ return;
+ }
+ dependencies.append(dep);
+ reader.readNext();
+ if (reader.tokenType() != QXmlStreamReader::EndElement)
+ reader.raiseError(msgUnexpectedToken());
+}
+
+/*!
+ \fn bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
+ \internal
+*/
+bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
+{
+ if (QString::compare(pluginName, name, Qt::CaseInsensitive) != 0)
+ return false;
+ return (versionCompare(version, pluginVersion) >= 0) && (versionCompare(compatVersion, pluginVersion) <= 0);
+}
+
+/*!
+ \fn QRegExp &PluginSpecPrivate::versionRegExp()
+ \internal
+*/
+QRegExp &PluginSpecPrivate::versionRegExp()
+{
+ static QRegExp reg("([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?");
+ return reg;
+}
+/*!
+ \fn bool PluginSpecPrivate::isValidVersion(const QString &version)
+ \internal
+*/
+bool PluginSpecPrivate::isValidVersion(const QString &version)
+{
+ return versionRegExp().exactMatch(version);
+}
+
+/*!
+ \fn int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
+ \internal
+*/
+int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
+{
+ QRegExp reg1 = versionRegExp();
+ QRegExp reg2 = versionRegExp();
+ if (!reg1.exactMatch(version1))
+ return 0;
+ if (!reg2.exactMatch(version2))
+ return 0;
+ int number1;
+ int number2;
+ for (int i = 0; i < 4; ++i) {
+ number1 = reg1.cap(i+1).toInt();
+ number2 = reg2.cap(i+1).toInt();
+ if (number1 < number2)
+ return -1;
+ if (number1 > number2)
+ return 1;
+ }
+ return 0;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::resolveDependencies(const QSet<PluginSpec *> &specs)
+ \internal
+*/
+bool PluginSpecPrivate::resolveDependencies(const QSet<PluginSpec *> &specs)
+{
+ if (hasError)
+ return false;
+ if (state == PluginSpec::Resolved)
+ state = PluginSpec::Read; // Go back, so we just re-resolve the dependencies.
+ if (state != PluginSpec::Read) {
+ errorString = QCoreApplication::translate("PluginSpec", "Resolving dependencies failed because state != Read");
+ hasError = true;
+ return false;
+ }
+ QList<PluginSpec *> resolvedDependencies;
+ foreach (const PluginDependency &dependency, dependencies) {
+ PluginSpec *found = 0;
+ foreach (PluginSpec *spec, specs) {
+ if (spec->provides(dependency.name, dependency.version)) {
+ found = spec;
+ break;
+ }
+ }
+ if (!found) {
+ hasError = true;
+ if (!errorString.isEmpty())
+ errorString.append("\n");
+ errorString.append(QCoreApplication::translate("PluginSpec", "Could not resolve dependency '%1(%2)'")
+ .arg(dependency.name).arg(dependency.version));
+ continue;
+ }
+ resolvedDependencies.append(found);
+ }
+ if (hasError)
+ return false;
+ dependencySpecs = resolvedDependencies;
+ state = PluginSpec::Resolved;
+ return true;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::loadLibrary()
+ \internal
+*/
+bool PluginSpecPrivate::loadLibrary()
+{
+ if (hasError)
+ return false;
+ if (state != PluginSpec::Resolved) {
+ if (state == PluginSpec::Loaded)
+ return true;
+ errorString = QCoreApplication::translate("PluginSpec", "Loading the library failed because state != Resolved");
+ hasError = true;
+ return false;
+ }
+#ifdef QT_NO_DEBUG
+
+#ifdef Q_OS_WIN
+ QString libName = QString("%1/%2.dll").arg(location).arg(name);
+#elif defined(Q_OS_MAC)
+ QString libName = QString("%1/lib%2.dylib").arg(location).arg(name);
+#else
+ QString libName = QString("%1/lib%2.so").arg(location).arg(name);
+#endif
+
+#else //Q_NO_DEBUG
+
+#ifdef Q_OS_WIN
+ QString libName = QString("%1/%2d.dll").arg(location).arg(name);
+#elif defined(Q_OS_MAC)
+ QString libName = QString("%1/lib%2_debug.dylib").arg(location).arg(name);
+#else
+ QString libName = QString("%1/lib%2.so").arg(location).arg(name);
+#endif
+
+#endif
+
+ QPluginLoader loader(libName);
+ if (!loader.load()) {
+ hasError = true;
+ errorString = loader.errorString();
+ errorString.append(QCoreApplication::translate("PluginSpec", "\nLibrary base name: %1").arg(libName));
+ return false;
+ }
+ IPlugin *pluginObject = qobject_cast<IPlugin*>(loader.instance());
+ if (!pluginObject) {
+ hasError = true;
+ errorString = QCoreApplication::translate("PluginSpec", "Plugin is not valid (doesn't derive from IPlugin)");
+ loader.unload();
+ return false;
+ }
+ state = PluginSpec::Loaded;
+ plugin = pluginObject;
+ plugin->d->pluginSpec = q;
+ return true;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::initializePlugin()
+ \internal
+*/
+bool PluginSpecPrivate::initializePlugin()
+{
+ if (hasError)
+ return false;
+ if (state != PluginSpec::Loaded) {
+ if (state == PluginSpec::Initialized)
+ return true;
+ errorString = QCoreApplication::translate("PluginSpec", "Initializing the plugin failed because state != Loaded");
+ hasError = true;
+ return false;
+ }
+ if (!plugin) {
+ errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to initialize");
+ hasError = true;
+ return false;
+ }
+ QString err;
+ if (!plugin->initialize(arguments, &err)) {
+ errorString = QCoreApplication::translate("PluginSpec", "Plugin initialization failed: %1").arg(err);
+ hasError = true;
+ return false;
+ }
+ state = PluginSpec::Initialized;
+ return true;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::initializeExtensions()
+ \internal
+*/
+bool PluginSpecPrivate::initializeExtensions()
+{
+ if (hasError)
+ return false;
+ if (state != PluginSpec::Initialized) {
+ if (state == PluginSpec::Running)
+ return true;
+ errorString = QCoreApplication::translate("PluginSpec", "Cannot perform extensionsInitialized because state != Initialized");
+ hasError = true;
+ return false;
+ }
+ if (!plugin) {
+ errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to perform extensionsInitialized");
+ hasError = true;
+ return false;
+ }
+ plugin->extensionsInitialized();
+ state = PluginSpec::Running;
+ return true;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::stop()
+ \internal
+*/
+void PluginSpecPrivate::stop()
+{
+ if (!plugin)
+ return;
+ plugin->shutdown();
+ state = PluginSpec::Stopped;
+}
+
+/*!
+ \fn bool PluginSpecPrivate::kill()
+ \internal
+*/
+void PluginSpecPrivate::kill()
+{
+ if (!plugin)
+ return;
+ delete plugin;
+ plugin = 0;
+ state = PluginSpec::Deleted;
+}
+
diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h
new file mode 100644
index 0000000000..06a219fe2d
--- /dev/null
+++ b/src/libs/extensionsystem/pluginspec.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINSPEC_H
+#define PLUGINSPEC_H
+
+#include "extensionsystem_global.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace ExtensionSystem {
+
+namespace Internal {
+ class PluginSpecPrivate;
+ class PluginManagerPrivate;
+}
+
+class IPlugin;
+
+struct EXTENSIONSYSTEM_EXPORT PluginDependency
+{
+ QString name;
+ QString version;
+ bool operator==(const PluginDependency &other);
+};
+
+struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription
+{
+ QString name;
+ QString parameter;
+ QString description;
+};
+
+class EXTENSIONSYSTEM_EXPORT PluginSpec
+{
+public:
+ enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted};
+
+ ~PluginSpec();
+
+ // information from the xml file, valid after 'Read' state is reached
+ QString name() const;
+ QString version() const;
+ QString compatVersion() const;
+ QString vendor() const;
+ QString copyright() const;
+ QString license() const;
+ QString description() const;
+ QString url() const;
+ QList<PluginDependency> dependencies() const;
+
+ typedef QList<PluginArgumentDescription> PluginArgumentDescriptions;
+ PluginArgumentDescriptions argumentDescriptions() const;
+
+ // other information, valid after 'Read' state is reached
+ QString location() const;
+ QString filePath() const;
+
+ QStringList arguments() const;
+ void setArguments(const QStringList &arguments);
+ void addArgument(const QString &argument);
+
+ bool provides(const QString &pluginName, const QString &version) const;
+
+ // dependency specs, valid after 'Resolved' state is reached
+ QList<PluginSpec *> dependencySpecs() const;
+
+ // linked plugin instance, valid after 'Loaded' state is reached
+ IPlugin *plugin() const;
+
+ // state
+ State state() const;
+ bool hasError() const;
+ QString errorString() const;
+
+private:
+ PluginSpec();
+
+ Internal::PluginSpecPrivate *d;
+ friend class Internal::PluginManagerPrivate;
+};
+
+} // namespace ExtensionSystem
+
+#endif // PLUGINSPEC_H
+
diff --git a/src/libs/extensionsystem/pluginspec_p.h b/src/libs/extensionsystem/pluginspec_p.h
new file mode 100644
index 0000000000..a11167e85e
--- /dev/null
+++ b/src/libs/extensionsystem/pluginspec_p.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINSPEC_P_H
+#define PLUGINSPEC_P_H
+
+#include "pluginspec.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QXmlStreamReader>
+
+namespace ExtensionSystem {
+
+class IPlugin;
+class PluginManager;
+
+namespace Internal {
+
+class EXTENSIONSYSTEM_EXPORT PluginSpecPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ PluginSpecPrivate(PluginSpec *spec);
+
+ bool read(const QString &fileName);
+ bool provides(const QString &pluginName, const QString &version) const;
+ bool resolveDependencies(const QSet<PluginSpec *> &specs);
+ bool loadLibrary();
+ bool initializePlugin();
+ bool initializeExtensions();
+ void stop();
+ void kill();
+
+ QString name;
+ QString version;
+ QString compatVersion;
+ QString vendor;
+ QString copyright;
+ QString license;
+ QString description;
+ QString url;
+ QList<PluginDependency> dependencies;
+
+ QString location;
+ QString filePath;
+ QStringList arguments;
+
+ QList<PluginSpec *> dependencySpecs;
+ PluginSpec::PluginArgumentDescriptions argumentDescriptions;
+ IPlugin *plugin;
+
+ PluginSpec::State state;
+ bool hasError;
+ QString errorString;
+
+ static bool isValidVersion(const QString &version);
+ static int versionCompare(const QString &version1, const QString &version2);
+
+private:
+ PluginSpec *q;
+
+ bool reportError(const QString &err);
+ void readPluginSpec(QXmlStreamReader &reader);
+ void readDependencies(QXmlStreamReader &reader);
+ void readDependencyEntry(QXmlStreamReader &reader);
+ void readArgumentDescriptions(QXmlStreamReader &reader);
+ void readArgumentDescription(QXmlStreamReader &reader);
+
+ static QRegExp &versionRegExp();
+};
+
+} // namespace Internal
+} // namespace ExtensionSystem
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp
new file mode 100644
index 0000000000..d75911ea37
--- /dev/null
+++ b/src/libs/extensionsystem/pluginview.cpp
@@ -0,0 +1,159 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "pluginview.h"
+#include "pluginview_p.h"
+#include "pluginmanager.h"
+#include "pluginspec.h"
+#include "ui_pluginview.h"
+
+#include <QtGui/QHeaderView>
+#include <QtGui/QTreeWidgetItem>
+#include <QtDebug>
+
+/*!
+ \class ExtensionSystem::PluginView
+ \brief Widget that shows a list of all plugins and their state.
+
+ This can be embedded e.g. in a dialog in the application that
+ uses the plugin manager.
+ The class also provides notifications for interactions with the list.
+
+ \sa ExtensionSystem::PluginDetailsView
+ \sa ExtensionSystem::PluginErrorView
+*/
+
+/*!
+ \fn void PluginView::currentPluginChanged(ExtensionSystem::PluginSpec *spec)
+ The current selection in the plugin list has changed to the
+ plugin corresponding to \a spec.
+*/
+
+/*!
+ \fn void PluginView::pluginActivated(ExtensionSystem::PluginSpec *spec)
+ The plugin list entry corresponding to \a spec has been activated,
+ e.g. by a double-click.
+*/
+
+using namespace ExtensionSystem;
+
+Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*);
+
+/*!
+ \fn PluginView::PluginView(PluginManager *manager, QWidget *parent)
+ Constructs a PluginView that gets the list of plugins from the
+ given plugin \a manager with a given \a parent widget.
+*/
+PluginView::PluginView(PluginManager *manager, QWidget *parent)
+ : QWidget(parent),
+ m_ui(new Internal::Ui::PluginView),
+ p(new Internal::PluginViewPrivate)
+{
+ m_ui->setupUi(this);
+ QHeaderView *header = m_ui->pluginWidget->header();
+ header->setResizeMode(0, QHeaderView::ResizeToContents);
+ header->setResizeMode(1, QHeaderView::ResizeToContents);
+ header->setResizeMode(2, QHeaderView::ResizeToContents);
+ m_ui->pluginWidget->sortItems(1, Qt::AscendingOrder);
+ p->manager = manager;
+ connect(p->manager, SIGNAL(pluginsChanged()), this, SLOT(updateList()));
+ connect(m_ui->pluginWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
+ this, SLOT(selectPlugin(QTreeWidgetItem*)));
+ connect(m_ui->pluginWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
+ this, SLOT(activatePlugin(QTreeWidgetItem*)));
+ updateList();
+}
+
+/*!
+ \fn PluginView::~PluginView()
+ \internal
+*/
+PluginView::~PluginView()
+{
+ delete p;
+ delete m_ui;
+}
+
+/*!
+ \fn PluginSpec *PluginView::currentPlugin() const
+ Returns the current selection in the list of plugins.
+*/
+PluginSpec *PluginView::currentPlugin() const
+{
+ if (!m_ui->pluginWidget->currentItem())
+ return 0;
+ return m_ui->pluginWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
+}
+
+void PluginView::updateList()
+{
+ static QIcon okIcon(":/extensionsystem/images/ok.png");
+ static QIcon errorIcon(":/extensionsystem/images/error.png");
+ QList<QTreeWidgetItem *> items;
+ QTreeWidgetItem *currentItem = 0;
+ PluginSpec *currPlugin = currentPlugin();
+ foreach (PluginSpec *spec, p->manager->plugins()) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(QStringList()
+ << ""
+ << spec->name()
+ << QString("%1 (%2)").arg(spec->version()).arg(spec->compatVersion())
+ << spec->vendor()
+ << spec->filePath());
+ item->setToolTip(4, spec->filePath());
+ item->setIcon(0, spec->hasError() ? errorIcon : okIcon);
+ item->setData(0, Qt::UserRole, qVariantFromValue(spec));
+ items.append(item);
+ if (currPlugin == spec)
+ currentItem = item;
+ }
+ m_ui->pluginWidget->clear();
+ if (!items.isEmpty())
+ m_ui->pluginWidget->addTopLevelItems(items);
+ if (currentItem)
+ m_ui->pluginWidget->setCurrentItem(currentItem);
+ else if (!items.isEmpty())
+ m_ui->pluginWidget->setCurrentItem(items.first());
+}
+
+void PluginView::selectPlugin(QTreeWidgetItem *current)
+{
+ if (!current)
+ emit currentPluginChanged(0);
+ else
+ emit currentPluginChanged(current->data(0, Qt::UserRole).value<PluginSpec *>());
+}
+
+void PluginView::activatePlugin(QTreeWidgetItem *item)
+{
+ emit pluginActivated(item->data(0, Qt::UserRole).value<PluginSpec *>());
+}
+
diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h
new file mode 100644
index 0000000000..eacf38edaa
--- /dev/null
+++ b/src/libs/extensionsystem/pluginview.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINVIEW_H
+#define PLUGINVIEW_H
+
+#include "extensionsystem_global.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+namespace ExtensionSystem {
+
+class PluginManager;
+class PluginSpec;
+
+namespace Internal {
+ class PluginViewPrivate;
+namespace Ui {
+ class PluginView;
+} // namespace Ui
+} // namespace Internal
+
+class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PluginView(PluginManager *manager, QWidget *parent = 0);
+ ~PluginView();
+
+ PluginSpec *currentPlugin() const;
+
+signals:
+ void currentPluginChanged(ExtensionSystem::PluginSpec *spec);
+ void pluginActivated(ExtensionSystem::PluginSpec *spec);
+
+private slots:
+ void updateList();
+ void selectPlugin(QTreeWidgetItem *current);
+ void activatePlugin(QTreeWidgetItem *item);
+
+private:
+ Internal::Ui::PluginView *m_ui;
+ Internal::PluginViewPrivate *p;
+};
+
+} // namespae ExtensionSystem
+
+#endif
diff --git a/src/libs/extensionsystem/pluginview.qrc b/src/libs/extensionsystem/pluginview.qrc
new file mode 100644
index 0000000000..7b78566568
--- /dev/null
+++ b/src/libs/extensionsystem/pluginview.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/extensionsystem" >
+ <file>images/ok.png</file>
+ <file>images/error.png</file>
+ </qresource>
+</RCC>
diff --git a/src/libs/extensionsystem/pluginview.ui b/src/libs/extensionsystem/pluginview.ui
new file mode 100644
index 0000000000..8d9123dfbf
--- /dev/null
+++ b/src/libs/extensionsystem/pluginview.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ExtensionSystem::Internal::PluginView</class>
+ <widget class="QWidget" name="ExtensionSystem::Internal::PluginView">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>773</width>
+ <height>304</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QTreeWidget" name="pluginWidget">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="columnCount">
+ <number>5</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>State</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Vendor</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Location</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/extensionsystem/pluginview_p.h b/src/libs/extensionsystem/pluginview_p.h
new file mode 100644
index 0000000000..48d63ba359
--- /dev/null
+++ b/src/libs/extensionsystem/pluginview_p.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINVIEW_P_H
+#define PLUGINVIEW_P_H
+
+namespace ExtensionSystem {
+
+class PluginManager;
+
+namespace Internal {
+
+class PluginViewPrivate
+{
+public:
+ PluginManager *manager;
+};
+
+} // namespace
+} // namespace
+
+#endif
diff --git a/src/libs/extensionsystem/test/auto/auto.pro b/src/libs/extensionsystem/test/auto/auto.pro
new file mode 100644
index 0000000000..2dd6400212
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/auto.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = pluginmanager pluginspec
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro
new file mode 100644
index 0000000000..21f257cf08
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = plugin1 plugin2 plugin3
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml
new file mode 100644
index 0000000000..db201f34c3
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml
@@ -0,0 +1,6 @@
+<plugin name="plugin1" version="1.0.0" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin2" version="1.0.0"/>
+ <dependency name="plugin3" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp
new file mode 100644
index 0000000000..69b9821b3b
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin1.h"
+
+#include <QtCore/qplugin.h>
+
+using namespace Plugin1;
+
+MyPlugin1::MyPlugin1()
+{
+}
+
+bool MyPlugin1::initialize(const QStringList & /*arguments*/, QString *errorString)
+{
+ return true;
+}
+
+void MyPlugin1::extensionsInitialized()
+{
+}
+
+Q_EXPORT_PLUGIN(MyPlugin1)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h
new file mode 100644
index 0000000000..d3c493aeba
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN1_H
+#define PLUGIN1_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace Plugin1 {
+
+class MyPlugin1 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin1();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro
new file mode 100644
index 0000000000..4181188287
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro
@@ -0,0 +1,8 @@
+TEMPLATE = lib
+TARGET = plugin1
+
+SOURCES += plugin1.cpp
+HEADERS += plugin1.h
+
+include(../../../../extensionsystem_test.pri)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml
new file mode 100644
index 0000000000..5436967a80
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml
@@ -0,0 +1,2 @@
+<plugin name="plugin2" version="1.0.0" compatVersion="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp
new file mode 100644
index 0000000000..c5af5f39a3
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin2.h"
+
+#include <QtCore/qplugin.h>
+
+using namespace Plugin2;
+
+MyPlugin2::MyPlugin2()
+{
+}
+
+bool MyPlugin2::initialize(const QStringList &, QString *)
+{
+ return true;
+}
+
+void MyPlugin2::extensionsInitialized()
+{
+}
+
+Q_EXPORT_PLUGIN(MyPlugin2)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h
new file mode 100644
index 0000000000..b1cd95c762
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN2_H
+#define PLUGIN2_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace Plugin2 {
+
+class MyPlugin2 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin2();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro
new file mode 100644
index 0000000000..58798b54f1
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro
@@ -0,0 +1,8 @@
+TEMPLATE = lib
+TARGET = plugin2
+
+SOURCES += plugin2.cpp
+HEADERS += plugin2.h
+
+include(../../../../extensionsystem_test.pri)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml
new file mode 100644
index 0000000000..f7e90978ba
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml
@@ -0,0 +1,5 @@
+<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin1" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp
new file mode 100644
index 0000000000..9b38565c35
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin3.h"
+
+#include <QtCore/qplugin.h>
+
+using namespace Plugin3;
+
+MyPlugin3::MyPlugin3()
+{
+}
+
+bool MyPlugin3::initialize(const QStringList &, QString *)
+{
+ return true;
+}
+
+void MyPlugin3::extensionsInitialized()
+{
+}
+
+Q_EXPORT_PLUGIN(MyPlugin3)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h
new file mode 100644
index 0000000000..7514d63bd7
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN3_H
+#define PLUGIN3_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace Plugin3 {
+
+class MyPlugin3 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin3();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro
new file mode 100644
index 0000000000..f601f06162
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro
@@ -0,0 +1,8 @@
+TEMPLATE = lib
+TARGET = plugin3
+
+SOURCES += plugin3.cpp
+HEADERS += plugin3.h
+
+include(../../../../extensionsystem_test.pri)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro
new file mode 100644
index 0000000000..f0d76950e8
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+SUBDIRS = plugin2 plugin3 plugin1
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec
new file mode 100644
index 0000000000..db201f34c3
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec
@@ -0,0 +1,6 @@
+<plugin name="plugin1" version="1.0.0" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin2" version="1.0.0"/>
+ <dependency name="plugin3" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp
new file mode 100644
index 0000000000..8149d046d2
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin1.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+
+using namespace Plugin1;
+
+MyPlugin1::MyPlugin1()
+ : initializeCalled(false)
+{
+}
+
+bool MyPlugin1::initialize(const QStringList & /*arguments*/, QString *errorString)
+{
+ initializeCalled = true;
+ QObject *obj = new QObject;
+ obj->setObjectName("MyPlugin1");
+ addAutoReleasedObject(obj);
+
+ bool found2 = false;
+ bool found3 = false;
+ foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) {
+ if (object->objectName() == "MyPlugin2")
+ found2 = true;
+ else if (object->objectName() == "MyPlugin3")
+ found3 = true;
+ }
+ if (found2 && found3)
+ return true;
+ if (errorString) {
+ QString error = "object(s) missing from plugin(s):";
+ if (!found2)
+ error.append(" plugin2");
+ if (!found3)
+ error.append(" plugin3");
+ *errorString = error;
+ }
+ return false;
+}
+
+void MyPlugin1::extensionsInitialized()
+{
+ if (!initializeCalled)
+ return;
+ // don't do this at home, it's just done here for the test
+ QObject *obj = new QObject;
+ obj->setObjectName("MyPlugin1_running");
+ addAutoReleasedObject(obj);
+}
+
+Q_EXPORT_PLUGIN(MyPlugin1)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h
new file mode 100644
index 0000000000..4be9f9bbf7
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN1_H
+#define PLUGIN1_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace Plugin1 {
+
+class MyPlugin1 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin1();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+private:
+ bool initializeCalled;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro
new file mode 100644
index 0000000000..9101770f9a
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro
@@ -0,0 +1,15 @@
+TEMPLATE = lib
+TARGET = plugin1
+
+SOURCES += plugin1.cpp
+HEADERS += plugin1.h
+
+include(../../../../extensionsystem_test.pri)
+
+LIBS += -L$${PWD}/../plugin2 -L$${PWD}/../plugin3 -lplugin2 -lplugin3
+
+macx {
+} else:unix {
+ QMAKE_RPATHDIR += $${PWD}/../plugin2
+ QMAKE_RPATHDIR += $${PWD}/../plugin3
+}
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec
new file mode 100644
index 0000000000..5436967a80
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec
@@ -0,0 +1,2 @@
+<plugin name="plugin2" version="1.0.0" compatVersion="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp
new file mode 100644
index 0000000000..99f192766a
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin2.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+
+using namespace Plugin2;
+
+MyPlugin2::MyPlugin2()
+ : initializeCalled(false)
+{
+}
+
+bool MyPlugin2::initialize(const QStringList &, QString *)
+{
+ initializeCalled = true;
+ QObject *obj = new QObject;
+ obj->setObjectName("MyPlugin2");
+ addAutoReleasedObject(obj);
+
+ return true;
+}
+
+void MyPlugin2::extensionsInitialized()
+{
+ if (!initializeCalled)
+ return;
+ // don't do this at home, it's just done here for the test
+ QObject *obj = new QObject;
+ obj->setObjectName("MyPlugin2_running");
+ addAutoReleasedObject(obj);
+}
+
+Q_EXPORT_PLUGIN(MyPlugin2)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h
new file mode 100644
index 0000000000..08d77a38c7
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN2_H
+#define PLUGIN2_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace Plugin2 {
+
+class MyPlugin2 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin2();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+private:
+ bool initializeCalled;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro
new file mode 100644
index 0000000000..a80f4a5c76
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+TARGET = plugin2
+
+SOURCES += plugin2.cpp
+HEADERS += plugin2.h
+
+include(../../../../extensionsystem_test.pri)
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/
+}
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec
new file mode 100644
index 0000000000..234bf56ea2
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec
@@ -0,0 +1,5 @@
+<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin2" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp
new file mode 100644
index 0000000000..4410c34511
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin3.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+
+using namespace Plugin3;
+
+MyPlugin3::MyPlugin3()
+ : initializeCalled(false)
+{
+}
+
+bool MyPlugin3::initialize(const QStringList & /*arguments*/, QString *errorString)
+{
+ initializeCalled = true;
+ QObject *obj = new QObject;
+ obj->setObjectName("MyPlugin3");
+ addAutoReleasedObject(obj);
+
+ bool found2 = false;
+ foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) {
+ if (object->objectName() == "MyPlugin2")
+ found2 = true;
+ }
+ if (found2)
+ return true;
+ if (errorString)
+ *errorString = "object from plugin2 could not be found";
+ return false;
+}
+
+void MyPlugin3::extensionsInitialized()
+{
+ if (!initializeCalled)
+ return;
+ // don't do this at home, it's just done here for the test
+ QObject *obj = new QObject;
+ obj->setObjectName("MyPlugin3_running");
+ addAutoReleasedObject(obj);
+}
+
+Q_EXPORT_PLUGIN(MyPlugin3)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h
new file mode 100644
index 0000000000..0991b7a152
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN3_H
+#define PLUGIN3_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace Plugin3 {
+
+class MyPlugin3 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin3();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+private:
+ bool initializeCalled;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro
new file mode 100644
index 0000000000..c5ff581b1b
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro
@@ -0,0 +1,15 @@
+TEMPLATE = lib
+TARGET = plugin3
+
+SOURCES += plugin3.cpp
+HEADERS += plugin3.h
+
+include(../../../../extensionsystem_test.pri)
+
+LIBS += -L$${PWD}/../plugin2 -lplugin2
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/
+} else:unix {
+ QMAKE_RPATHDIR += $${PWD}/../plugin2
+}
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro b/src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro
new file mode 100644
index 0000000000..57b026f5fb
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+
+SUBDIRS = test.pro \
+ circularplugins \
+ correctplugins1
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml
new file mode 100644
index 0000000000..c79b29780d
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml
@@ -0,0 +1,2 @@
+<plugin name="dummyPlugin" version="1.1.1" compatVersion="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml
new file mode 100644
index 0000000000..6f0483f0f8
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml
@@ -0,0 +1,2 @@
+<plugin name="helloworld" version="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml
new file mode 100644
index 0000000000..6bd573957b
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml
@@ -0,0 +1,2 @@
+<plugin name="MyPlugin" version="2.2.3_9" compatVersion="2.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/test.pro b/src/libs/extensionsystem/test/auto/pluginmanager/test.pro
new file mode 100644
index 0000000000..c5934b1331
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/test.pro
@@ -0,0 +1,14 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Fr Jul 27 23:12:52 2007
+######################################################################
+
+CONFIG += qtestlib
+TEMPLATE = app
+CONFIG -= app_bundle
+
+# Input
+
+include(../../extensionsystem_test.pri)
+
+SOURCES += tst_pluginmanager.cpp
+
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/test.sh b/src/libs/extensionsystem/test/auto/pluginmanager/test.sh
new file mode 100755
index 0000000000..426901ea74
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/test.sh
@@ -0,0 +1,5 @@
+# -- run the plugin test from this directory.
+
+export LD_LIBRARY_PATH=../../../../../../lib:$LD_LIBRARY_PATH
+export DYLD_LIBRARY_PATH=../../../../../../bin/QtCreator.app/Contents/PlugIns:$DYLD_LIBRARY_PATH # mac
+exec ./test
diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp
new file mode 100644
index 0000000000..f54b978e9a
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp
@@ -0,0 +1,267 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtTest/QtTest>
+
+#include <QtCore/QObject>
+
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginspec.h>
+#include <extensionsystem/iplugin.h>
+
+using namespace ExtensionSystem;
+
+class SignalReceiver;
+
+class tst_PluginManager : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void init();
+ void cleanup();
+ void addRemoveObjects();
+ void getObject();
+ void getObjects();
+ void plugins();
+ void circularPlugins();
+ void correctPlugins1();
+
+private:
+ PluginManager *m_pm;
+ SignalReceiver *m_sr;
+};
+
+class SignalReceiver : public QObject
+{
+ Q_OBJECT
+
+public:
+ SignalReceiver() :
+ objectAddedCount(0),
+ aboutToRemoveObjectCount(0),
+ pluginsChangedCount(0),
+ objectAddedObj(0),
+ aboutToRemoveObjectObj(0)
+ { }
+ int objectAddedCount;
+ int aboutToRemoveObjectCount;
+ int pluginsChangedCount;
+ QObject *objectAddedObj;
+ QObject *aboutToRemoveObjectObj;
+public slots:
+ void objectAdded(QObject *obj) { objectAddedCount++; objectAddedObj = obj; }
+ void aboutToRemoveObject(QObject *obj) { aboutToRemoveObjectCount++; aboutToRemoveObjectObj = obj; }
+ void pluginsChanged() { pluginsChangedCount++; }
+};
+
+class MyClass1 : public QObject
+{
+ Q_OBJECT
+};
+
+class MyClass2 : public QObject
+{
+ Q_OBJECT
+};
+
+class MyClass11 : public MyClass1
+{
+ Q_OBJECT
+};
+
+void tst_PluginManager::init()
+{
+ m_pm = new PluginManager;
+ m_sr = new SignalReceiver;
+ connect(m_pm, SIGNAL(objectAdded(QObject*)), m_sr, SLOT(objectAdded(QObject*)));
+ connect(m_pm, SIGNAL(aboutToRemoveObject(QObject*)), m_sr, SLOT(aboutToRemoveObject(QObject*)));
+ connect(m_pm, SIGNAL(pluginsChanged()), m_sr, SLOT(pluginsChanged()));
+}
+
+void tst_PluginManager::cleanup()
+{
+ delete m_pm;
+ delete m_sr;
+}
+
+void tst_PluginManager::addRemoveObjects()
+{
+ QObject *object1 = new QObject;
+ QObject *object2 = new QObject;
+ QCOMPARE(m_pm->allObjects().size(), 0);
+ m_pm->addObject(object1);
+ QCOMPARE(m_sr->objectAddedCount, 1);
+ QCOMPARE(m_sr->objectAddedObj, object1);
+ QCOMPARE(m_sr->aboutToRemoveObjectCount, 0);
+ QVERIFY(m_pm->allObjects().contains(object1));
+ QVERIFY(!m_pm->allObjects().contains(object2));
+ QCOMPARE(m_pm->allObjects().size(), 1);
+ m_pm->addObject(object2);
+ QCOMPARE(m_sr->objectAddedCount, 2);
+ QCOMPARE(m_sr->objectAddedObj, object2);
+ QCOMPARE(m_sr->aboutToRemoveObjectCount, 0);
+ QVERIFY(m_pm->allObjects().contains(object1));
+ QVERIFY(m_pm->allObjects().contains(object2));
+ QCOMPARE(m_pm->allObjects().size(), 2);
+ m_pm->removeObject(object1);
+ QCOMPARE(m_sr->objectAddedCount, 2);
+ QCOMPARE(m_sr->aboutToRemoveObjectCount, 1);
+ QCOMPARE(m_sr->aboutToRemoveObjectObj, object1);
+ QVERIFY(!m_pm->allObjects().contains(object1));
+ QVERIFY(m_pm->allObjects().contains(object2));
+ QCOMPARE(m_pm->allObjects().size(), 1);
+ m_pm->removeObject(object2);
+ QCOMPARE(m_sr->objectAddedCount, 2);
+ QCOMPARE(m_sr->aboutToRemoveObjectCount, 2);
+ QCOMPARE(m_sr->aboutToRemoveObjectObj, object2);
+ QVERIFY(!m_pm->allObjects().contains(object1));
+ QVERIFY(!m_pm->allObjects().contains(object2));
+ QCOMPARE(m_pm->allObjects().size(), 0);
+ delete object1;
+ delete object2;
+}
+
+void tst_PluginManager::getObject()
+{
+ MyClass2 *object2 = new MyClass2;
+ MyClass11 *object11 = new MyClass11;
+ m_pm->addObject(object2);
+ QCOMPARE(m_pm->getObject<MyClass11>(), (MyClass11*)0);
+ QCOMPARE(m_pm->getObject<MyClass1>(), (MyClass1*)0);
+ QCOMPARE(m_pm->getObject<MyClass2>(), object2);
+ m_pm->addObject(object11);
+ QCOMPARE(m_pm->getObject<MyClass11>(), object11);
+ QCOMPARE(m_pm->getObject<MyClass1>(), qobject_cast<MyClass1*>(object11));
+ QCOMPARE(m_pm->getObject<MyClass2>(), object2);
+ m_pm->removeObject(object2);
+ m_pm->removeObject(object11);
+ delete object2;
+ delete object11;
+}
+
+void tst_PluginManager::getObjects()
+{
+ MyClass1 *object1 = new MyClass1;
+ MyClass2 *object2 = new MyClass2;
+ MyClass11 *object11 = new MyClass11;
+ m_pm->addObject(object2);
+ QCOMPARE(m_pm->getObjects<MyClass11>(), QList<MyClass11*>());
+ QCOMPARE(m_pm->getObjects<MyClass1>(), QList<MyClass1*>());
+ QCOMPARE(m_pm->getObjects<MyClass2>(), QList<MyClass2*>() << object2);
+ QCOMPARE(m_pm->allObjects(), QList<QObject*>() << object2);
+ m_pm->addObject(object11);
+ QCOMPARE(m_pm->getObjects<MyClass11>(), QList<MyClass11*>() << object11);
+ QCOMPARE(m_pm->getObjects<MyClass1>(), QList<MyClass1*>() << object11);
+ QCOMPARE(m_pm->getObjects<MyClass2>(), QList<MyClass2*>() << object2);
+ QCOMPARE(m_pm->allObjects(), QList<QObject*>() << object2 << object11);
+ m_pm->addObject(object1);
+ QCOMPARE(m_pm->getObjects<MyClass11>(), QList<MyClass11*>() << object11);
+ QCOMPARE(m_pm->getObjects<MyClass1>(), QList<MyClass1*>() << object11 << object1);
+ QCOMPARE(m_pm->getObjects<MyClass2>(), QList<MyClass2*>() << object2);
+ QCOMPARE(m_pm->allObjects(), QList<QObject*>() << object2 << object11 << object1);
+ m_pm->removeObject(object2);
+ m_pm->removeObject(object11);
+ m_pm->removeObject(object1);
+ delete object1;
+ delete object2;
+ delete object11;
+}
+
+void tst_PluginManager::plugins()
+{
+ m_pm->setPluginPaths(QStringList() << "plugins");
+ QCOMPARE(m_sr->pluginsChangedCount, 1);
+ QSet<PluginSpec *> plugins = m_pm->plugins();
+ QCOMPARE(plugins.count(), 3);
+ foreach (const QString &expected, QStringList() << "helloworld" << "MyPlugin" << "dummyPlugin") {
+ bool found = false;
+ foreach (PluginSpec *spec, plugins) {
+ if (spec->name() == expected) {
+ found = true;
+ break;
+ }
+ }
+ QVERIFY2(found, QString("plugin '%1' not found").arg(expected).toLocal8Bit().constData());
+ }
+}
+
+void tst_PluginManager::circularPlugins()
+{
+ m_pm->setPluginPaths(QStringList() << "circularplugins");
+ m_pm->loadPlugins();
+ foreach (PluginSpec *spec, m_pm->plugins()) {
+ if (spec->name() == "plugin1") {
+ QVERIFY(spec->hasError());
+ QCOMPARE(spec->state(), PluginSpec::Resolved);
+ QCOMPARE(spec->plugin(), (IPlugin*)0);
+ } else if (spec->name() == "plugin2") {
+ QVERIFY(!spec->hasError());
+ QCOMPARE(spec->state(), PluginSpec::Running);
+ } else if (spec->name() == "plugin3") {
+ QVERIFY(spec->hasError());
+ QCOMPARE(spec->state(), PluginSpec::Resolved);
+ QCOMPARE(spec->plugin(), (IPlugin*)0);
+ }
+ }
+}
+
+void tst_PluginManager::correctPlugins1()
+{
+ m_pm->setFileExtension("spec");
+ m_pm->setPluginPaths(QStringList() << "correctplugins1");
+ m_pm->loadPlugins();
+ foreach (PluginSpec *spec, m_pm->plugins()) {
+ if (spec->hasError())
+ qDebug() << spec->errorString();
+ QVERIFY(!spec->hasError());
+ QCOMPARE(spec->state(), PluginSpec::Running);
+ }
+ bool plugin1running = false;
+ bool plugin2running = false;
+ bool plugin3running = false;
+ foreach (QObject *obj, m_pm->allObjects()) {
+ if (obj->objectName() == "MyPlugin1_running")
+ plugin1running = true;
+ else if (obj->objectName() == "MyPlugin2_running")
+ plugin2running = true;
+ else if (obj->objectName() == "MyPlugin3_running")
+ plugin3running = true;
+ }
+ QVERIFY(plugin1running);
+ QVERIFY(plugin2running);
+ QVERIFY(plugin3running);
+}
+
+QTEST_MAIN(tst_PluginManager)
+#include "tst_pluginmanager.moc"
+
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro b/src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro
new file mode 100644
index 0000000000..d4b941b232
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = testplugin test.pro
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/test.pro b/src/libs/extensionsystem/test/auto/pluginspec/test.pro
new file mode 100644
index 0000000000..d8fda88917
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/test.pro
@@ -0,0 +1,14 @@
+CONFIG += qtestlib
+TEMPLATE = app
+CONFIG -= app_bundle
+DESTDIR = $${PWD}
+# Input
+SOURCES += tst_pluginspec.cpp
+
+include(../../extensionsystem_test.pri)
+
+LIBS += -L$${PWD}/testplugin -ltest
+macx {
+} else:unix {
+ QMAKE_RPATHDIR += $${PWD}/testplugin
+}
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/test.sh b/src/libs/extensionsystem/test/auto/pluginspec/test.sh
new file mode 100755
index 0000000000..426901ea74
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/test.sh
@@ -0,0 +1,5 @@
+# -- run the plugin test from this directory.
+
+export LD_LIBRARY_PATH=../../../../../../lib:$LD_LIBRARY_PATH
+export DYLD_LIBRARY_PATH=../../../../../../bin/QtCreator.app/Contents/PlugIns:$DYLD_LIBRARY_PATH # mac
+exec ./test
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml
new file mode 100644
index 0000000000..137e1b494c
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml
@@ -0,0 +1,6 @@
+<plugin name="plugin1" version="1.0.1" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin2" version="2.3.0_2"/>
+ <dependency name="plugin3" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml
new file mode 100644
index 0000000000..451f854185
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml
@@ -0,0 +1,2 @@
+<plugin name="plugin2" version="2.4.1" compatVersion="2.3.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml
new file mode 100644
index 0000000000..9fa01a442f
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml
@@ -0,0 +1,2 @@
+<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml
new file mode 100644
index 0000000000..b06bab2fa0
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml
@@ -0,0 +1,5 @@
+<plugin name="plugin4" version="1.0.1" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin5" version="2.3.0_2"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml
new file mode 100644
index 0000000000..aab8f424c3
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml
@@ -0,0 +1,2 @@
+<plugin name="plugin5" version="1.0.1" compatVersion="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml
new file mode 100644
index 0000000000..6bd573957b
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml
@@ -0,0 +1,2 @@
+<plugin name="MyPlugin" version="2.2.3_9" compatVersion="2.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp
new file mode 100644
index 0000000000..8c3db6c189
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "testplugin.h"
+
+#include <QtCore/qplugin.h>
+
+using namespace MyPlugin;
+
+MyPluginImpl::MyPluginImpl()
+ : m_isInitialized(false), m_isExtensionsInitialized(false)
+{
+}
+
+bool MyPluginImpl::initialize(const QStringList &, QString *)
+{
+ m_isInitialized = true;
+ return true;
+}
+
+void MyPluginImpl::extensionsInitialized()
+{
+ m_isExtensionsInitialized = true;
+}
+
+Q_EXPORT_PLUGIN(MyPluginImpl)
+
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h
new file mode 100644
index 0000000000..10fc0acf50
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TESTPLUGIN_H
+#define TESTPLUGIN_H
+
+#include "testplugin_global.h"
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace MyPlugin {
+
+class MYPLUGIN_EXPORT MyPluginImpl : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPluginImpl();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+ bool isInitialized() { return m_isInitialized; }
+ bool isExtensionsInitialized() { return m_isExtensionsInitialized; }
+private:
+ bool m_isInitialized;
+ bool m_isExtensionsInitialized;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro
new file mode 100644
index 0000000000..8b4d81a82a
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro
@@ -0,0 +1,13 @@
+TEMPLATE = lib
+TARGET = test
+DESTDIR = $${PWD}
+DEFINES += MYPLUGIN_LIBRARY
+SOURCES += testplugin.cpp
+HEADERS += testplugin.h testplugin_global.h
+
+include(../../../extensionsystem_test.pri)
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/
+}
+
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml
new file mode 100644
index 0000000000..f8ab3f7a39
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml
@@ -0,0 +1,2 @@
+<plugin name="test" version="1.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h
new file mode 100644
index 0000000000..ae40ac8ea8
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TESTPLUGIN_GLOBAL_H
+#define TESTPLUGIN_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(MYPLUGIN_LIBRARY)
+# define MYPLUGIN_EXPORT Q_DECL_EXPORT
+#else
+# define MYPLUGIN_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // header
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml
new file mode 100644
index 0000000000..6bd573957b
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml
@@ -0,0 +1,2 @@
+<plugin name="MyPlugin" version="2.2.3_9" compatVersion="2.0.0">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml
new file mode 100644
index 0000000000..31cebf4414
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml
@@ -0,0 +1,18 @@
+<plugin name="test" version="1.0.1" compatVersion="1.0.0">
+ <vendor>Trolltech</vendor>
+ <copyright>(C) 2007 Trolltech ASA</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.trolltech.com</url>
+ <dependencyList>
+ <dependency name="SomeOtherPlugin" version="2.3.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml
new file mode 100644
index 0000000000..454f58cb75
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml
@@ -0,0 +1,2 @@
+<plugin name="test" version="3.1.4_10">
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml
new file mode 100644
index 0000000000..e6fe956c98
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml
@@ -0,0 +1,18 @@
+<something name="test" version="1.0.1" compatVersion="1.0.0">
+ <vendor>Trolltech</vendor>
+ <copyright>(C) 2007 Trolltech ASA</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.trolltech.com</url>
+ <dependencyList>
+ <dependency name="SomeOtherPlugin" version="2.3.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+</something>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml
new file mode 100644
index 0000000000..200a1fd1ac
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml
@@ -0,0 +1,18 @@
+<plugin version="1.0.1" compatVersion="1.0.0">
+ <vendor>Trolltech</vendor>
+ <copyright>(C) 2007 Trolltech ASA</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.trolltech.com</url>
+ <dependencyList>
+ <dependency name="SomeOtherPlugin" version="2.3.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml
new file mode 100644
index 0000000000..13bbdb09a8
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml
@@ -0,0 +1,18 @@
+<plugin name="test" compatVersion="1.0.0">
+ <vendor>Trolltech</vendor>
+ <copyright>(C) 2007 Trolltech ASA</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.trolltech.com</url>
+ <dependencyList>
+ <dependency name="SomeOtherPlugin" version="2.3.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml
new file mode 100644
index 0000000000..b904f90138
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml
@@ -0,0 +1,18 @@
+<plugin name="test" version="1.0.1" compatVersion="1.0.0">
+ <vendor>Trolltech</vendor>
+ <copyright>(C) 2007 Trolltech ASA</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.trolltech.com</url>
+ <dependencyList>
+ <dependency version="2.3.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml
new file mode 100644
index 0000000000..1c110d1eea
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml
@@ -0,0 +1,18 @@
+<plugin name="test" version="1.0.1" compatVersion="1.0.0">
+ <vendor>Trolltech</vendor>
+ <copyright>(C) 2007 Trolltech ASA</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.trolltech.com</url>
+ <dependencyList>
+ <dependency name="SomeOtherPlugin" version="2.3aa.0_2"/>
+ <dependency name="EvenOther" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp b/src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp
new file mode 100644
index 0000000000..f3471edcaa
--- /dev/null
+++ b/src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp
@@ -0,0 +1,278 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtTest/QtTest>
+
+#include "testplugin/testplugin.h"
+
+#include <extensionsystem/pluginspec.h>
+#include <extensionsystem/pluginspec_p.h>
+#include <extensionsystem/pluginmanager_p.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QObject>
+
+using namespace ExtensionSystem;
+
+class tst_PluginSpec : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void read();
+ void readError();
+ void isValidVersion();
+ void versionCompare();
+ void provides();
+ void locationAndPath();
+ void resolveDependencies();
+ void loadLibrary();
+ void initializePlugin();
+ void initializeExtensions();
+};
+
+void tst_PluginSpec::read()
+{
+ Internal::PluginSpecPrivate spec(0);
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.read("testspecs/spec1.xml"));
+ QCOMPARE(spec.state, PluginSpec::Read);
+ QVERIFY(!spec.hasError);
+ QVERIFY(spec.errorString.isEmpty());
+ QCOMPARE(spec.name, QString("test"));
+ QCOMPARE(spec.version, QString("1.0.1"));
+ QCOMPARE(spec.compatVersion, QString("1.0.0"));
+ QCOMPARE(spec.vendor, QString("Trolltech"));
+ QCOMPARE(spec.copyright, QString("(C) 2007 Trolltech ASA"));
+ QCOMPARE(spec.license, QString("This is a default license bla\nblubbblubb\nend of terms"));
+ QCOMPARE(spec.description, QString("This plugin is just a test.\n it demonstrates the great use of the plugin spec."));
+ QCOMPARE(spec.url, QString("http://www.trolltech.com"));
+ PluginDependency dep1;
+ dep1.name = QString("SomeOtherPlugin");
+ dep1.version = QString("2.3.0_2");
+ PluginDependency dep2;
+ dep2.name = QString("EvenOther");
+ dep2.version = QString("1.0.0");
+ QCOMPARE(spec.dependencies, QList<PluginDependency>() << dep1 << dep2);
+
+ // test missing compatVersion behavior
+ QVERIFY(spec.read("testspecs/spec2.xml"));
+ QCOMPARE(spec.version, QString("3.1.4_10"));
+ QCOMPARE(spec.compatVersion, QString("3.1.4_10"));
+}
+
+void tst_PluginSpec::readError()
+{
+ Internal::PluginSpecPrivate spec(0);
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(!spec.read("non-existing-file.xml"));
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.hasError);
+ QVERIFY(!spec.errorString.isEmpty());
+ QVERIFY(!spec.read("testspecs/spec_wrong1.xml"));
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.hasError);
+ QVERIFY(!spec.errorString.isEmpty());
+ QVERIFY(!spec.read("testspecs/spec_wrong2.xml"));
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.hasError);
+ QVERIFY(!spec.errorString.isEmpty());
+ QVERIFY(!spec.read("testspecs/spec_wrong3.xml"));
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.hasError);
+ QVERIFY(!spec.errorString.isEmpty());
+ QVERIFY(!spec.read("testspecs/spec_wrong4.xml"));
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.hasError);
+ QVERIFY(!spec.errorString.isEmpty());
+ QVERIFY(!spec.read("testspecs/spec_wrong5.xml"));
+ QCOMPARE(spec.state, PluginSpec::Invalid);
+ QVERIFY(spec.hasError);
+ QVERIFY(!spec.errorString.isEmpty());
+}
+
+void tst_PluginSpec::isValidVersion()
+{
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("2"));
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("53"));
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("52_1"));
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("3.12"));
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1_12"));
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1.0"));
+ QVERIFY(Internal::PluginSpecPrivate::isValidVersion("1.0.2_1"));
+
+ QVERIFY(!Internal::PluginSpecPrivate::isValidVersion(""));
+ QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1..0"));
+ QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0_"));
+ QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0.0.0"));
+}
+
+void tst_PluginSpec::versionCompare()
+{
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3") == 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0", "3") == 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0", "3") == 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0_1", "3_1") == 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0_21", "3_21") == 0);
+
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1") > 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1.0_12") > 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3_1", "3") > 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1.0_23", "3.1") > 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_23", "3.1_12") > 0);
+
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("1", "3") < 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("1.0_12", "3") < 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3_1") < 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1", "3.1.0_23") < 0);
+ QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_12", "3.1_23") < 0);
+}
+
+void tst_PluginSpec::provides()
+{
+ Internal::PluginSpecPrivate spec(0);
+ QVERIFY(spec.read("testspecs/simplespec.xml"));
+ QVERIFY(!spec.provides("SomeOtherPlugin", "2.2.3_9"));
+ QVERIFY(!spec.provides("MyPlugin", "2.2.3_10"));
+ QVERIFY(!spec.provides("MyPlugin", "2.2.4"));
+ QVERIFY(!spec.provides("MyPlugin", "2.3.11_1"));
+ QVERIFY(!spec.provides("MyPlugin", "2.3"));
+ QVERIFY(!spec.provides("MyPlugin", "3.0"));
+ QVERIFY(!spec.provides("MyPlugin", "1.9.9_99"));
+ QVERIFY(!spec.provides("MyPlugin", "1.9"));
+ QVERIFY(!spec.provides("MyPlugin", "0.9"));
+ QVERIFY(!spec.provides("MyPlugin", "1"));
+
+ QVERIFY(spec.provides("myplugin", "2.2.3_9"));
+ QVERIFY(spec.provides("MyPlugin", "2.2.3_9"));
+ QVERIFY(spec.provides("MyPlugin", "2.2.3_8"));
+ QVERIFY(spec.provides("MyPlugin", "2.2.3"));
+ QVERIFY(spec.provides("MyPlugin", "2.2.2"));
+ QVERIFY(spec.provides("MyPlugin", "2.1.2_10"));
+ QVERIFY(spec.provides("MyPlugin", "2.0_10"));
+ QVERIFY(spec.provides("MyPlugin", "2"));
+}
+
+void tst_PluginSpec::locationAndPath()
+{
+ Internal::PluginSpecPrivate spec(0);
+ QVERIFY(spec.read("testspecs/simplespec.xml"));
+ QCOMPARE(spec.location, QDir::currentPath()+"/testspecs");
+ QCOMPARE(spec.filePath, QDir::currentPath()+"/testspecs/simplespec.xml");
+ QVERIFY(spec.read("testdir/../testspecs/simplespec.xml"));
+ QCOMPARE(spec.location, QDir::currentPath()+"/testspecs");
+ QCOMPARE(spec.filePath, QDir::currentPath()+"/testspecs/simplespec.xml");
+ QVERIFY(spec.read("testdir/spec.xml"));
+ QCOMPARE(spec.location, QDir::currentPath()+"/testdir");
+ QCOMPARE(spec.filePath, QDir::currentPath()+"/testdir/spec.xml");
+}
+
+void tst_PluginSpec::resolveDependencies()
+{
+ QSet<PluginSpec *> specs;
+ PluginSpec *spec1 = Internal::PluginManagerPrivate::createSpec();
+ specs.insert(spec1);
+ Internal::PluginSpecPrivate *spec1Priv = Internal::PluginManagerPrivate::privateSpec(spec1);
+ spec1Priv->read("testdependencies/spec1.xml");
+ PluginSpec *spec2 = Internal::PluginManagerPrivate::createSpec();
+ specs.insert(spec2);
+ Internal::PluginManagerPrivate::privateSpec(spec2)->read("testdependencies/spec2.xml");
+ PluginSpec *spec3 = Internal::PluginManagerPrivate::createSpec();
+ specs.insert(spec3);
+ Internal::PluginManagerPrivate::privateSpec(spec3)->read("testdependencies/spec3.xml");
+ PluginSpec *spec4 = Internal::PluginManagerPrivate::createSpec();
+ specs.insert(spec4);
+ Internal::PluginSpecPrivate *spec4Priv = Internal::PluginManagerPrivate::privateSpec(spec4);
+ spec4Priv->read("testdependencies/spec4.xml");
+ PluginSpec *spec5 = Internal::PluginManagerPrivate::createSpec();
+ specs.insert(spec5);
+ Internal::PluginManagerPrivate::privateSpec(spec5)->read("testdependencies/spec5.xml");
+ QVERIFY(spec1Priv->resolveDependencies(specs));
+ QCOMPARE(spec1Priv->dependencySpecs.size(), 2);
+ QVERIFY(spec1Priv->dependencySpecs.contains(spec2));
+ QVERIFY(spec1Priv->dependencySpecs.contains(spec3));
+ QCOMPARE(spec1Priv->state, PluginSpec::Resolved);
+ QVERIFY(!spec4Priv->resolveDependencies(specs));
+ QVERIFY(spec4Priv->hasError);
+ QCOMPARE(spec4Priv->state, PluginSpec::Read);
+}
+
+void tst_PluginSpec::loadLibrary()
+{
+ PluginSpec *ps = Internal::PluginManagerPrivate::createSpec();
+ Internal::PluginSpecPrivate *spec = Internal::PluginManagerPrivate::privateSpec(ps);
+ PluginManager *manager = new PluginManager();
+ QVERIFY(spec->read("testplugin/testplugin.xml"));
+ QVERIFY(spec->resolveDependencies(QSet<PluginSpec *>()));
+ QVERIFY(spec->loadLibrary());
+ QVERIFY(qobject_cast<MyPlugin::MyPluginImpl*>(spec->plugin) != 0);
+ QCOMPARE(spec->state, PluginSpec::Loaded);
+ QVERIFY(!spec->hasError);
+ QCOMPARE(spec->plugin->pluginSpec(), ps);
+ delete manager;
+ delete ps;
+}
+
+void tst_PluginSpec::initializePlugin()
+{
+ Internal::PluginSpecPrivate spec(0);
+ MyPlugin::MyPluginImpl *impl;
+ QVERIFY(spec.read("testplugin/testplugin.xml"));
+ QVERIFY(spec.resolveDependencies(QSet<PluginSpec *>()));
+ QVERIFY(spec.loadLibrary());
+ impl = qobject_cast<MyPlugin::MyPluginImpl*>(spec.plugin);
+ QVERIFY(impl != 0);
+ QVERIFY(!impl->isInitialized());
+ QVERIFY(spec.initializePlugin());
+ QCOMPARE(spec.state, PluginSpec::Initialized);
+ QVERIFY(!spec.hasError);
+ QVERIFY(impl->isInitialized());
+}
+
+void tst_PluginSpec::initializeExtensions()
+{
+ Internal::PluginSpecPrivate spec(0);
+ MyPlugin::MyPluginImpl *impl;
+ QVERIFY(spec.read("testplugin/testplugin.xml"));
+ QVERIFY(spec.resolveDependencies(QSet<PluginSpec *>()));
+ QVERIFY(spec.loadLibrary());
+ impl = qobject_cast<MyPlugin::MyPluginImpl*>(spec.plugin);
+ QVERIFY(impl != 0);
+ QVERIFY(spec.initializePlugin());
+ QVERIFY(spec.initializeExtensions());
+ QCOMPARE(spec.state, PluginSpec::Running);
+ QVERIFY(!spec.hasError);
+ QVERIFY(impl->isExtensionsInitialized());
+}
+
+QTEST_MAIN(tst_PluginSpec)
+#include "tst_pluginspec.moc"
diff --git a/src/libs/extensionsystem/test/extensionsystem_test.pri b/src/libs/extensionsystem/test/extensionsystem_test.pri
new file mode 100644
index 0000000000..6ad874add3
--- /dev/null
+++ b/src/libs/extensionsystem/test/extensionsystem_test.pri
@@ -0,0 +1,12 @@
+
+INCLUDEPATH *= $$PWD/../..
+macx {
+ LIBPATH*= $$PWD/../../../../bin/QtCreator.app/Contents/PlugIns
+}
+else {
+ LIBPATH*= $$PWD/../../../../lib
+}
+
+include(../extensionsystem.pri)
+
+QT *= xml
diff --git a/src/libs/extensionsystem/test/manual/manual.pro b/src/libs/extensionsystem/test/manual/manual.pro
new file mode 100644
index 0000000000..829f2fce57
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/manual.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = pluginview
+
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp
new file mode 100644
index 0000000000..3282d9862e
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp
@@ -0,0 +1,142 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugindialog.h"
+#include <extensionsystem/plugindetailsview.h>
+#include <extensionsystem/pluginerrorview.h>
+#include <extensionsystem/pluginspec.h>
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QDialog>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QApplication>
+#include <QtDebug>
+
+PluginDialog::PluginDialog(ExtensionSystem::PluginManager *manager)
+ : m_view(new ExtensionSystem::PluginView(manager, this))
+{
+ QVBoxLayout *vl = new QVBoxLayout(this);
+ vl->setMargin(0);
+ vl->setSpacing(0);
+ vl->addWidget(m_view);
+
+ QHBoxLayout *hl = new QHBoxLayout;
+ vl->addLayout(hl);
+ hl->setMargin(0);
+ hl->setSpacing(6);
+ m_detailsButton = new QPushButton(tr("Details"), this);
+ m_errorDetailsButton = new QPushButton(tr("Error Details"), this);
+ m_detailsButton->setEnabled(false);
+ m_errorDetailsButton->setEnabled(false);
+ hl->addWidget(m_detailsButton);
+ hl->addWidget(m_errorDetailsButton);
+ hl->addStretch(5);
+ resize(650, 300);
+ setWindowTitle(tr("Installed Plugins"));
+
+ connect(m_view, SIGNAL(currentPluginChanged(ExtensionSystem::PluginSpec*)),
+ this, SLOT(updateButtons()));
+ connect(m_view, SIGNAL(pluginActivated(ExtensionSystem::PluginSpec*)),
+ this, SLOT(openDetails(ExtensionSystem::PluginSpec*)));
+ connect(m_detailsButton, SIGNAL(clicked()), this, SLOT(openDetails()));
+ connect(m_errorDetailsButton, SIGNAL(clicked()), this, SLOT(openErrorDetails()));
+}
+
+void PluginDialog::updateButtons()
+{
+ ExtensionSystem::PluginSpec *selectedSpec = m_view->currentPlugin();
+ if (selectedSpec) {
+ m_detailsButton->setEnabled(true);
+ m_errorDetailsButton->setEnabled(selectedSpec->hasError());
+ } else {
+ m_detailsButton->setEnabled(false);
+ m_errorDetailsButton->setEnabled(false);
+ }
+}
+
+
+void PluginDialog::openDetails()
+{
+ openDetails(m_view->currentPlugin());
+}
+
+void PluginDialog::openDetails(ExtensionSystem::PluginSpec *spec)
+{
+ if (!spec)
+ return;
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Plugin Details of %1").arg(spec->name()));
+ QVBoxLayout *layout = new QVBoxLayout;
+ dialog.setLayout(layout);
+ ExtensionSystem::PluginDetailsView *details = new ExtensionSystem::PluginDetailsView(&dialog);
+ layout->addWidget(details);
+ details->update(spec);
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
+ layout->addWidget(buttons);
+ connect(buttons, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ dialog.resize(400, 500);
+ dialog.exec();
+}
+
+void PluginDialog::openErrorDetails()
+{
+ ExtensionSystem::PluginSpec *spec = m_view->currentPlugin();
+ if (!spec)
+ return;
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Plugin Errors of %1").arg(spec->name()));
+ QVBoxLayout *layout = new QVBoxLayout;
+ dialog.setLayout(layout);
+ ExtensionSystem::PluginErrorView *errors = new ExtensionSystem::PluginErrorView(&dialog);
+ layout->addWidget(errors);
+ errors->update(spec);
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
+ layout->addWidget(buttons);
+ connect(buttons, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ dialog.resize(500, 300);
+ dialog.exec();
+}
+
+int main(int argc, char *argv[])
+{
+ ExtensionSystem::PluginManager manager;
+ QApplication app(argc, argv);
+ PluginDialog dialog(&manager);
+ manager.setPluginPaths(QStringList() << "plugins");
+ manager.loadPlugins();
+ dialog.show();
+ app.exec();
+}
+
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugindialog.h b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.h
new file mode 100644
index 0000000000..8987230681
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINDIALOG_H
+#define PLUGINDIALOG_H
+
+#include <extensionsystem/pluginview.h>
+#include <extensionsystem/pluginmanager.h>
+#include <QtGui/QWidget>
+#include <QtGui/QPushButton>
+
+class PluginDialog : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PluginDialog(ExtensionSystem::PluginManager *manager);
+
+private slots:
+ void updateButtons();
+ void openDetails();
+ void openDetails(ExtensionSystem::PluginSpec *spec);
+ void openErrorDetails();
+
+private:
+ ExtensionSystem::PluginView *m_view;
+
+ QPushButton *m_detailsButton;
+ QPushButton *m_errorDetailsButton;
+};
+
+#endif
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml
new file mode 100644
index 0000000000..63faecdf52
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml
@@ -0,0 +1,18 @@
+<plugin name="plugin1" version="2.1.0" compatVersion="1.0.0">
+ <vendor>Blablubb Corp</vendor>
+ <copyright>(C) 2023 Blubb</copyright>
+ <license>
+This is a default license bla
+blubbblubb
+end of terms
+ </license>
+ <description>
+This plugin is just a test.
+ it demonstrates the great use of the plugin spec.
+ </description>
+ <url>http://www.blablubb-corp.com/greatplugin</url>
+ <dependencyList>
+ <dependency name="plugin2" version="1.0.0"/>
+ <dependency name="plugin3" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp
new file mode 100644
index 0000000000..32d3bdf070
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin1.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+
+using namespace Plugin1;
+
+MyPlugin1::MyPlugin1()
+ : initializeCalled(false)
+{
+}
+
+bool MyPlugin1::initialize(const QStringList & /*arguments*/, QString *errorString)
+{
+ initializeCalled = true;
+ QObject *obj = new QObject(this);
+ obj->setObjectName("MyPlugin1");
+ addAutoReleasedObject(obj);
+
+ bool found2 = false;
+ bool found3 = false;
+ foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) {
+ if (object->objectName() == "MyPlugin2")
+ found2 = true;
+ else if (object->objectName() == "MyPlugin3")
+ found3 = true;
+ }
+ if (found2 && found3)
+ return true;
+ if (errorString) {
+ QString error = "object(s) missing from plugin(s):";
+ if (!found2)
+ error.append(" plugin2");
+ if (!found3)
+ error.append(" plugin3");
+ *errorString = error;
+ }
+ return false;
+}
+
+void MyPlugin1::extensionsInitialized()
+{
+ if (!initializeCalled)
+ return;
+ // don't do this at home, it's just done here for the test
+ QObject *obj = new QObject(this);
+ obj->setObjectName("MyPlugin1_running");
+ addAutoReleasedObject(obj);
+}
+
+Q_EXPORT_PLUGIN(MyPlugin1)
+
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h
new file mode 100644
index 0000000000..f993b25c9f
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN1_H
+#define PLUGIN1_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace Plugin1 {
+
+class MyPlugin1 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin1();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+private:
+ bool initializeCalled;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro
new file mode 100644
index 0000000000..9101770f9a
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro
@@ -0,0 +1,15 @@
+TEMPLATE = lib
+TARGET = plugin1
+
+SOURCES += plugin1.cpp
+HEADERS += plugin1.h
+
+include(../../../../extensionsystem_test.pri)
+
+LIBS += -L$${PWD}/../plugin2 -L$${PWD}/../plugin3 -lplugin2 -lplugin3
+
+macx {
+} else:unix {
+ QMAKE_RPATHDIR += $${PWD}/../plugin2
+ QMAKE_RPATHDIR += $${PWD}/../plugin3
+}
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml
new file mode 100644
index 0000000000..1a230ad38d
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml
@@ -0,0 +1,4 @@
+<plugin name="plugin2" version="1.0.0" compatVersion="1.0.0">
+ <vendor>1 &lt; 2 GmbH</vendor>
+ <url>http://www.somewhereintheweb.com/dodo.php?q=p</url>
+</plugin>
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp
new file mode 100644
index 0000000000..3ce6f258fa
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin2.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+
+using namespace Plugin2;
+
+MyPlugin2::MyPlugin2()
+ : initializeCalled(false)
+{
+}
+
+bool MyPlugin2::initialize(const QStringList & /*arguments*/, QString *errorString)
+{
+ Q_UNUSED(errorString);
+ initializeCalled = true;
+ QObject *obj = new QObject(this);
+ obj->setObjectName("MyPlugin2");
+ addAutoReleasedObject(obj);
+
+ return true;
+}
+
+void MyPlugin2::extensionsInitialized()
+{
+ if (!initializeCalled)
+ return;
+ // don't do this at home, it's just done here for the test
+ QObject *obj = new QObject(this);
+ obj->setObjectName("MyPlugin2_running");
+ addAutoReleasedObject(obj);
+}
+
+Q_EXPORT_PLUGIN(MyPlugin2)
+
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h
new file mode 100644
index 0000000000..5120038754
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN2_H
+#define PLUGIN2_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace Plugin2 {
+
+class MyPlugin2 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin2();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+private:
+ bool initializeCalled;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro
new file mode 100644
index 0000000000..a80f4a5c76
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+TARGET = plugin2
+
+SOURCES += plugin2.cpp
+HEADERS += plugin2.h
+
+include(../../../../extensionsystem_test.pri)
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/
+}
+
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml
new file mode 100644
index 0000000000..fd2279824e
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml
@@ -0,0 +1,6 @@
+<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0">
+ <vendor>Günöl AG</vendor>
+ <dependencyList>
+ <dependency name="plugin2" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp
new file mode 100644
index 0000000000..ff37d06096
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugin3.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+
+using namespace Plugin3;
+
+MyPlugin3::MyPlugin3()
+ : initializeCalled(false)
+{
+}
+
+bool MyPlugin3::initialize(const QStringList & /*arguments*/, QString *errorString)
+{
+ initializeCalled = true;
+ QObject *obj = new QObject(this);
+ obj->setObjectName("MyPlugin3");
+ addAutoReleasedObject(obj);
+
+ bool found2 = false;
+ foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) {
+ if (object->objectName() == "MyPlugin2")
+ found2 = true;
+ }
+ if (found2)
+ return true;
+ if (errorString)
+ *errorString = "object from plugin2 could not be found";
+ return false;
+}
+
+void MyPlugin3::extensionsInitialized()
+{
+ if (!initializeCalled)
+ return;
+ // don't do this at home, it's just done here for the test
+ QObject *obj = new QObject(this);
+ obj->setObjectName("MyPlugin3_running");
+ addAutoReleasedObject(obj);
+}
+
+Q_EXPORT_PLUGIN(MyPlugin3)
+
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h
new file mode 100644
index 0000000000..00bd642912
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGIN3_H
+#define PLUGIN3_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace Plugin3 {
+
+class MyPlugin3 : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ MyPlugin3();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+
+private:
+ bool initializeCalled;
+};
+
+} // namespace
+
+#endif // header guard
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro
new file mode 100644
index 0000000000..c5ff581b1b
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro
@@ -0,0 +1,15 @@
+TEMPLATE = lib
+TARGET = plugin3
+
+SOURCES += plugin3.cpp
+HEADERS += plugin3.h
+
+include(../../../../extensionsystem_test.pri)
+
+LIBS += -L$${PWD}/../plugin2 -lplugin2
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/
+} else:unix {
+ QMAKE_RPATHDIR += $${PWD}/../plugin2
+}
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml
new file mode 100644
index 0000000000..61f37bd706
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml
@@ -0,0 +1,5 @@
+<plugin name="plugin4" version="1.0.0" compatVersion="1.0.0">
+ <dependencyList>
+ <dependency name="plugin2" version="1.0.0"/>
+ </dependencyList>
+</plugin>
diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro
new file mode 100644
index 0000000000..f0d76950e8
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+SUBDIRS = plugin2 plugin3 plugin1
diff --git a/src/libs/extensionsystem/test/manual/pluginview/pluginview.pro b/src/libs/extensionsystem/test/manual/pluginview/pluginview.pro
new file mode 100644
index 0000000000..8527b82c47
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/pluginview.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = test.pro \
+ plugins
diff --git a/src/libs/extensionsystem/test/manual/pluginview/test.pro b/src/libs/extensionsystem/test/manual/pluginview/test.pro
new file mode 100644
index 0000000000..4b9cd21d8a
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/test.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+
+macx:CONFIG-=app_bundle
+
+# Input
+HEADERS += plugindialog.h
+SOURCES += plugindialog.cpp
+
+include(../../extensionsystem_test.pri)
diff --git a/src/libs/extensionsystem/test/manual/pluginview/test.sh b/src/libs/extensionsystem/test/manual/pluginview/test.sh
new file mode 100755
index 0000000000..426901ea74
--- /dev/null
+++ b/src/libs/extensionsystem/test/manual/pluginview/test.sh
@@ -0,0 +1,5 @@
+# -- run the plugin test from this directory.
+
+export LD_LIBRARY_PATH=../../../../../../lib:$LD_LIBRARY_PATH
+export DYLD_LIBRARY_PATH=../../../../../../bin/QtCreator.app/Contents/PlugIns:$DYLD_LIBRARY_PATH # mac
+exec ./test
diff --git a/src/libs/extensionsystem/test/test.pro b/src/libs/extensionsystem/test/test.pro
new file mode 100644
index 0000000000..471ea892f1
--- /dev/null
+++ b/src/libs/extensionsystem/test/test.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+
+SUBDIRS = auto manual
+
diff --git a/src/libs/libs.pro b/src/libs/libs.pro
new file mode 100644
index 0000000000..0bb942edad
--- /dev/null
+++ b/src/libs/libs.pro
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = \
+ qtconcurrent \
+ aggregation \
+ extensionsystem \
+ utils \
+ cplusplus
diff --git a/src/libs/qtconcurrent/QtConcurrentTools b/src/libs/qtconcurrent/QtConcurrentTools
new file mode 100644
index 0000000000..ffd0cb10a7
--- /dev/null
+++ b/src/libs/qtconcurrent/QtConcurrentTools
@@ -0,0 +1,2 @@
+#include "qtconcurrent/multitask.h"
+#include "qtconcurrent/runextensions.h"
diff --git a/src/libs/qtconcurrent/multitask.h b/src/libs/qtconcurrent/multitask.h
new file mode 100644
index 0000000000..fc66de1715
--- /dev/null
+++ b/src/libs/qtconcurrent/multitask.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MULTITASK_H
+#define MULTITASK_H
+
+#include "qtconcurrent_global.h"
+#include "runextensions.h"
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QEventLoop>
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QThreadPool>
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+class QTCONCURRENT_EXPORT MultiTaskBase : public QObject, public QRunnable
+{
+ Q_OBJECT
+protected slots:
+ virtual void cancelSelf() = 0;
+ virtual void setFinished() = 0;
+ virtual void setProgressRange(int min, int max) = 0;
+ virtual void setProgressValue(int value) = 0;
+ virtual void setProgressText(QString value) = 0;
+};
+
+template <typename Class, typename R>
+class MultiTask : public MultiTaskBase
+{
+public:
+ MultiTask(void (Class::*fn)(QFutureInterface<R> &), const QList<Class *> &objects)
+ : fn(fn),
+ objects(objects)
+ {
+ maxProgress = 100*objects.size();
+ }
+
+ QFuture<R> future()
+ {
+ futureInterface.reportStarted();
+ return futureInterface.future();
+ }
+
+ void run()
+ {
+ QThreadPool::globalInstance()->releaseThread();
+ futureInterface.setProgressRange(0, maxProgress);
+ foreach (Class *object, objects) {
+ QFutureWatcher<R> *watcher = new QFutureWatcher<R>();
+ watchers.insert(object, watcher);
+ finished.insert(watcher, false);
+ connect(watcher, SIGNAL(finished()), this, SLOT(setFinished()));
+ connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(setProgressRange(int,int)));
+ connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int)));
+ connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(setProgressText(QString)));
+ watcher->setFuture(QtConcurrent::run(fn, object));
+ }
+ selfWatcher = new QFutureWatcher<R>();
+ connect(selfWatcher, SIGNAL(canceled()), this, SLOT(cancelSelf()));
+ selfWatcher->setFuture(futureInterface.future());
+ loop = new QEventLoop;
+ loop->exec();
+ futureInterface.reportFinished();
+ QThreadPool::globalInstance()->reserveThread();
+ qDeleteAll(watchers.values());
+ delete selfWatcher;
+ delete loop;
+ }
+protected:
+ void cancelSelf()
+ {
+ foreach (QFutureWatcher<R> *watcher, watchers)
+ watcher->future().cancel();
+ }
+
+ void setFinished()
+ {
+ updateProgress();
+ QFutureWatcher<R> *watcher = static_cast<QFutureWatcher<R> *>(sender());
+ if (finished.contains(watcher))
+ finished[watcher] = true;
+ bool allFinished = true;
+ const QList<bool> finishedValues = finished.values();
+ foreach (bool isFinished, finishedValues) {
+ if (!isFinished) {
+ allFinished = false;
+ break;
+ }
+ }
+ if (allFinished)
+ loop->quit();
+ }
+
+ void setProgressRange(int min, int max)
+ {
+ Q_UNUSED(min);
+ Q_UNUSED(max);
+ updateProgress();
+ }
+
+ void setProgressValue(int value)
+ {
+ Q_UNUSED(value);
+ updateProgress();
+ }
+
+ void setProgressText(QString value)
+ {
+ Q_UNUSED(value);
+ updateProgressText();
+ }
+private:
+ void updateProgress()
+ {
+ int progressSum = 0;
+ const QList<QFutureWatcher<R> *> watchersValues = watchers.values();
+ foreach (QFutureWatcher<R> *watcher, watchersValues) {
+ if (watcher->progressMinimum() == watcher->progressMaximum()) {
+ if (watcher->future().isFinished() && !watcher->future().isCanceled())
+ progressSum += 100;
+ } else {
+ progressSum += 100*(watcher->progressValue()-watcher->progressMinimum())/(watcher->progressMaximum()-watcher->progressMinimum());
+ }
+ }
+ futureInterface.setProgressValue(progressSum);
+ }
+
+ void updateProgressText()
+ {
+ QString text;
+ const QList<QFutureWatcher<R> *> watchersValues = watchers.values();
+ foreach (QFutureWatcher<R> *watcher, watchersValues) {
+ if (!watcher->progressText().isEmpty())
+ text += watcher->progressText() + "\n";
+ }
+ text = text.trimmed();
+ futureInterface.setProgressValueAndText(futureInterface.progressValue(), text);
+ }
+
+ QFutureInterface<R> futureInterface;
+ void (Class::*fn)(QFutureInterface<R> &);
+ QList<Class *> objects;
+
+ QFutureWatcher<R> *selfWatcher;
+ QMap<Class *, QFutureWatcher<R> *> watchers;
+ QMap<QFutureWatcher<R> *, bool> finished;
+ QEventLoop *loop;
+ int maxProgress;
+};
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), const QList<Class *> &objects, int priority = 0) {
+ MultiTask<Class, T> *task = new MultiTask<Class, T>(fn, objects);
+ QFuture<T> future = task->future();
+ QThreadPool::globalInstance()->start(task, priority);
+ return future;
+}
+
+} //namespace
+
+QT_END_NAMESPACE
+
+#endif // MULTITASK_H
diff --git a/src/libs/qtconcurrent/qtconcurrent.pri b/src/libs/qtconcurrent/qtconcurrent.pri
new file mode 100644
index 0000000000..57929a4cf1
--- /dev/null
+++ b/src/libs/qtconcurrent/qtconcurrent.pri
@@ -0,0 +1 @@
+LIBS *= -l$$qtLibraryTarget(QtConcurrent)
diff --git a/src/libs/qtconcurrent/qtconcurrent.pro b/src/libs/qtconcurrent/qtconcurrent.pro
new file mode 100644
index 0000000000..46302f11cd
--- /dev/null
+++ b/src/libs/qtconcurrent/qtconcurrent.pro
@@ -0,0 +1,10 @@
+TEMPLATE = lib
+TARGET = QtConcurrent
+DEFINES += BUILD_QTCONCURRENT
+
+include(../../qworkbenchlibrary.pri)
+
+HEADERS += \
+ qtconcurrent_global.h \
+ multitask.h \
+ runextensions.h
diff --git a/src/libs/qtconcurrent/qtconcurrent_global.h b/src/libs/qtconcurrent/qtconcurrent_global.h
new file mode 100644
index 0000000000..15d47af5f3
--- /dev/null
+++ b/src/libs/qtconcurrent/qtconcurrent_global.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTCONCURRENT_GLOBAL_H
+#define QTCONCURRENT_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(BUILD_QTCONCURRENT)
+# define QTCONCURRENT_EXPORT Q_DECL_EXPORT
+#else
+# define QTCONCURRENT_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // QTCONCURRENT_GLOBAL_H
diff --git a/src/libs/qtconcurrent/runextensions.h b/src/libs/qtconcurrent/runextensions.h
new file mode 100644
index 0000000000..43707c14d5
--- /dev/null
+++ b/src/libs/qtconcurrent/runextensions.h
@@ -0,0 +1,397 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTCONCURRENT_RUNEX_H
+#define QTCONCURRENT_RUNEX_H
+
+#include <qrunnable.h>
+#include <qfutureinterface.h>
+#include <qthreadpool.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+template <typename T, typename FunctionPointer>
+class StoredInterfaceFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall0(void (fn)(QFutureInterface<T> &))
+ : fn(fn) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+
+};
+template <typename T, typename FunctionPointer, typename Class>
+class StoredInterfaceMemberFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+ : fn(fn), object(object) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+
+};
+
+template <typename T, typename FunctionPointer, typename Arg1>
+class StoredInterfaceFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall1(void (fn)(QFutureInterface<T> &, Arg1), Arg1 arg1)
+ : fn(fn), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1>
+class StoredInterfaceMemberFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, Arg1 arg1)
+ : fn(fn), object(object), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2>
+class StoredInterfaceFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall2(void (fn)(QFutureInterface<T> &, Arg1, Arg2), Arg1 arg1, Arg2 arg2)
+ : fn(fn), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2>
+class StoredInterfaceMemberFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, Arg1 arg1, Arg2 arg2)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall3(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceMemberFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall4(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceMemberFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall5(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceMemberFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+
+template <typename T>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &))
+{
+ return (new StoredInterfaceFunctionCall0<T, void (*)(QFutureInterface<T> &)>(functionPointer))->start();
+}
+template <typename T, typename Arg1>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1), Arg1 arg1)
+{
+ return (new StoredInterfaceFunctionCall1<T, void (*)(QFutureInterface<T> &, Arg1), Arg1>(functionPointer, arg1))->start();
+}
+template <typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2), Arg1 arg1, Arg2 arg2)
+{
+ return (new StoredInterfaceFunctionCall2<T, void (*)(QFutureInterface<T> &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3)
+{
+ return (new StoredInterfaceFunctionCall3<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+{
+ return (new StoredInterfaceFunctionCall4<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+{
+ return (new StoredInterfaceFunctionCall5<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start();
+}
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+{
+ return (new StoredInterfaceMemberFunctionCall0<T, void (Class::*)(QFutureInterface<T> &), Class>(fn, object))->start();
+}
+
+} //namespace QtConcurrent
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/libs/utils/basevalidatinglineedit.cpp b/src/libs/utils/basevalidatinglineedit.cpp
new file mode 100644
index 0000000000..cb936e3c2d
--- /dev/null
+++ b/src/libs/utils/basevalidatinglineedit.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basevalidatinglineedit.h"
+
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+namespace Core {
+namespace Utils {
+
+struct BaseValidatingLineEditPrivate {
+ explicit BaseValidatingLineEditPrivate(const QWidget *w);
+
+ const QColor m_okTextColor;
+ QColor m_errorTextColor;
+
+ BaseValidatingLineEdit::State m_state;
+ QString m_errorMessage;
+ QString m_initialText;
+ bool m_firstChange;
+};
+
+BaseValidatingLineEditPrivate::BaseValidatingLineEditPrivate(const QWidget *w) :
+ m_okTextColor(BaseValidatingLineEdit::textColor(w)),
+ m_errorTextColor(Qt::red),
+ m_state(BaseValidatingLineEdit::Invalid),
+ m_firstChange(true)
+{
+}
+
+BaseValidatingLineEdit::BaseValidatingLineEdit(QWidget *parent) :
+ QLineEdit(parent),
+ m_bd(new BaseValidatingLineEditPrivate(this))
+{
+ // Note that textChanged() is also triggered automagically by
+ // QLineEdit::setText(), no need to trigger manually.
+ connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotChanged(QString)));
+}
+
+BaseValidatingLineEdit::~BaseValidatingLineEdit()
+{
+ delete m_bd;
+}
+
+QString BaseValidatingLineEdit::initialText() const
+{
+ return m_bd->m_initialText;
+}
+
+void BaseValidatingLineEdit::setInitialText(const QString &t)
+{
+ if (m_bd->m_initialText != t) {
+ m_bd->m_initialText = t;
+ m_bd->m_firstChange = true;
+ setText(t);
+ }
+}
+
+QColor BaseValidatingLineEdit::errorColor() const
+{
+ return m_bd->m_errorTextColor;
+}
+
+void BaseValidatingLineEdit::setErrorColor(const QColor &c)
+{
+ m_bd->m_errorTextColor = c;
+}
+
+QColor BaseValidatingLineEdit::textColor(const QWidget *w)
+{
+ return w->palette().color(QPalette::Active, QPalette::Text);
+}
+
+void BaseValidatingLineEdit::setTextColor(QWidget *w, const QColor &c)
+{
+ QPalette palette = w->palette();
+ palette.setColor(QPalette::Active, QPalette::Text, c);
+ w->setPalette(palette);
+}
+
+BaseValidatingLineEdit::State BaseValidatingLineEdit::state() const
+{
+ return m_bd->m_state;
+}
+
+bool BaseValidatingLineEdit::isValid() const
+{
+ return m_bd->m_state == Valid;
+}
+
+QString BaseValidatingLineEdit::errorMessage() const
+{
+ return m_bd->m_errorMessage;
+}
+
+void BaseValidatingLineEdit::slotChanged(const QString &t)
+{
+ m_bd->m_errorMessage.clear();
+ // Are we displaying the initial text?
+ const bool isDisplayingInitialText = !m_bd->m_initialText.isEmpty() && t == m_bd->m_initialText;
+ const State newState = isDisplayingInitialText ?
+ DisplayingInitialText :
+ (validate(t, &m_bd->m_errorMessage) ? Valid : Invalid);
+ setToolTip(m_bd->m_errorMessage);
+ if (debug)
+ qDebug() << Q_FUNC_INFO << t << "State" << m_bd->m_state << "->" << newState << m_bd->m_errorMessage;
+ // Changed..figure out if valid changed. DisplayingInitialText is not valid,
+ // but should not show error color. Also trigger on the first change.
+ if (newState != m_bd->m_state || m_bd->m_firstChange) {
+ const bool validHasChanged = (m_bd->m_state == Valid) != (newState == Valid);
+ m_bd->m_state = newState;
+ m_bd->m_firstChange = false;
+ setTextColor(this, newState == Invalid ? m_bd->m_errorTextColor : m_bd->m_okTextColor);
+ if (validHasChanged)
+ emit validChanged();
+ }
+}
+
+void BaseValidatingLineEdit::slotReturnPressed()
+{
+ if (isValid())
+ emit validReturnPressed();
+}
+
+}
+}
diff --git a/src/libs/utils/basevalidatinglineedit.h b/src/libs/utils/basevalidatinglineedit.h
new file mode 100644
index 0000000000..3482687011
--- /dev/null
+++ b/src/libs/utils/basevalidatinglineedit.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEVALIDATINGLINEEDIT_H
+#define BASEVALIDATINGLINEEDIT_H
+
+#include "utils_global.h"
+
+#include <QtGui/QLineEdit>
+
+namespace Core {
+namespace Utils {
+
+struct BaseValidatingLineEditPrivate;
+
+/* Base class for validating line edits that performs validation in a virtual
+ * validate() function to be implemented in derived classes.
+ * When invalid, the text color will turn red and a tooltip will
+ * contain the error message. This approach is less intrusive than a
+ * QValidator which will prevent the user from entering certain characters.
+ *
+ * The widget has a concept of an "initialText" which can be something like
+ * "<Enter name here>". This results in state 'DisplayingInitialText', which
+ * is not valid, but is not marked red. */
+
+class QWORKBENCH_UTILS_EXPORT BaseValidatingLineEdit : public QLineEdit {
+ Q_OBJECT
+ Q_DISABLE_COPY(BaseValidatingLineEdit)
+ Q_PROPERTY(QString initialText READ initialText WRITE setInitialText DESIGNABLE true)
+ Q_PROPERTY(QColor errorColor READ errorColor WRITE setErrorColor DESIGNABLE true)
+
+public:
+ enum State { Invalid, DisplayingInitialText, Valid };
+
+ explicit BaseValidatingLineEdit(QWidget *parent = 0);
+ virtual ~BaseValidatingLineEdit();
+
+
+ State state() const;
+ bool isValid() const;
+ QString errorMessage() const;
+
+ QString initialText() const;
+ void setInitialText(const QString &);
+
+ QColor errorColor() const;
+ void setErrorColor(const QColor &);
+
+ static QColor textColor(const QWidget *w);
+ static void setTextColor(QWidget *w, const QColor &c);
+
+signals:
+ void validChanged();
+ void validReturnPressed();
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const = 0;
+
+protected slots:
+ // Custom behaviour can be added here. The base implementation must
+ // be called.
+ virtual void slotReturnPressed();
+ virtual void slotChanged(const QString &t);
+
+private:
+ BaseValidatingLineEditPrivate *m_bd;
+};
+
+}
+}
+#endif // BASEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/classnamevalidatinglineedit.cpp b/src/libs/utils/classnamevalidatinglineedit.cpp
new file mode 100644
index 0000000000..b52758eda5
--- /dev/null
+++ b/src/libs/utils/classnamevalidatinglineedit.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "classnamevalidatinglineedit.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
+
+namespace Core {
+namespace Utils {
+
+struct ClassNameValidatingLineEditPrivate {
+ ClassNameValidatingLineEditPrivate();
+
+ const QRegExp m_nameRegexp;
+ const QString m_namespaceDelimiter;
+ bool m_namespacesEnabled;
+};
+
+// Match something like "Namespace1::Namespace2::ClassName".
+ClassNameValidatingLineEditPrivate:: ClassNameValidatingLineEditPrivate() :
+ m_nameRegexp(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*")),
+ m_namespaceDelimiter(QLatin1String("::")),
+ m_namespacesEnabled(false)
+{
+ Q_ASSERT(m_nameRegexp.isValid());
+}
+
+// --------------------- ClassNameValidatingLineEdit
+ClassNameValidatingLineEdit::ClassNameValidatingLineEdit(QWidget *parent) :
+ Core::Utils::BaseValidatingLineEdit(parent),
+ m_d(new ClassNameValidatingLineEditPrivate)
+{
+}
+
+ClassNameValidatingLineEdit::~ClassNameValidatingLineEdit()
+{
+ delete m_d;
+}
+
+bool ClassNameValidatingLineEdit::namespacesEnabled() const
+{
+ return m_d->m_namespacesEnabled;
+}
+
+void ClassNameValidatingLineEdit::setNamespacesEnabled(bool b)
+{
+ m_d->m_namespacesEnabled = b;
+}
+
+bool ClassNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ if (!m_d->m_namespacesEnabled && value.contains(QLatin1Char(':'))) {
+ if (errorMessage)
+ *errorMessage = tr("The class name must not contain namespace delimiters.");
+ return false;
+ }
+ if (!m_d->m_nameRegexp.exactMatch(value)) {
+ if (errorMessage)
+ *errorMessage = tr("The class name contains invalid characters.");
+ return false;
+ }
+ return true;
+}
+
+void ClassNameValidatingLineEdit::slotChanged(const QString &t)
+{
+ Core::Utils::BaseValidatingLineEdit::slotChanged(t);
+ if (isValid()) {
+ // Suggest file names, strip namespaces
+ QString fileName = t.toLower();
+ if (m_d->m_namespacesEnabled) {
+ const int namespaceIndex = fileName.lastIndexOf(m_d->m_namespaceDelimiter);
+ if (namespaceIndex != -1)
+ fileName.remove(0, namespaceIndex + m_d->m_namespaceDelimiter.size());
+ }
+ emit updateFileName(fileName);
+ }
+}
+
+QString ClassNameValidatingLineEdit::createClassName(const QString &name)
+{
+ // Remove spaces and convert the adjacent characters to uppercase
+ QString className = name;
+ QRegExp spaceMatcher(QLatin1String(" +(\\w)"), Qt::CaseSensitive, QRegExp::RegExp2);
+ Q_ASSERT(spaceMatcher.isValid());
+ int pos;
+ while ((pos = spaceMatcher.indexIn(className)) != -1) {
+ className.replace(pos, spaceMatcher.matchedLength(),
+ spaceMatcher.cap(1).toUpper());
+ }
+
+ // Filter out any remaining invalid characters
+ className.remove(QRegExp(QLatin1String("[^a-zA-Z0-9_]")));
+
+ // If the first character is numeric, prefix the name with a "_"
+ if (className.at(0).isNumber()) {
+ className.prepend(QLatin1Char('_'));
+ } else {
+ // Convert the first character to uppercase
+ className.replace(0, 1, className.left(1).toUpper());
+ }
+
+ return className;
+}
+
+}
+}
diff --git a/src/libs/utils/classnamevalidatinglineedit.h b/src/libs/utils/classnamevalidatinglineedit.h
new file mode 100644
index 0000000000..c0a209d0d7
--- /dev/null
+++ b/src/libs/utils/classnamevalidatinglineedit.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CLASSNAMEVALIDATINGLINEEDIT_H
+#define CLASSNAMEVALIDATINGLINEEDIT_H
+
+#include "utils_global.h"
+#include "basevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+struct ClassNameValidatingLineEditPrivate;
+
+/* A Line edit that validates a C++ class name and emits a signal
+ * to derive suggested file names from it. */
+
+class QWORKBENCH_UTILS_EXPORT ClassNameValidatingLineEdit :
+ public Core::Utils::BaseValidatingLineEdit {
+ Q_DISABLE_COPY(ClassNameValidatingLineEdit)
+ Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true)
+ Q_OBJECT
+
+public:
+ explicit ClassNameValidatingLineEdit(QWidget *parent = 0);
+ virtual ~ClassNameValidatingLineEdit();
+
+ bool namespacesEnabled() const;
+ void setNamespacesEnabled(bool b);
+
+ // Clean an input string to get a valid class name.
+ static QString createClassName(const QString &name);
+
+signals:
+ // Will be emitted with a suggestion for a base name of the
+ // source/header file of the class.
+ void updateFileName(const QString &t);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+ virtual void slotChanged(const QString &t);
+
+private:
+ ClassNameValidatingLineEditPrivate *m_d;
+};
+
+}
+}
+
+#endif // CLASSNAMEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/codegeneration.cpp b/src/libs/utils/codegeneration.cpp
new file mode 100644
index 0000000000..3af484935a
--- /dev/null
+++ b/src/libs/utils/codegeneration.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "codegeneration.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QStringList>
+#include <QtCore/QFileInfo>
+
+namespace Core {
+namespace Utils {
+
+QWORKBENCH_UTILS_EXPORT QString headerGuard(const QString &file)
+{
+ QString rc = QFileInfo(file).baseName().toUpper();
+ rc += QLatin1String("_H");
+ return rc;
+}
+
+QWORKBENCH_UTILS_EXPORT
+void writeIncludeFileDirective(const QString &file, bool globalInclude,
+ QTextStream &str)
+{
+ const QChar opening = globalInclude ? QLatin1Char('<') : QLatin1Char('"');
+ const QChar closing = globalInclude ? QLatin1Char('>') : QLatin1Char('"');
+ str << QLatin1String("#include ") << opening << file << closing << QLatin1Char('\n');
+}
+
+QWORKBENCH_UTILS_EXPORT
+QString writeOpeningNameSpaces(const QStringList &l, const QString &indent,
+ QTextStream &str)
+{
+ const int count = l.size();
+ QString rc;
+ if (count) {
+ str << '\n';
+ for (int i = 0; i < count; i++) {
+ str << rc << "namespace " << l.at(i) << " {\n";
+ rc += indent;
+ }
+ str << '\n';
+ }
+ return rc;
+}
+
+QWORKBENCH_UTILS_EXPORT
+void writeClosingNameSpaces(const QStringList &l, const QString &indent,
+ QTextStream &str)
+{
+ if (!l.empty())
+ str << '\n';
+ for (int i = l.size() - 1; i >= 0; i--) {
+ if (i)
+ str << QString(indent.size() * i, QLatin1Char(' '));
+ str << "} // namespace " << l.at(i) << '\n';
+ }
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/codegeneration.h b/src/libs/utils/codegeneration.h
new file mode 100644
index 0000000000..1a20c76d08
--- /dev/null
+++ b/src/libs/utils/codegeneration.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CODEGENERATION_H
+#define CODEGENERATION_H
+
+#include "utils_global.h"
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+QWORKBENCH_UTILS_EXPORT QString headerGuard(const QString &file);
+
+QWORKBENCH_UTILS_EXPORT
+void writeIncludeFileDirective(const QString &file,
+ bool globalInclude,
+ QTextStream &str);
+
+// Write opening namespaces and return an indentation string to be used
+// in the following code if there are any.
+QWORKBENCH_UTILS_EXPORT
+QString writeOpeningNameSpaces(const QStringList &namespaces,
+ const QString &indent,
+ QTextStream &str);
+
+// Close namespacesnamespaces
+QWORKBENCH_UTILS_EXPORT
+void writeClosingNameSpaces(const QStringList &namespaces,
+ const QString &indent,
+ QTextStream &str);
+
+} // namespace Utils
+} // namespace Core
+
+#endif // CODEGENERATION_H
diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp
new file mode 100644
index 0000000000..e7e930c544
--- /dev/null
+++ b/src/libs/utils/fancylineedit.cpp
@@ -0,0 +1,317 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fancylineedit.h"
+
+#include <QtCore/QEvent>
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+#include <QtGui/QApplication>
+#include <QtGui/QMenu>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QLabel>
+
+enum { margin = 6 };
+
+namespace Core {
+namespace Utils {
+
+static inline QString sideToStyleSheetString(FancyLineEdit::Side side)
+{
+ return side == FancyLineEdit::Left ? QLatin1String("left") : QLatin1String("right");
+}
+
+// Format style sheet for the label containing the pixmap. It has a margin on
+// the outer side of the whole FancyLineEdit.
+static QString labelStyleSheet(FancyLineEdit::Side side)
+{
+ QString rc = QLatin1String("QLabel { margin-");
+ rc += sideToStyleSheetString(side);
+ rc += QLatin1String(": ");
+ rc += QString::number(margin);
+ rc += QLatin1Char('}');
+ return rc;
+}
+
+// --------- FancyLineEditPrivate as QObject with label
+// event filter
+
+class FancyLineEditPrivate : public QObject {
+public:
+ explicit FancyLineEditPrivate(QLineEdit *parent);
+
+ virtual bool eventFilter(QObject *obj, QEvent *event);
+
+ const QString m_leftLabelStyleSheet;
+ const QString m_rightLabelStyleSheet;
+
+ QLineEdit *m_lineEdit;
+ QPixmap m_pixmap;
+ QMenu *m_menu;
+ QLabel *m_menuLabel;
+ FancyLineEdit::Side m_side;
+ bool m_useLayoutDirection;
+ bool m_menuTabFocusTrigger;
+ QString m_hintText;
+ bool m_showingHintText;
+};
+
+
+FancyLineEditPrivate::FancyLineEditPrivate(QLineEdit *parent) :
+ QObject(parent),
+ m_leftLabelStyleSheet(labelStyleSheet(FancyLineEdit::Left)),
+ m_rightLabelStyleSheet(labelStyleSheet(FancyLineEdit::Right)),
+ m_lineEdit(parent),
+ m_menu(0),
+ m_menuLabel(0),
+ m_side(FancyLineEdit::Left),
+ m_useLayoutDirection(false),
+ m_menuTabFocusTrigger(false),
+ m_showingHintText(false)
+{
+}
+
+bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)
+{
+ if (!m_menu || obj != m_menuLabel)
+ return QObject::eventFilter(obj, event);
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress: {
+ const QMouseEvent *me = static_cast<QMouseEvent *>(event);
+ m_menu->exec(me->globalPos());
+ return true;
+ }
+ case QEvent::FocusIn:
+ if (m_menuTabFocusTrigger) {
+ m_lineEdit->setFocus();
+ m_menu->exec(m_menuLabel->mapToGlobal(m_menuLabel->rect().center()));
+ return true;
+ }
+ default:
+ break;
+ }
+ return QObject::eventFilter(obj, event);
+}
+
+// --------- FancyLineEdit
+FancyLineEdit::FancyLineEdit(QWidget *parent) :
+ QLineEdit(parent),
+ m_d(new FancyLineEditPrivate(this))
+{
+ m_d->m_menuLabel = new QLabel(this);
+ m_d->m_menuLabel->installEventFilter(m_d);
+ updateMenuLabel();
+ showHintText();
+}
+
+FancyLineEdit::~FancyLineEdit()
+{
+}
+
+// Position the menu label left or right according to size.
+// Called when switching side and from resizeEvent.
+void FancyLineEdit::positionMenuLabel()
+{
+ switch (side()) {
+ case Left:
+ m_d->m_menuLabel->setGeometry(0, 0, m_d->m_pixmap.width()+margin, height());
+ break;
+ case Right:
+ m_d->m_menuLabel->setGeometry(width() - m_d->m_pixmap.width() - margin, 0,
+ m_d->m_pixmap.width()+margin, height());
+ break;
+ }
+}
+
+void FancyLineEdit::updateStyleSheet(Side side)
+{
+ // Udate the LineEdit style sheet. Make room for the label on the
+ // respective side and set color according to whether we are showing the
+ // hint text
+ QString sheet = QLatin1String("QLineEdit{ padding-");
+ sheet += sideToStyleSheetString(side);
+ sheet += QLatin1String(": ");
+ sheet += QString::number(m_d->m_pixmap.width() + margin);
+ sheet += QLatin1Char(';');
+ if (m_d->m_showingHintText)
+ sheet += QLatin1String(" color: #BBBBBB;");
+ sheet += QLatin1Char('}');
+ setStyleSheet(sheet);
+}
+
+void FancyLineEdit::updateMenuLabel()
+{
+ m_d->m_menuLabel->setPixmap(m_d->m_pixmap);
+ const Side s = side();
+ switch (s) {
+ case Left:
+ m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
+ m_d->m_menuLabel->setStyleSheet(m_d->m_leftLabelStyleSheet);
+ break;
+ case Right:
+ m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+ m_d->m_menuLabel->setStyleSheet(m_d->m_rightLabelStyleSheet);
+ break;
+ }
+ updateStyleSheet(s);
+ positionMenuLabel();
+}
+
+void FancyLineEdit::setSide(Side side)
+{
+ m_d->m_side = side;
+ updateMenuLabel();
+}
+
+FancyLineEdit::Side FancyLineEdit::side() const
+{
+ if (m_d->m_useLayoutDirection)
+ return qApp->layoutDirection() == Qt::LeftToRight ? Left : Right;
+ return m_d->m_side;
+}
+
+void FancyLineEdit::resizeEvent(QResizeEvent *)
+{
+ positionMenuLabel();
+}
+
+void FancyLineEdit::setPixmap(const QPixmap &pixmap)
+{
+ m_d->m_pixmap = pixmap;
+ updateMenuLabel();
+}
+
+QPixmap FancyLineEdit::pixmap() const
+{
+ return m_d->m_pixmap;
+}
+
+void FancyLineEdit::setMenu(QMenu *menu)
+{
+ m_d->m_menu = menu;
+}
+
+QMenu *FancyLineEdit::menu() const
+{
+ return m_d->m_menu;
+}
+
+bool FancyLineEdit::useLayoutDirection() const
+{
+ return m_d->m_useLayoutDirection;
+}
+
+void FancyLineEdit::setUseLayoutDirection(bool v)
+{
+ m_d->m_useLayoutDirection = v;
+}
+
+bool FancyLineEdit::isSideStored() const
+{
+ return !m_d->m_useLayoutDirection;
+}
+
+bool FancyLineEdit::hasMenuTabFocusTrigger() const
+{
+ return m_d->m_menuTabFocusTrigger;
+}
+
+void FancyLineEdit::setMenuTabFocusTrigger(bool v)
+{
+ if (m_d->m_menuTabFocusTrigger == v)
+ return;
+
+ m_d->m_menuTabFocusTrigger = v;
+ m_d->m_menuLabel->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
+}
+
+QString FancyLineEdit::hintText() const
+{
+ return m_d->m_hintText;
+}
+
+void FancyLineEdit::setHintText(const QString &ht)
+{
+ // Updating magic to make the property work in Designer.
+ if (ht == m_d->m_hintText)
+ return;
+ hideHintText();
+ m_d->m_hintText = ht;
+ if (!hasFocus() && !ht.isEmpty())
+ showHintText();
+}
+
+void FancyLineEdit::showHintText()
+{
+ if (!m_d->m_showingHintText && text().isEmpty() && !m_d->m_hintText.isEmpty()) {
+ m_d->m_showingHintText = true;
+ setText(m_d->m_hintText);
+ updateStyleSheet(side());
+ }
+}
+
+void FancyLineEdit::hideHintText()
+{
+ if (m_d->m_showingHintText && !m_d->m_hintText.isEmpty()) {
+ m_d->m_showingHintText = false;
+ setText(QString());
+ updateStyleSheet(side());
+ }
+}
+
+void FancyLineEdit::focusInEvent(QFocusEvent *e)
+{
+ hideHintText();
+ QLineEdit::focusInEvent(e);
+}
+
+void FancyLineEdit::focusOutEvent(QFocusEvent *e)
+{
+ // Focus out: Switch to displaying the hint text unless
+ // there is user input
+ showHintText();
+ QLineEdit::focusOutEvent(e);
+}
+
+bool FancyLineEdit::isShowingHintText() const
+{
+ return m_d->m_showingHintText;
+}
+
+QString FancyLineEdit::typedText() const
+{
+ return m_d->m_showingHintText ? QString() : text();
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/fancylineedit.h b/src/libs/utils/fancylineedit.h
new file mode 100644
index 0000000000..24a109eada
--- /dev/null
+++ b/src/libs/utils/fancylineedit.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FANCYLINEEDIT_H
+#define FANCYLINEEDIT_H
+
+#include "utils_global.h"
+
+#include <QtGui/QLineEdit>
+
+namespace Core {
+namespace Utils {
+
+class FancyLineEditPrivate;
+
+/* A line edit with an embedded pixmap on one side that is connected to
+ * a menu. Additionally, it can display a grayed hintText (like "Type Here to")
+ * when not focussed and empty. When connecting to the changed signals and
+ * querying text, one has to be aware that the text is set to that hint
+ * text if isShowingHintText() returns true (that is, does not contain
+ * valid user input).
+ */
+class QWORKBENCH_UTILS_EXPORT FancyLineEdit : public QLineEdit
+{
+ Q_DISABLE_COPY(FancyLineEdit)
+ Q_OBJECT
+ Q_ENUMS(Side)
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE true)
+ Q_PROPERTY(Side side READ side WRITE setSide DESIGNABLE isSideStored STORED isSideStored)
+ Q_PROPERTY(bool useLayoutDirection READ useLayoutDirection WRITE setUseLayoutDirection DESIGNABLE true)
+ Q_PROPERTY(bool menuTabFocusTrigger READ hasMenuTabFocusTrigger WRITE setMenuTabFocusTrigger DESIGNABLE true)
+ Q_PROPERTY(QString hintText READ hintText WRITE setHintText DESIGNABLE true)
+
+public:
+ enum Side {Left, Right};
+
+ explicit FancyLineEdit(QWidget *parent = 0);
+ ~FancyLineEdit();
+
+ QPixmap pixmap() const;
+
+ void setMenu(QMenu *menu);
+ QMenu *menu() const;
+
+ void setSide(Side side);
+ Side side() const;
+
+ bool useLayoutDirection() const;
+ void setUseLayoutDirection(bool v);
+
+ /* Set whether tabbing in will trigger the menu. */
+ bool hasMenuTabFocusTrigger() const;
+ void setMenuTabFocusTrigger(bool v);
+
+ /* Hint text that is displayed when no focus is set */
+ QString hintText() const;
+
+ bool isShowingHintText() const;
+
+ // Convenience for accessing the text that returns "" in case of isShowingHintText().
+ QString typedText() const;
+
+public slots:
+ void setPixmap(const QPixmap &pixmap);
+ void setHintText(const QString &ht);
+ void showHintText();
+ void hideHintText();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual void focusInEvent(QFocusEvent *e);
+ virtual void focusOutEvent(QFocusEvent *e);
+
+private:
+ bool isSideStored() const;
+ void updateMenuLabel();
+ void positionMenuLabel();
+ void updateStyleSheet(Side side);
+
+ FancyLineEditPrivate *m_d;
+};
+
+} // namespace Utils
+} // namespace Core
+
+#endif // FANCYLINEEDIT_H
diff --git a/src/libs/utils/filenamevalidatinglineedit.cpp b/src/libs/utils/filenamevalidatinglineedit.cpp
new file mode 100644
index 0000000000..1beed717ef
--- /dev/null
+++ b/src/libs/utils/filenamevalidatinglineedit.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filenamevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+FileNameValidatingLineEdit::FileNameValidatingLineEdit(QWidget *parent) :
+ BaseValidatingLineEdit(parent)
+{
+
+}
+
+/* Validate a file base name, check for forbidden characters/strings. */
+
+static const char *notAllowedChars = "/?:&\\*\"|#%<> ";
+static const char *notAllowedSubStrings[] = {".."};
+
+// Naming a file like a device name will break on Windows, even if it is
+// "com1.txt". Since we are cross-platform, we generally disallow such file
+// names.
+static const char *notAllowedStrings[] = {"CON", "AUX", "PRN", "COM1", "COM2", "LPT1", "LPT2" };
+
+bool FileNameValidatingLineEdit::validateFileName(const QString &name, QString *errorMessage /* = 0*/)
+{
+ if (name.isEmpty()) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not be empty");
+ return false;
+ }
+ // Characters
+ for (const char *c = notAllowedChars; *c; c++)
+ if (name.contains(QLatin1Char(*c))) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not contain any of the characters '%1'.").arg(QLatin1String(notAllowedChars));
+ return false;
+ }
+ // Substrings
+ const int notAllowedSubStringCount = sizeof(notAllowedSubStrings)/sizeof(const char *);
+ for (int s = 0; s < notAllowedSubStringCount; s++) {
+ const QLatin1String notAllowedSubString(notAllowedSubStrings[s]);
+ if (name.contains(notAllowedSubString)) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not contain '%1'.").arg(QString(notAllowedSubString));
+ return false;
+ }
+ }
+ // Strings
+ const int notAllowedStringCount = sizeof(notAllowedStrings)/sizeof(const char *);
+ for (int s = 0; s < notAllowedStringCount; s++) {
+ const QLatin1String notAllowedString(notAllowedStrings[s]);
+ if (name == notAllowedString) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not be '%1'.").arg(QString(notAllowedString));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FileNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ return validateFileName(value, errorMessage);
+}
+
+}
+}
diff --git a/src/libs/utils/filenamevalidatinglineedit.h b/src/libs/utils/filenamevalidatinglineedit.h
new file mode 100644
index 0000000000..7535fc196d
--- /dev/null
+++ b/src/libs/utils/filenamevalidatinglineedit.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILENAMEVALIDATINGLINEEDIT_H
+#define FILENAMEVALIDATINGLINEEDIT_H
+
+#include "basevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT FileNameValidatingLineEdit : public BaseValidatingLineEdit {
+ Q_OBJECT
+ Q_DISABLE_COPY(FileNameValidatingLineEdit)
+
+public:
+ explicit FileNameValidatingLineEdit(QWidget *parent = 0);
+
+ static bool validateFileName(const QString &name, QString *errorMessage /* = 0*/);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+};
+
+}
+}
+#endif // FILENAMEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp
new file mode 100644
index 0000000000..9756984b4b
--- /dev/null
+++ b/src/libs/utils/filesearch.cpp
@@ -0,0 +1,216 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filesearch.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QRegExp>
+#include <QtGui/QApplication>
+
+#include <qtconcurrent/runextensions.h>
+
+using namespace Core::Utils;
+
+namespace {
+ void runFileSearch(QFutureInterface<FileSearchResult> &future,
+ QString searchTerm,
+ QStringList files,
+ QTextDocument::FindFlags flags)
+ {
+ future.setProgressRange(0, files.size());
+ int numFilesSearched = 0;
+ int numMatches = 0;
+
+ bool caseInsensitive = !(flags & QTextDocument::FindCaseSensitively);
+ bool wholeWord = (flags & QTextDocument::FindWholeWords);
+
+ QByteArray sa = searchTerm.toUtf8();
+ int scMaxIndex = sa.length()-1;
+ const char *sc = sa.constData();
+
+ QByteArray sal = searchTerm.toLower().toUtf8();
+ const char *scl = sal.constData();
+
+ QByteArray sau = searchTerm.toUpper().toUtf8();
+ const char *scu = sau.constData();
+
+ int chunkSize = qMax(100000, sa.length());
+
+ foreach (QString s, files) {
+ if (future.isPaused())
+ future.waitForResume();
+ if (future.isCanceled()) {
+ future.setProgressValueAndText(numFilesSearched,
+ qApp->translate("FileSearch", "%1: canceled. %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ break;
+ }
+ QFile file(s);
+ if (!file.open(QIODevice::ReadOnly))
+ continue;
+ int lineNr = 1;
+ const char *startOfLastLine = NULL;
+
+ bool firstChunk = true;
+ while (!file.atEnd()) {
+ if (!firstChunk)
+ file.seek(file.pos()-sa.length()+1);
+
+ const QByteArray chunk = file.read(chunkSize);
+ const char *chunkPtr = chunk.constData();
+ startOfLastLine = chunkPtr;
+ for (const char *regionPtr = chunkPtr; regionPtr < chunkPtr + chunk.length()-scMaxIndex; ++regionPtr) {
+ const char *regionEnd = regionPtr + scMaxIndex;
+
+ if (*regionPtr == '\n') {
+ startOfLastLine = regionPtr + 1;
+ ++lineNr;
+ }
+ else if (
+ // case sensitive
+ (!caseInsensitive && *regionPtr == sc[0] && *regionEnd == sc[scMaxIndex])
+ ||
+ // case insensitive
+ (caseInsensitive && (*regionPtr == scl[0] || *regionPtr == scu[0])
+ && (*regionEnd == scl[scMaxIndex] || *regionEnd == scu[scMaxIndex]))
+ ) {
+ const char *afterRegion = regionEnd + 1;
+ const char *beforeRegion = regionPtr - 1;
+ bool equal = true;
+ if (wholeWord &&
+ ( ((*beforeRegion >= '0' && *beforeRegion <= '9') || *beforeRegion >= 'A')
+ || ((*afterRegion >= '0' && *afterRegion <= '9') || *afterRegion >= 'A')))
+ {
+ equal = false;
+ }
+
+ int regionIndex = 1;
+ for (const char *regionCursor = regionPtr + 1; regionCursor < regionEnd; ++regionCursor, ++regionIndex) {
+ if ( // case sensitive
+ (!caseInsensitive && equal && *regionCursor != sc[regionIndex])
+ ||
+ // case insensitive
+ (caseInsensitive && equal && *regionCursor != sc[regionIndex] && *regionCursor != scl[regionIndex] && *regionCursor != scu[regionIndex])
+ ) {
+ equal = false;
+ }
+ }
+ if (equal) {
+ int textLength = chunk.length() - (startOfLastLine - chunkPtr);
+ if (textLength > 0) {
+ QByteArray res;
+ res.reserve(256);
+ int i = 0;
+ int n = 0;
+ while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256)
+ res.append(startOfLastLine[i++]);
+ future.reportResult(FileSearchResult(QDir::toNativeSeparators(s), lineNr, QString(res),
+ regionPtr - startOfLastLine, sa.length()));
+ ++numMatches;
+ }
+ }
+ }
+ }
+ firstChunk = false;
+ }
+ ++numFilesSearched;
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 of %4 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched).arg(files.size()));
+ }
+ if (!future.isCanceled())
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ }
+
+ void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future,
+ QString searchTerm,
+ QStringList files,
+ QTextDocument::FindFlags flags)
+ {
+ future.setProgressRange(0, files.size());
+ int numFilesSearched = 0;
+ int numMatches = 0;
+ if (flags & QTextDocument::FindWholeWords)
+ searchTerm = QString("\b%1\b").arg(searchTerm);
+ Qt::CaseSensitivity caseSensitivity = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ QRegExp expression(searchTerm, caseSensitivity);
+
+ foreach (QString s, files) {
+ if (future.isPaused())
+ future.waitForResume();
+ if (future.isCanceled()) {
+ future.setProgressValueAndText(numFilesSearched,
+ qApp->translate("FileSearch", "%1: canceled. %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ break;
+ }
+ QFile file(s);
+ if (!file.open(QIODevice::ReadOnly))
+ continue;
+ QTextStream stream(&file);
+ int lineNr = 1;
+ QString line;
+ while (!stream.atEnd()) {
+ line = stream.readLine();
+ int pos = 0;
+ while ((pos = expression.indexIn(line, pos)) != -1) {
+ future.reportResult(FileSearchResult(QDir::toNativeSeparators(s), lineNr, line,
+ pos, expression.matchedLength()));
+ pos += expression.matchedLength();
+ }
+ ++lineNr;
+ }
+ ++numFilesSearched;
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 of %4 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched).arg(files.size()));
+ }
+ if (!future.isCanceled())
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ }
+} // namespace
+
+
+QFuture<FileSearchResult> Core::Utils::findInFiles(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags)
+{
+ return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags>(runFileSearch, searchTerm, files, flags);
+}
+
+QFuture<FileSearchResult> Core::Utils::findInFilesRegExp(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags)
+{
+ return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags>(runFileSearchRegExp, searchTerm, files, flags);
+}
diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h
new file mode 100644
index 0000000000..3b747fb548
--- /dev/null
+++ b/src/libs/utils/filesearch.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILESEARCH_H
+#define FILESEARCH_H
+
+#include "utils_global.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QFuture>
+#include <QtGui/QTextDocument>
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT FileSearchResult
+{
+public:
+ FileSearchResult() {}
+ FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength)
+ : fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength)
+ {
+ }
+ QString fileName;
+ int lineNumber;
+ QString matchingLine;
+ int matchStart;
+ int matchLength;
+};
+
+QWORKBENCH_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags);
+
+QWORKBENCH_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags);
+
+} //Utils
+} //Core
+
+#endif
diff --git a/src/libs/utils/filewizarddialog.cpp b/src/libs/utils/filewizarddialog.cpp
new file mode 100644
index 0000000000..2843a304e5
--- /dev/null
+++ b/src/libs/utils/filewizarddialog.cpp
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filewizarddialog.h"
+#include "filewizardpage.h"
+
+#include <QtGui/QAbstractButton>
+
+namespace Core {
+namespace Utils {
+
+FileWizardDialog::FileWizardDialog(QWidget *parent) :
+ QWizard(parent),
+ m_filePage(new FileWizardPage)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/qworkbench/images/qtwatermark.png")));
+ addPage(m_filePage);
+ connect(m_filePage, SIGNAL(activated()), button(QWizard::FinishButton), SLOT(animateClick()));
+}
+
+QString FileWizardDialog::name() const
+{
+ return m_filePage->name();
+}
+
+QString FileWizardDialog::path() const
+{
+ return m_filePage->path();
+}
+
+void FileWizardDialog::setPath(const QString &path)
+{
+ m_filePage->setPath(path);
+
+}
+
+void FileWizardDialog::setName(const QString &name)
+{
+ m_filePage->setName(name);
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/filewizarddialog.h b/src/libs/utils/filewizarddialog.h
new file mode 100644
index 0000000000..6a4a7d9ba6
--- /dev/null
+++ b/src/libs/utils/filewizarddialog.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILEWIZARDDIALOG_H
+#define FILEWIZARDDIALOG_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWizard>
+
+namespace Core {
+namespace Utils {
+
+class FileWizardPage;
+
+/*
+ Standard wizard for a single file letting the user choose name
+ and path. Custom pages can be added via Core::IWizardExtension.
+*/
+
+class QWORKBENCH_UTILS_EXPORT FileWizardDialog : public QWizard {
+ Q_OBJECT
+ Q_DISABLE_COPY(FileWizardDialog)
+public:
+ explicit FileWizardDialog(QWidget *parent = 0);
+
+ QString name() const;
+ QString path() const;
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private:
+ FileWizardPage *m_filePage;
+};
+
+}
+}
+#endif // FILEWIZARDDIALOG_H
diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp
new file mode 100644
index 0000000000..a448ebe739
--- /dev/null
+++ b/src/libs/utils/filewizardpage.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filewizardpage.h"
+#include "ui_filewizardpage.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtGui/QMessageBox>
+
+namespace Core {
+namespace Utils {
+
+struct FileWizardPagePrivate
+{
+ FileWizardPagePrivate();
+ Ui::WizardPage m_ui;
+ bool m_complete;
+};
+
+FileWizardPagePrivate::FileWizardPagePrivate() :
+ m_complete(false)
+{
+}
+
+FileWizardPage::FileWizardPage(QWidget *parent) :
+ QWizardPage(parent),
+ m_d(new FileWizardPagePrivate)
+{
+ m_d->m_ui.setupUi(this);
+ connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()), this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(validChanged()), this, SLOT(slotValidChanged()));
+
+ connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated()));
+}
+
+FileWizardPage::~FileWizardPage()
+{
+ delete m_d;
+}
+
+QString FileWizardPage::name() const
+{
+ return m_d->m_ui.nameLineEdit->text();
+}
+
+QString FileWizardPage::path() const
+{
+ return m_d->m_ui.pathChooser->path();
+}
+
+void FileWizardPage::setPath(const QString &path)
+{
+ m_d->m_ui.pathChooser->setPath(path);
+}
+
+void FileWizardPage::setName(const QString &name)
+{
+ m_d->m_ui.nameLineEdit->setText(name);
+}
+
+void FileWizardPage::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+bool FileWizardPage::isComplete() const
+{
+ return m_d->m_complete;
+}
+
+void FileWizardPage::slotValidChanged()
+{
+ const bool newComplete = m_d->m_ui.pathChooser->isValid() && m_d->m_ui.nameLineEdit->isValid();
+ if (newComplete != m_d->m_complete) {
+ m_d->m_complete = newComplete;
+ emit completeChanged();
+ }
+}
+
+void FileWizardPage::slotActivated()
+{
+ if (m_d->m_complete)
+ emit activated();
+}
+
+bool FileWizardPage::validateBaseName(const QString &name, QString *errorMessage /* = 0*/)
+{
+ return FileNameValidatingLineEdit::validateFileName(name, errorMessage);
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/filewizardpage.h b/src/libs/utils/filewizardpage.h
new file mode 100644
index 0000000000..b2ae28a9d0
--- /dev/null
+++ b/src/libs/utils/filewizardpage.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILEWIZARDPAGE_H
+#define FILEWIZARDPAGE_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWizardPage>
+
+namespace Core {
+namespace Utils {
+
+struct FileWizardPagePrivate;
+
+/* Standard wizard page for a single file letting the user choose name
+ * and path. Sets the "FileNames" QWizard field. */
+
+class QWORKBENCH_UTILS_EXPORT FileWizardPage : public QWizardPage {
+ Q_OBJECT
+ Q_DISABLE_COPY(FileWizardPage)
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true)
+public:
+ explicit FileWizardPage(QWidget *parent = 0);
+ virtual ~FileWizardPage();
+
+ QString name() const;
+ QString path() const;
+
+ virtual bool isComplete() const;
+
+ // Validate a base name entry field (potentially containing extension)
+ static bool validateBaseName(const QString &name, QString *errorMessage = 0);
+
+signals:
+ void activated();
+ void pathChanged();
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private slots:
+ void slotValidChanged();
+ void slotActivated();
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private:
+ FileWizardPagePrivate *m_d;
+};
+
+}
+}
+#endif // FILEWIZARDPAGE_H
diff --git a/src/libs/utils/filewizardpage.ui b/src/libs/utils/filewizardpage.ui
new file mode 100644
index 0000000000..2e614c6f55
--- /dev/null
+++ b/src/libs/utils/filewizardpage.ui
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::WizardPage</class>
+ <widget class="QWizardPage" name="Core::Utils::WizardPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>WizardPage</string>
+ </property>
+ <property name="title">
+ <string>Choose the location</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="nameLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>201</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header>pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::FileNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>filenamevalidatinglineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/linecolumnlabel.cpp b/src/libs/utils/linecolumnlabel.cpp
new file mode 100644
index 0000000000..c6028ab13f
--- /dev/null
+++ b/src/libs/utils/linecolumnlabel.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "linecolumnlabel.h"
+
+namespace Core {
+namespace Utils {
+
+LineColumnLabel::LineColumnLabel(QWidget *parent) :
+ QLabel(parent),
+ m_unused(0)
+{
+}
+
+LineColumnLabel::~LineColumnLabel()
+{
+}
+
+void LineColumnLabel::setText(const QString &text, const QString &maxText)
+{
+ QLabel::setText(text);
+ m_maxText = maxText;
+}
+QSize LineColumnLabel::sizeHint() const
+{
+ return fontMetrics().boundingRect(m_maxText).size();
+}
+
+QString LineColumnLabel::maxText() const
+{
+ return m_maxText;
+}
+
+void LineColumnLabel::setMaxText(const QString &maxText)
+{
+ m_maxText = maxText;
+}
+
+}
+}
diff --git a/src/libs/utils/linecolumnlabel.h b/src/libs/utils/linecolumnlabel.h
new file mode 100644
index 0000000000..d5dea084cc
--- /dev/null
+++ b/src/libs/utils/linecolumnlabel.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LINECOLUMNLABEL_H
+#define LINECOLUMNLABEL_H
+
+#include "utils_global.h"
+#include <QtGui/QLabel>
+
+namespace Core {
+namespace Utils {
+
+/* A label suitable for displaying cursor positions, etc. with a fixed
+ * with derived from a sample text. */
+
+class QWORKBENCH_UTILS_EXPORT LineColumnLabel : public QLabel {
+ Q_DISABLE_COPY(LineColumnLabel)
+ Q_OBJECT
+ Q_PROPERTY(QString maxText READ maxText WRITE setMaxText DESIGNABLE true)
+
+public:
+ explicit LineColumnLabel(QWidget *parent = 0);
+ virtual ~LineColumnLabel();
+
+ void setText(const QString &text, const QString &maxText);
+ QSize sizeHint() const;
+
+ QString maxText() const;
+ void setMaxText(const QString &maxText);
+
+private:
+ QString m_maxText;
+ void *m_unused;
+};
+
+}
+}
+
+#endif // LINECOLUMNLABEL_H
diff --git a/src/libs/utils/listutils.h b/src/libs/utils/listutils.h
new file mode 100644
index 0000000000..3b688f336d
--- /dev/null
+++ b/src/libs/utils/listutils.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LISTUTILS_H
+#define LISTUTILS_H
+
+#include <QtCore/QList>
+
+namespace Core {
+namespace Utils {
+
+template <class T1, class T2>
+QList<T1> qwConvertList(const QList<T2> &list)
+{
+ QList<T1> convertedList;
+ foreach (T2 listEntry, list) {
+ convertedList << qobject_cast<T1>(listEntry);
+ }
+ return convertedList;
+}
+
+} // Utils
+} // Core
+
+#endif // LISTUTILS_H
diff --git a/src/libs/utils/newclasswidget.cpp b/src/libs/utils/newclasswidget.cpp
new file mode 100644
index 0000000000..67cd1f8691
--- /dev/null
+++ b/src/libs/utils/newclasswidget.cpp
@@ -0,0 +1,462 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "newclasswidget.h"
+#include "ui_newclasswidget.h"
+
+#include <utils/filewizardpage.h>
+
+#include <QtGui/QFileDialog>
+#include <QtCore/QFileInfo>
+#include <QtCore/QStringList>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
+
+enum { debugNewClassWidget = 0 };
+
+namespace Core {
+namespace Utils {
+
+struct NewClassWidgetPrivate {
+ NewClassWidgetPrivate();
+
+ Ui::NewClassWidget m_ui;
+ QString m_headerExtension;
+ QString m_sourceExtension;
+ QString m_formExtension;
+ bool m_valid;
+ bool m_classEdited;
+ // Store the "visible" values to prevent the READ accessors from being
+ // fooled by a temporarily hidden widget
+ bool m_baseClassInputVisible;
+ bool m_formInputVisible;
+ bool m_pathInputVisible;
+ bool m_formInputCheckable;
+};
+
+NewClassWidgetPrivate:: NewClassWidgetPrivate() :
+ m_headerExtension(QLatin1String("h")),
+ m_sourceExtension(QLatin1String("cpp")),
+ m_formExtension(QLatin1String("ui")),
+ m_valid(false),
+ m_classEdited(false),
+ m_baseClassInputVisible(true),
+ m_formInputVisible(true),
+ m_pathInputVisible(true),
+ m_formInputCheckable(false)
+{
+}
+
+// --------------------- NewClassWidget
+NewClassWidget::NewClassWidget(QWidget *parent) :
+ QWidget(parent),
+ m_d(new NewClassWidgetPrivate)
+{
+ m_d->m_ui.setupUi(this);
+
+ m_d->m_ui.baseClassComboBox->setEditable(false);
+
+ connect(m_d->m_ui.classLineEdit, SIGNAL(updateFileName(QString)),
+ this, SLOT(updateFileNames(QString)));
+ connect(m_d->m_ui.classLineEdit, SIGNAL(textEdited(QString)),
+ this, SLOT(classNameEdited()));
+ connect(m_d->m_ui.baseClassComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(suggestClassNameFromBase()));
+ connect(m_d->m_ui.baseClassComboBox, SIGNAL(editTextChanged(QString)),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.classLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.formFileLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+
+ connect(m_d->m_ui.classLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()),
+ this, SLOT(slotActivated()));
+
+ connect(m_d->m_ui.generateFormCheckBox, SIGNAL(stateChanged(int)),
+ this, SLOT(slotFormInputChecked()));
+
+ m_d->m_ui.generateFormCheckBox->setChecked(true);
+ setFormInputCheckable(false, true);
+}
+
+NewClassWidget::~NewClassWidget()
+{
+ delete m_d;
+}
+
+void NewClassWidget::classNameEdited()
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension;
+ m_d->m_classEdited = true;
+}
+
+void NewClassWidget::suggestClassNameFromBase()
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension;
+ if (m_d->m_classEdited)
+ return;
+ // Suggest a class unless edited ("QMainWindow"->"MainWindow")
+ QString base = baseClassName();
+ if (base.startsWith(QLatin1Char('Q'))) {
+ base.remove(0, 1);
+ setClassName(base);
+ }
+}
+
+QStringList NewClassWidget::baseClassChoices() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.baseClassComboBox->count();
+ for (int i = 0; i < count; i++)
+ rc.push_back(m_d->m_ui.baseClassComboBox->itemText(i));
+ return rc;
+}
+
+void NewClassWidget::setBaseClassChoices(const QStringList &choices)
+{
+ m_d->m_ui.baseClassComboBox->clear();
+ m_d->m_ui.baseClassComboBox->addItems(choices);
+}
+
+void NewClassWidget::setBaseClassInputVisible(bool visible)
+{
+ m_d->m_baseClassInputVisible = visible;
+ m_d->m_ui.baseClassLabel->setVisible(visible);
+ m_d->m_ui.baseClassComboBox->setVisible(visible);
+}
+
+void NewClassWidget::setBaseClassEditable(bool editable)
+{
+ m_d->m_ui.baseClassComboBox->setEditable(editable);
+}
+
+bool NewClassWidget::isBaseClassInputVisible() const
+{
+ return m_d->m_baseClassInputVisible;
+}
+
+bool NewClassWidget::isBaseClassEditable() const
+{
+ return m_d->m_ui.baseClassComboBox->isEditable();
+}
+
+void NewClassWidget::setFormInputVisible(bool visible)
+{
+ m_d->m_formInputVisible = visible;
+ m_d->m_ui.formLabel->setVisible(visible);
+ m_d->m_ui.formFileLineEdit->setVisible(visible);
+}
+
+bool NewClassWidget::isFormInputVisible() const
+{
+ return m_d->m_formInputVisible;
+}
+
+void NewClassWidget::setFormInputCheckable(bool checkable)
+{
+ setFormInputCheckable(checkable, false);
+}
+
+void NewClassWidget::setFormInputCheckable(bool checkable, bool force)
+{
+ if (!force && checkable == m_d->m_formInputCheckable)
+ return;
+ m_d->m_formInputCheckable = checkable;
+ m_d->m_ui.generateFormLabel->setVisible(checkable);
+ m_d->m_ui.generateFormCheckBox->setVisible(checkable);
+}
+
+void NewClassWidget::setFormInputChecked(bool v)
+{
+ m_d->m_ui.generateFormCheckBox->setChecked(v);
+}
+
+bool NewClassWidget::formInputCheckable() const
+{
+ return m_d->m_formInputCheckable;
+}
+
+bool NewClassWidget::formInputChecked() const
+{
+ return m_d->m_ui.generateFormCheckBox->isChecked();
+}
+
+void NewClassWidget::slotFormInputChecked()
+{
+ const bool checked = formInputChecked();
+ m_d->m_ui.formLabel->setEnabled(checked);
+ m_d->m_ui.formFileLineEdit->setEnabled(checked);
+}
+
+void NewClassWidget::setPathInputVisible(bool visible)
+{
+ m_d->m_pathInputVisible = visible;
+ m_d->m_ui.pathLabel->setVisible(visible);
+ m_d->m_ui.pathChooser->setVisible(visible);
+}
+
+bool NewClassWidget::isPathInputVisible() const
+{
+ return m_d->m_pathInputVisible;
+}
+
+void NewClassWidget::setClassName(const QString &suggestedName)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << suggestedName << m_d->m_headerExtension << m_d->m_sourceExtension;
+ m_d->m_ui.classLineEdit->setText(ClassNameValidatingLineEdit::createClassName(suggestedName));
+}
+
+QString NewClassWidget::className() const
+{
+ return m_d->m_ui.classLineEdit->text();
+}
+
+QString NewClassWidget::baseClassName() const
+{
+ return m_d->m_ui.baseClassComboBox->currentText();
+}
+
+void NewClassWidget::setBaseClassName(const QString &c)
+{
+ const int index = m_d->m_ui.baseClassComboBox->findText(c);
+ if (index != -1) {
+ m_d->m_ui.baseClassComboBox->setCurrentIndex(index);
+ suggestClassNameFromBase();
+ }
+}
+
+QString NewClassWidget::sourceFileName() const
+{
+ return m_d->m_ui.sourceFileLineEdit->text();
+}
+
+QString NewClassWidget::headerFileName() const
+{
+ return m_d->m_ui.headerFileLineEdit->text();
+}
+
+QString NewClassWidget::formFileName() const
+{
+ return m_d->m_ui.formFileLineEdit->text();
+}
+
+QString NewClassWidget::path() const
+{
+ return m_d->m_ui.pathChooser->path();
+}
+
+void NewClassWidget::setPath(const QString &path)
+{
+ m_d->m_ui.pathChooser->setPath(path);
+}
+
+bool NewClassWidget::namespacesEnabled() const
+{
+ return m_d->m_ui.classLineEdit->namespacesEnabled();
+}
+
+void NewClassWidget::setNamespacesEnabled(bool b)
+{
+ m_d->m_ui.classLineEdit->setNamespacesEnabled(b);
+}
+
+QString NewClassWidget::sourceExtension() const
+{
+ return m_d->m_sourceExtension;
+}
+
+void NewClassWidget::setSourceExtension(const QString &e)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_sourceExtension = fixSuffix(e);
+}
+
+QString NewClassWidget::headerExtension() const
+{
+ return m_d->m_headerExtension;
+}
+
+void NewClassWidget::setHeaderExtension(const QString &e)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_headerExtension = fixSuffix(e);
+}
+
+QString NewClassWidget::formExtension() const
+{
+ return m_d->m_formExtension;
+}
+
+void NewClassWidget::setFormExtension(const QString &e)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_formExtension = fixSuffix(e);
+}
+
+void NewClassWidget::slotValidChanged()
+{
+ const bool newValid = isValid();
+ if (newValid != m_d->m_valid) {
+ m_d->m_valid = newValid;
+ emit validChanged();
+ }
+}
+
+bool NewClassWidget::isValid(QString *error) const
+{
+ if (!m_d->m_ui.classLineEdit->isValid()) {
+ if (error)
+ *error = m_d->m_ui.classLineEdit->errorMessage();
+ return false;
+ }
+
+ if (isBaseClassInputVisible() && isBaseClassEditable()) {
+ // TODO: Should this be a ClassNameValidatingComboBox?
+ QRegExp classNameValidator(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*"));
+ const QString baseClass = m_d->m_ui.baseClassComboBox->currentText().trimmed();
+ if (!baseClass.isEmpty() && !classNameValidator.exactMatch(baseClass)) {
+ if (error)
+ *error = tr("Invalid base class name");
+ return false;
+ }
+ }
+
+ if (!m_d->m_ui.headerFileLineEdit->isValid()) {
+ if (error)
+ *error = tr("Invalid header file name: %1").arg(m_d->m_ui.headerFileLineEdit->errorMessage());
+ return false;
+ }
+
+ if (!m_d->m_ui.sourceFileLineEdit->isValid()) {
+ if (error)
+ *error = tr("Invalid source file name: %1").arg(m_d->m_ui.sourceFileLineEdit->errorMessage());
+ return false;
+ }
+
+ if (isFormInputVisible()) {
+ if (!m_d->m_ui.formFileLineEdit->isValid()) {
+ if (error)
+ *error = tr("Invalid form file name: %1").arg(m_d->m_ui.formFileLineEdit->errorMessage());
+ return false;
+ }
+ }
+
+ if (isPathInputVisible()) {
+ if (!m_d->m_ui.pathChooser->isValid()) {
+ if (error)
+ *error = m_d->m_ui.pathChooser->errorMessage();
+ return false;
+ }
+ }
+ return true;
+}
+
+void NewClassWidget::updateFileNames(const QString &baseName)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << baseName << m_d->m_headerExtension << m_d->m_sourceExtension;
+ const QChar dot = QLatin1Char('.');
+ m_d->m_ui.sourceFileLineEdit->setText(baseName + dot + m_d->m_sourceExtension);
+ m_d->m_ui.headerFileLineEdit->setText(baseName + dot + m_d->m_headerExtension);
+ m_d->m_ui.formFileLineEdit->setText(baseName + dot + m_d->m_formExtension);
+}
+
+void NewClassWidget::slotActivated()
+{
+ if (m_d->m_valid)
+ emit activated();
+}
+
+QString NewClassWidget::fixSuffix(const QString &suffix)
+{
+ QString s = suffix;
+ if (s.startsWith(QLatin1Char('.')))
+ s.remove(0, 1);
+ return s;
+}
+
+// Utility to add a suffix to a file unless the user specified one
+static QString ensureSuffix(QString f, const QString &extension)
+{
+ const QChar dot = QLatin1Char('.');
+ if (f.contains(dot))
+ return f;
+ f += dot;
+ f += extension;
+ return f;
+}
+
+// If a non-empty name was passed, expand to directory and suffix
+static QString expandFileName(const QDir &dir, const QString name, const QString &extension)
+{
+ if (name.isEmpty())
+ return QString();
+ return dir.absoluteFilePath(ensureSuffix(name, extension));
+}
+
+QStringList NewClassWidget::files() const
+{
+ QStringList rc;
+ const QDir dir = QDir(path());
+ rc.push_back(expandFileName(dir, headerFileName(), headerExtension()));
+ rc.push_back(expandFileName(dir, sourceFileName(), sourceExtension()));
+ if (isFormInputVisible())
+ rc.push_back(expandFileName(dir, formFileName(), formExtension()));
+ return rc;
+}
+
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/newclasswidget.h b/src/libs/utils/newclasswidget.h
new file mode 100644
index 0000000000..e534189d77
--- /dev/null
+++ b/src/libs/utils/newclasswidget.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef NEWCLASSWIDGET_H
+#define NEWCLASSWIDGET_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+struct NewClassWidgetPrivate;
+
+/* NewClassWidget: Utility widget for 'New Class' wizards. Prompts the user
+ * to enter a class name (optionally derived from some base class) and file
+ * names for header, source and form files. Has some smart logic to derive
+ * the file names from the class name. */
+
+class QWORKBENCH_UTILS_EXPORT NewClassWidget : public QWidget
+{
+ Q_DISABLE_COPY(NewClassWidget)
+ Q_OBJECT
+ Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true)
+ Q_PROPERTY(bool baseClassInputVisible READ isBaseClassInputVisible WRITE setBaseClassInputVisible DESIGNABLE true)
+ Q_PROPERTY(bool baseClassEditable READ isBaseClassEditable WRITE setBaseClassEditable DESIGNABLE false)
+ Q_PROPERTY(bool formInputVisible READ isFormInputVisible WRITE setFormInputVisible DESIGNABLE true)
+ Q_PROPERTY(bool pathInputVisible READ isPathInputVisible WRITE setPathInputVisible DESIGNABLE true)
+ Q_PROPERTY(QString className READ className WRITE setClassName DESIGNABLE true)
+ Q_PROPERTY(QString baseClassName READ baseClassName WRITE setBaseClassName DESIGNABLE true)
+ Q_PROPERTY(QString sourceFileName READ sourceFileName DESIGNABLE false)
+ Q_PROPERTY(QString headerFileName READ headerFileName DESIGNABLE false)
+ Q_PROPERTY(QString formFileName READ formFileName DESIGNABLE false)
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QStringList baseClassChoices READ baseClassChoices WRITE setBaseClassChoices DESIGNABLE true)
+ Q_PROPERTY(QString sourceExtension READ sourceExtension WRITE setSourceExtension DESIGNABLE true)
+ Q_PROPERTY(QString headerExtension READ headerExtension WRITE setHeaderExtension DESIGNABLE true)
+ Q_PROPERTY(QString formExtension READ formExtension WRITE setFormExtension DESIGNABLE true)
+ Q_PROPERTY(bool formInputCheckable READ formInputCheckable WRITE setFormInputCheckable DESIGNABLE true)
+ Q_PROPERTY(bool formInputChecked READ formInputChecked WRITE setFormInputChecked DESIGNABLE true)
+ // Utility "USER" property for wizards containing file names.
+ Q_PROPERTY(QStringList files READ files DESIGNABLE false USER true)
+public:
+ explicit NewClassWidget(QWidget *parent = 0);
+ ~NewClassWidget();
+
+ bool namespacesEnabled() const;
+ bool isBaseClassInputVisible() const;
+ bool isBaseClassEditable() const;
+ bool isFormInputVisible() const;
+ bool isPathInputVisible() const;
+ bool formInputCheckable() const;
+ bool formInputChecked() const;
+
+ QString className() const;
+ QString baseClassName() const;
+ QString sourceFileName() const;
+ QString headerFileName() const;
+ QString formFileName() const;
+ QString path() const;
+ QStringList baseClassChoices() const;
+ QString sourceExtension() const;
+ QString headerExtension() const;
+ QString formExtension() const;
+
+
+ bool isValid(QString *error = 0) const;
+
+ QStringList files() const;
+
+signals:
+ void validChanged();
+ void activated();
+
+public slots:
+ void setNamespacesEnabled(bool b);
+ void setBaseClassInputVisible(bool visible);
+ void setBaseClassEditable(bool editable);
+ void setFormInputVisible(bool visible);
+ void setPathInputVisible(bool visible);
+ void setFormInputCheckable(bool v);
+ void setFormInputChecked(bool v);
+
+ /* The name passed into the new class widget will be reformatted to be a
+ * valid class name. */
+ void setClassName(const QString &suggestedName);
+ void setBaseClassName(const QString &);
+ void setPath(const QString &path);
+ void setBaseClassChoices(const QStringList &choices);
+ void setSourceExtension(const QString &e);
+ void setHeaderExtension(const QString &e);
+ void setFormExtension(const QString &e);
+
+ /* Suggest a class name from the base class by stripping the leading 'Q'
+ * character. This will happen automagically if the base class combo
+ * changes until the class line edited is manually edited. */
+ void suggestClassNameFromBase();
+
+private slots:
+ void updateFileNames(const QString &t);
+ void slotValidChanged();
+ void slotActivated();
+ void classNameEdited();
+ void slotFormInputChecked();
+
+private:
+ void setFormInputCheckable(bool checkable, bool force);
+
+ QString fixSuffix(const QString &suffix);
+ NewClassWidgetPrivate *m_d;
+};
+
+} // namespace Utils
+} // namespace Core
+
+#endif // NEWCLASSWIDGET_H
diff --git a/src/libs/utils/newclasswidget.ui b/src/libs/utils/newclasswidget.ui
new file mode 100644
index 0000000000..14e0a6574b
--- /dev/null
+++ b/src/libs/utils/newclasswidget.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::NewClassWidget</class>
+ <widget class="QWidget" name="Core::Utils::NewClassWidget">
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="classNameLabel">
+ <property name="text">
+ <string>Class name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Core::Utils::ClassNameValidatingLineEdit" name="classLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="baseClassLabel">
+ <property name="text">
+ <string>Base class:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="baseClassComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="headerLabel">
+ <property name="text">
+ <string>Header file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="headerFileLineEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="sourceLabel">
+ <property name="text">
+ <string>Source file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="sourceFileLineEdit"/>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="generateFormLabel">
+ <property name="text">
+ <string>Generate form:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="formLabel">
+ <property name="text">
+ <string>Form file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="formFileLineEdit"/>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/>
+ </item>
+ <item row="5" column="1">
+ <widget class="QCheckBox" name="generateFormCheckBox">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::ClassNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>classnamevalidatinglineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::FileNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header location="global">utils/filenamevalidatinglineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
new file mode 100644
index 0000000000..188aa3b126
--- /dev/null
+++ b/src/libs/utils/pathchooser.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "pathchooser.h"
+#include "basevalidatinglineedit.h"
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QToolButton>
+#include <QtGui/QFileDialog>
+#include <QtGui/QDesktopServices>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtCore/QDebug>
+
+namespace Core {
+namespace Utils {
+
+// ------------------ PathValidatingLineEdit
+class PathValidatingLineEdit : public BaseValidatingLineEdit {
+public:
+ explicit PathValidatingLineEdit(QWidget *parent = 0);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+};
+
+PathValidatingLineEdit::PathValidatingLineEdit(QWidget *parent) :
+ BaseValidatingLineEdit(parent)
+{
+}
+
+bool PathValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ return PathChooser::validatePath(value, errorMessage);
+}
+
+// ------------------ PathChooserPrivate
+struct PathChooserPrivate {
+ PathChooserPrivate();
+
+ PathValidatingLineEdit *m_lineEdit;
+};
+
+PathChooserPrivate::PathChooserPrivate() :
+ m_lineEdit(new PathValidatingLineEdit)
+{
+}
+
+PathChooser::PathChooser(QWidget *parent) :
+ QWidget(parent),
+ m_d(new PathChooserPrivate)
+{
+ QHBoxLayout *hLayout = new QHBoxLayout;
+ hLayout->setContentsMargins(0, 0, 0, 0);
+
+ connect(m_d->m_lineEdit, SIGNAL(validReturnPressed()), this, SIGNAL(returnPressed()));
+ connect(m_d->m_lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(changed()));
+ connect(m_d->m_lineEdit, SIGNAL(validChanged()), this, SIGNAL(validChanged()));
+
+ m_d->m_lineEdit->setMinimumWidth(300);
+ hLayout->addWidget(m_d->m_lineEdit);
+
+ QToolButton *browseButton = new QToolButton;
+ browseButton->setText(tr("..."));
+ connect(browseButton, SIGNAL(clicked()), this, SLOT(slotBrowse()));
+
+ hLayout->addWidget(browseButton);
+ setLayout(hLayout);
+ setFocusProxy(m_d->m_lineEdit);
+}
+
+PathChooser::~PathChooser()
+{
+ delete m_d;
+}
+
+QString PathChooser::path() const
+{
+ return m_d->m_lineEdit->text();
+}
+
+void PathChooser::setPath(const QString &path)
+{
+ const QString defaultPath = path.isEmpty() ? homePath() : path;
+ m_d->m_lineEdit->setText(QDir::toNativeSeparators(defaultPath));
+}
+
+void PathChooser::slotBrowse()
+{
+ QString predefined = path();
+ if (!predefined.isEmpty() && !QFileInfo(predefined).isDir())
+ predefined.clear();
+ // Prompt for a directory, delete trailing slashes unless it is "/", only
+ QString newPath = QFileDialog::getExistingDirectory(this, tr("Choose a path"), predefined);
+ if (!newPath .isEmpty()) {
+ if (newPath .size() > 1 && newPath .endsWith(QDir::separator()))
+ newPath .truncate(newPath .size() - 1);
+ setPath(newPath);
+ }
+}
+
+bool PathChooser::isValid() const
+{
+ return m_d->m_lineEdit->isValid();
+}
+
+QString PathChooser::errorMessage() const
+{
+ return m_d->m_lineEdit->errorMessage();
+}
+
+bool PathChooser::validatePath(const QString &path, QString *errorMessage)
+{
+ if (path.isEmpty()) {
+ if (errorMessage)
+ *errorMessage = tr("The path must not be empty.");
+ return false;
+ }
+ // Must be a directory?
+ const QFileInfo fi(path);
+ if (fi.isDir())
+ return true; // Happy!
+
+ if (!fi.exists()) {
+ if (errorMessage)
+ *errorMessage = tr("The path '%1' does not exist.").arg(path);
+ return false;
+ }
+ // Must be something weird
+ if (errorMessage)
+ *errorMessage = tr("The path '%1' is not a directory.").arg(path);
+ return false;
+}
+
+QString PathChooser::label()
+{
+ return tr("Path:");
+}
+
+QString PathChooser::homePath()
+{
+#ifdef Q_OS_WIN
+ // Return 'users/<name>/Documents' on Windows, since Windows explorer
+ // does not let people actually display the contents of their home
+ // directory. Alternatively, create a QtCreator-specific directory?
+ return QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+#else
+ return QDir::homePath();
+#endif
+}
+
+}
+}
diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h
new file mode 100644
index 0000000000..e09040c4c0
--- /dev/null
+++ b/src/libs/utils/pathchooser.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PATHCHOOSER_H
+#define PATHCHOOSER_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWidget>
+
+namespace Core {
+namespace Utils {
+
+struct PathChooserPrivate;
+
+/* A Control that let's the user choose a path, consisting of a QLineEdit and
+ * a "Browse" button. Has some validation logic for embedding into
+ * QWizardPage. */
+
+class QWORKBENCH_UTILS_EXPORT PathChooser : public QWidget
+{
+ Q_DISABLE_COPY(PathChooser)
+ Q_OBJECT
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+
+public:
+ explicit PathChooser(QWidget *parent = 0);
+ virtual ~PathChooser();
+
+ bool isValid() const;
+ QString errorMessage() const;
+
+ QString path() const;
+
+ // Returns the suggested label title when used in a form layout
+ static QString label();
+
+ static bool validatePath(const QString &path, QString *errorMessage = 0);
+
+ // Return the home directory, which needs some fixing under Windows.
+ static QString homePath();
+
+signals:
+ void validChanged();
+ void changed();
+ void returnPressed();
+
+public slots:
+ void setPath(const QString &);
+
+private slots:
+ void slotBrowse();
+
+private:
+ PathChooserPrivate *m_d;
+};
+
+}
+}
+
+#endif // PATHCHOOSER_H
diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp
new file mode 100644
index 0000000000..bc17333fb9
--- /dev/null
+++ b/src/libs/utils/projectintropage.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "projectintropage.h"
+#include "filewizardpage.h"
+#include "ui_projectintropage.h"
+
+#include <QtGui/QMessageBox>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+
+namespace Core {
+namespace Utils {
+
+struct ProjectIntroPagePrivate
+{
+ ProjectIntroPagePrivate();
+ Ui::ProjectIntroPage m_ui;
+ bool m_complete;
+ // Status label style sheets
+ const QString m_errorStyleSheet;
+ const QString m_warningStyleSheet;
+ const QString m_hintStyleSheet;
+};
+
+ProjectIntroPagePrivate:: ProjectIntroPagePrivate() :
+ m_complete(false),
+ m_errorStyleSheet(QLatin1String("background : red;")),
+ m_warningStyleSheet(QLatin1String("background : yellow;")),
+ m_hintStyleSheet()
+{
+}
+
+ProjectIntroPage::ProjectIntroPage(QWidget *parent) :
+ QWizardPage(parent),
+ m_d(new ProjectIntroPagePrivate)
+{
+ m_d->m_ui.setupUi(this);
+ hideStatusLabel();
+ m_d->m_ui.nameLineEdit->setInitialText(tr("<Enter_Name>"));
+ m_d->m_ui.nameLineEdit->setFocus(Qt::TabFocusReason);
+ connect(m_d->m_ui.pathChooser, SIGNAL(changed()), this, SLOT(slotChanged()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotChanged()));
+ connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated()));
+}
+
+void ProjectIntroPage::insertControl(int row, QWidget *label, QWidget *control)
+{
+ m_d->m_ui.formLayout->insertRow(row, label, control);
+}
+
+ProjectIntroPage::~ProjectIntroPage()
+{
+ delete m_d;
+}
+
+QString ProjectIntroPage::name() const
+{
+ return m_d->m_ui.nameLineEdit->text();
+}
+
+QString ProjectIntroPage::path() const
+{
+ return m_d->m_ui.pathChooser->path();
+}
+
+void ProjectIntroPage::setPath(const QString &path)
+{
+ m_d->m_ui.pathChooser->setPath(path);
+}
+
+void ProjectIntroPage::setName(const QString &name)
+{
+ m_d->m_ui.nameLineEdit->setText(name);
+}
+
+QString ProjectIntroPage::description() const
+{
+ return m_d->m_ui.descriptionLabel->text();
+}
+
+void ProjectIntroPage::setDescription(const QString &description)
+{
+ m_d->m_ui.descriptionLabel->setText(description);
+}
+
+void ProjectIntroPage::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+bool ProjectIntroPage::isComplete() const
+{
+ return m_d->m_complete;
+}
+
+bool ProjectIntroPage::validate()
+{
+ // Validate and display status
+ if (!m_d->m_ui.pathChooser->isValid()) {
+ displayStatusMessage(Error, m_d->m_ui.pathChooser->errorMessage());
+ return false;
+ }
+
+ // Name valid? Ignore 'DisplayingInitialText' state.
+ bool nameValid = false;
+ switch (m_d->m_ui.nameLineEdit->state()) {
+ case BaseValidatingLineEdit::Invalid:
+ displayStatusMessage(Error, m_d->m_ui.nameLineEdit->errorMessage());
+ return false;
+ case BaseValidatingLineEdit::DisplayingInitialText:
+ break;
+ case BaseValidatingLineEdit::Valid:
+ nameValid = true;
+ break;
+ }
+
+ // Check existence of the directory
+ QString projectDir = path();
+ projectDir += QDir::separator();
+ projectDir += m_d->m_ui.nameLineEdit->text();
+ const QFileInfo projectDirFile(projectDir);
+ if (!projectDirFile.exists()) { // All happy
+ hideStatusLabel();
+ return nameValid;
+ }
+
+ if (projectDirFile.isDir()) {
+ displayStatusMessage(Warning, tr("The project already exists."));
+ return nameValid;;
+ }
+ // Not a directory, but something else, likely causing directory creation to fail
+ displayStatusMessage(Error, tr("A file with that name already exists."));
+ return false;
+}
+
+void ProjectIntroPage::slotChanged()
+{
+ const bool newComplete = validate();
+ if (newComplete != m_d->m_complete) {
+ m_d->m_complete = newComplete;
+ emit completeChanged();
+ }
+}
+
+void ProjectIntroPage::slotActivated()
+{
+ if (m_d->m_complete)
+ emit activated();
+}
+
+bool ProjectIntroPage::validateProjectDirectory(const QString &name, QString *errorMessage)
+{
+ return ProjectNameValidatingLineEdit::validateProjectName(name, errorMessage);
+}
+
+void ProjectIntroPage::displayStatusMessage(StatusLabelMode m, const QString &s)
+{
+ switch (m) {
+ case Error:
+ m_d->m_ui.stateLabel->setStyleSheet(m_d->m_errorStyleSheet);
+ break;
+ case Warning:
+ m_d->m_ui.stateLabel->setStyleSheet(m_d->m_warningStyleSheet);
+ break;
+ case Hint:
+ m_d->m_ui.stateLabel->setStyleSheet(m_d->m_hintStyleSheet);
+ break;
+ }
+ m_d->m_ui.stateLabel->setText(s);
+}
+
+void ProjectIntroPage::hideStatusLabel()
+{
+ displayStatusMessage(Hint, QString());
+}
+
+}
+}
diff --git a/src/libs/utils/projectintropage.h b/src/libs/utils/projectintropage.h
new file mode 100644
index 0000000000..56dcc25327
--- /dev/null
+++ b/src/libs/utils/projectintropage.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTINTROPAGE_H
+#define PROJECTINTROPAGE_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWizardPage>
+
+namespace Core {
+namespace Utils {
+
+struct ProjectIntroPagePrivate;
+
+/* Standard wizard page for a single file letting the user choose name
+ * and path. Looks similar to FileWizardPage, but provides additional
+ * functionality:
+ * - Description label at the top for displaying introductory text
+ * - It does on the fly validation (connected to changed()) and displays
+ * warnings/errors in a status label at the bottom (the page is complete
+ * when fully validated, validatePage() is thus not implemented).
+ *
+ * Note: Careful when changing projectintropage.ui. It must have main
+ * geometry cleared and QLayout::SetMinimumSize constraint on the main
+ * layout, otherwise, QWizard will squeeze it due to its strange expanding
+ * hacks. */
+
+class QWORKBENCH_UTILS_EXPORT ProjectIntroPage : public QWizardPage {
+ Q_OBJECT
+ Q_DISABLE_COPY(ProjectIntroPage)
+ Q_PROPERTY(QString description READ description WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true)
+public:
+ explicit ProjectIntroPage(QWidget *parent = 0);
+ virtual ~ProjectIntroPage();
+
+ QString name() const;
+ QString path() const;
+ QString description() const;
+
+ // Insert an additional control into the form layout for the target.
+ void insertControl(int row, QWidget *label, QWidget *control);
+
+ virtual bool isComplete() const;
+
+ // Validate a project directory name entry field
+ static bool validateProjectDirectory(const QString &name, QString *errorMessage);
+
+signals:
+ void activated();
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+ void setDescription(const QString &description);
+
+private slots:
+ void slotChanged();
+ void slotActivated();
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private:
+ enum StatusLabelMode { Error, Warning, Hint };
+
+ bool validate();
+ void displayStatusMessage(StatusLabelMode m, const QString &);
+ void hideStatusLabel();
+
+ ProjectIntroPagePrivate *m_d;
+};
+
+}
+}
+#endif // PROJECTINTROPAGE_H
diff --git a/src/libs/utils/projectintropage.ui b/src/libs/utils/projectintropage.ui
new file mode 100644
index 0000000000..f530b78044
--- /dev/null
+++ b/src/libs/utils/projectintropage.ui
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::ProjectIntroPage</class>
+ <widget class="QWizardPage" name="Core::Utils::ProjectIntroPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>208</width>
+ <height>143</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>WizardPage</string>
+ </property>
+ <property name="title">
+ <string>Introduction and project location</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Core::Utils::ProjectNameValidatingLineEdit" name="nameLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="stateLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header>pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::ProjectNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>projectnamevalidatinglineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/projectnamevalidatinglineedit.cpp b/src/libs/utils/projectnamevalidatinglineedit.cpp
new file mode 100644
index 0000000000..fb979d3934
--- /dev/null
+++ b/src/libs/utils/projectnamevalidatinglineedit.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "projectnamevalidatinglineedit.h"
+#include "filenamevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+ProjectNameValidatingLineEdit::ProjectNameValidatingLineEdit(QWidget *parent) :
+ BaseValidatingLineEdit(parent)
+{
+}
+
+bool ProjectNameValidatingLineEdit::validateProjectName(const QString &name, QString *errorMessage /* = 0*/)
+{
+ // Validation is file name + checking for dots
+ if (!FileNameValidatingLineEdit::validateFileName(name, errorMessage))
+ return false;
+
+ // We don't want dots in the directory name for some legacy Windows
+ // reason. Since we are cross-platform, we generally disallow it.
+ if (name.contains(QLatin1Char('.'))) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not contain the '.'-character.");
+ return false;
+ }
+ return true;
+}
+
+bool ProjectNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ return validateProjectName(value, errorMessage);
+}
+
+}
+}
diff --git a/src/libs/utils/projectnamevalidatinglineedit.h b/src/libs/utils/projectnamevalidatinglineedit.h
new file mode 100644
index 0000000000..c677cea141
--- /dev/null
+++ b/src/libs/utils/projectnamevalidatinglineedit.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTNAMEVALIDATINGLINEEDIT_H
+#define PROJECTNAMEVALIDATINGLINEEDIT_H
+
+#include "basevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT ProjectNameValidatingLineEdit : public BaseValidatingLineEdit {
+ Q_OBJECT
+ Q_DISABLE_COPY(ProjectNameValidatingLineEdit)
+
+public:
+ explicit ProjectNameValidatingLineEdit(QWidget *parent = 0);
+
+ static bool validateProjectName(const QString &name, QString *errorMessage /* = 0*/);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+};
+
+}
+}
+#endif // PROJECTNAMEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/qtcolorbutton.cpp b/src/libs/utils/qtcolorbutton.cpp
new file mode 100644
index 0000000000..8b54bdda1d
--- /dev/null
+++ b/src/libs/utils/qtcolorbutton.cpp
@@ -0,0 +1,290 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtcolorbutton.h"
+#include <QtGui/QColorDialog>
+#include <QtGui/QPainter>
+#include <QtCore/QMimeData>
+#include <QtGui/QDragEnterEvent>
+#include <QtGui/QApplication>
+
+namespace Core {
+namespace Utils {
+
+class QtColorButtonPrivate
+{
+ QtColorButton *q_ptr;
+ Q_DECLARE_PUBLIC(QtColorButton)
+public:
+ QColor m_color;
+#ifndef QT_NO_DRAGANDDROP
+ QColor m_dragColor;
+ QPoint m_dragStart;
+ bool m_dragging;
+#endif
+ bool m_backgroundCheckered;
+ bool m_alphaAllowed;
+
+ void slotEditColor();
+ QColor shownColor() const;
+ QPixmap generatePixmap() const;
+};
+
+void QtColorButtonPrivate::slotEditColor()
+{
+ QColor newColor;
+ if (m_alphaAllowed) {
+ bool ok;
+ const QRgb rgba = QColorDialog::getRgba(m_color.rgba(), &ok, q_ptr);
+ if (!ok)
+ return;
+ newColor = QColor::fromRgba(rgba);
+ } else {
+ newColor = QColorDialog::getColor(m_color, q_ptr);
+ if (!newColor.isValid())
+ return;
+ }
+ if (newColor == q_ptr->color())
+ return;
+ q_ptr->setColor(newColor);
+ emit q_ptr->colorChanged(m_color);
+}
+
+QColor QtColorButtonPrivate::shownColor() const
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (m_dragging)
+ return m_dragColor;
+#endif
+ return m_color;
+}
+
+QPixmap QtColorButtonPrivate::generatePixmap() const
+{
+ QPixmap pix(24, 24);
+
+ int pixSize = 20;
+ QBrush br(shownColor());
+
+ QPixmap pm(2 * pixSize, 2 * pixSize);
+ QPainter pmp(&pm);
+ pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray);
+ pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray);
+ pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray);
+ pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray);
+ pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, shownColor());
+ br = QBrush(pm);
+
+ QPainter p(&pix);
+ int corr = 1;
+ QRect r = pix.rect().adjusted(corr, corr, -corr, -corr);
+ p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
+ p.fillRect(r, br);
+
+ p.fillRect(r.width() / 4 + corr, r.height() / 4 + corr,
+ r.width() / 2, r.height() / 2,
+ QColor(shownColor().rgb()));
+ p.drawRect(pix.rect().adjusted(0, 0, -1, -1));
+
+ return pix;
+}
+
+///////////////
+
+QtColorButton::QtColorButton(QWidget *parent)
+ : QToolButton(parent)
+{
+ d_ptr = new QtColorButtonPrivate;
+ d_ptr->q_ptr = this;
+ d_ptr->m_dragging = false;
+ d_ptr->m_backgroundCheckered = true;
+ d_ptr->m_alphaAllowed = true;
+
+ setAcceptDrops(true);
+
+ connect(this, SIGNAL(clicked()), this, SLOT(slotEditColor()));
+ setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
+}
+
+QtColorButton::~QtColorButton()
+{
+ delete d_ptr;
+}
+
+void QtColorButton::setColor(const QColor &color)
+{
+ if (d_ptr->m_color == color)
+ return;
+ d_ptr->m_color = color;
+ update();
+}
+
+QColor QtColorButton::color() const
+{
+ return d_ptr->m_color;
+}
+
+void QtColorButton::setBackgroundCheckered(bool checkered)
+{
+ if (d_ptr->m_backgroundCheckered == checkered)
+ return;
+ d_ptr->m_backgroundCheckered = checkered;
+ update();
+}
+
+bool QtColorButton::isBackgroundCheckered() const
+{
+ return d_ptr->m_backgroundCheckered;
+}
+
+void QtColorButton::setAlphaAllowed(bool allowed)
+{
+ d_ptr->m_alphaAllowed = allowed;
+}
+
+bool QtColorButton::isAlphaAllowed() const
+{
+ return d_ptr->m_alphaAllowed;
+}
+
+void QtColorButton::paintEvent(QPaintEvent *event)
+{
+ QToolButton::paintEvent(event);
+ if (!isEnabled())
+ return;
+
+ const int pixSize = 10;
+ QBrush br(d_ptr->shownColor());
+ if (d_ptr->m_backgroundCheckered) {
+ QPixmap pm(2 * pixSize, 2 * pixSize);
+ QPainter pmp(&pm);
+ pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
+ pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
+ pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
+ pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
+ pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, d_ptr->shownColor());
+ br = QBrush(pm);
+ }
+
+ QPainter p(this);
+ const int corr = 5;
+ QRect r = rect().adjusted(corr, corr, -corr, -corr);
+ p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
+ p.fillRect(r, br);
+
+ //const int adjX = qRound(r.width() / 4.0);
+ //const int adjY = qRound(r.height() / 4.0);
+ //p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY),
+ // QColor(d_ptr->shownColor().rgb()));
+ /*
+ p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0),
+ QColor(d_ptr->shownColor().rgb()));
+ p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4),
+ QColor(d_ptr->shownColor().rgb()));
+ */
+ /*
+ const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha())));
+ p.setPen(frameColor0);
+ p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1));
+ */
+
+ const QColor frameColor1(0, 0, 0, 26);
+ p.setPen(frameColor1);
+ p.drawRect(r.adjusted(1, 1, -2, -2));
+ const QColor frameColor2(0, 0, 0, 51);
+ p.setPen(frameColor2);
+ p.drawRect(r.adjusted(0, 0, -1, -1));
+}
+
+void QtColorButton::mousePressEvent(QMouseEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (event->button() == Qt::LeftButton)
+ d_ptr->m_dragStart = event->pos();
+#endif
+ QToolButton::mousePressEvent(event);
+}
+
+void QtColorButton::mouseMoveEvent(QMouseEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (event->buttons() & Qt::LeftButton &&
+ (d_ptr->m_dragStart - event->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ QMimeData *mime = new QMimeData;
+ mime->setColorData(color());
+ QDrag *drg = new QDrag(this);
+ drg->setMimeData(mime);
+ drg->setPixmap(d_ptr->generatePixmap());
+ setDown(false);
+ event->accept();
+ drg->start();
+ return;
+ }
+#endif
+ QToolButton::mouseMoveEvent(event);
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QtColorButton::dragEnterEvent(QDragEnterEvent *event)
+{
+ const QMimeData *mime = event->mimeData();
+ if (!mime->hasColor())
+ return;
+
+ event->accept();
+ d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData());
+ d_ptr->m_dragging = true;
+ update();
+}
+
+void QtColorButton::dragLeaveEvent(QDragLeaveEvent *event)
+{
+ event->accept();
+ d_ptr->m_dragging = false;
+ update();
+}
+
+void QtColorButton::dropEvent(QDropEvent *event)
+{
+ event->accept();
+ d_ptr->m_dragging = false;
+ if (d_ptr->m_dragColor == color())
+ return;
+ setColor(d_ptr->m_dragColor);
+ emit colorChanged(color());
+}
+#endif
+
+} // namespace Utils
+} // namespace Core
+
+#include "moc_qtcolorbutton.cpp"
diff --git a/src/libs/utils/qtcolorbutton.h b/src/libs/utils/qtcolorbutton.h
new file mode 100644
index 0000000000..07355c883e
--- /dev/null
+++ b/src/libs/utils/qtcolorbutton.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTCOLORBUTTON_H
+#define QTCOLORBUTTON_H
+
+#include "utils_global.h"
+
+#include <QtGui/QToolButton>
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT QtColorButton : public QToolButton
+{
+ Q_OBJECT
+ Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered)
+ Q_PROPERTY(bool alphaAllowed READ isAlphaAllowed WRITE setAlphaAllowed)
+public:
+ QtColorButton(QWidget *parent = 0);
+ ~QtColorButton();
+
+ bool isBackgroundCheckered() const;
+ void setBackgroundCheckered(bool checkered);
+
+ bool isAlphaAllowed() const;
+ void setAlphaAllowed(bool allowed);
+
+ QColor color() const;
+
+public slots:
+ void setColor(const QColor &color);
+
+signals:
+ void colorChanged(const QColor &color);
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dragLeaveEvent(QDragLeaveEvent *event);
+ void dropEvent(QDropEvent *event);
+#endif
+private:
+ class QtColorButtonPrivate *d_ptr;
+ friend class QtColorButtonPrivate;
+ Q_DISABLE_COPY(QtColorButton)
+ Q_PRIVATE_SLOT(d_ptr, void slotEditColor())
+};
+
+} // namespace Utils
+} // namespace Core
+
+#endif // QTCOLORBUTTON_H
diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp
new file mode 100644
index 0000000000..ca1d9e23de
--- /dev/null
+++ b/src/libs/utils/reloadpromptutils.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "reloadpromptutils.h"
+#include <QtGui/QMessageBox>
+
+using namespace Core;
+using namespace Core::Utils;
+
+QWORKBENCH_UTILS_EXPORT Core::Utils::ReloadPromptAnswer
+ Core::Utils::reloadPrompt(const QString &fileName, QWidget *parent)
+{
+ return reloadPrompt(QObject::tr("File Changed"),
+ QObject::tr("The file %1 has changed outside Qt Creator. Do you want to reload it?").arg(fileName),
+ parent);
+}
+
+QWORKBENCH_UTILS_EXPORT Core::Utils::ReloadPromptAnswer
+ Core::Utils::reloadPrompt(const QString &title, const QString &prompt, QWidget *parent)
+{
+ switch (QMessageBox::question(parent, title, prompt, QMessageBox::Yes|QMessageBox::YesToAll|QMessageBox::No|QMessageBox::NoToAll,
+ QMessageBox::YesToAll)) {
+ case QMessageBox::Yes:
+ return ReloadCurrent;
+ case QMessageBox::YesToAll:
+ return ReloadAll;
+ case QMessageBox::No:
+ return ReloadSkipCurrent;
+ default:
+ break;
+ }
+ return ReloadNone;
+}
diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h
new file mode 100644
index 0000000000..deaf4b920a
--- /dev/null
+++ b/src/libs/utils/reloadpromptutils.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RELOADPROMPTUTILS_H
+#define RELOADPROMPTUTILS_H
+
+#include "utils_global.h"
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+enum ReloadPromptAnswer { ReloadCurrent, ReloadAll, ReloadSkipCurrent, ReloadNone };
+
+QWORKBENCH_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName, QWidget *parent);
+QWORKBENCH_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, const QString &prompt, QWidget *parent);
+
+} // namespace Utils
+} // namespace Core
+
+#endif // RELOADPROMPTUTILS_H
diff --git a/src/libs/utils/settingsutils.cpp b/src/libs/utils/settingsutils.cpp
new file mode 100644
index 0000000000..ca8de01828
--- /dev/null
+++ b/src/libs/utils/settingsutils.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingsutils.h"
+#include <QtCore/QString>
+
+namespace Core {
+namespace Utils {
+
+QWORKBENCH_UTILS_EXPORT QString settingsKey(const QString &category)
+{
+ QString rc(category);
+ const QChar underscore = QLatin1Char('_');
+ const int size = rc.size();
+ for (int i = 0; i < size;i++) {
+ const QChar c = rc.at(i);
+ if (!c.isLetterOrNumber() && c != underscore)
+ rc[i] = underscore;
+ }
+ return rc;
+}
+
+}
+}
diff --git a/src/libs/utils/settingsutils.h b/src/libs/utils/settingsutils.h
new file mode 100644
index 0000000000..734a2f02f9
--- /dev/null
+++ b/src/libs/utils/settingsutils.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSTUTILS_H
+#define SETTINGSTUTILS_H
+
+#include "utils_global.h"
+
+namespace Core {
+namespace Utils {
+
+// Create a usable settings key from a category,
+// for example Editor|C++ -> Editor_C__
+QWORKBENCH_UTILS_EXPORT QString settingsKey(const QString &category);
+
+} // namespace Utils
+} // namespace Core
+
+#endif // SETTINGSTUTILS_H
diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp
new file mode 100644
index 0000000000..aeafcd828d
--- /dev/null
+++ b/src/libs/utils/submiteditorwidget.cpp
@@ -0,0 +1,305 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "submiteditorwidget.h"
+#include "ui_submiteditorwidget.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QPointer>
+
+enum { debug= 0 };
+
+namespace Core {
+namespace Utils {
+
+struct SubmitEditorWidgetPrivate {
+ SubmitEditorWidgetPrivate();
+
+ Ui::SubmitEditorWidget m_ui;
+ bool m_filesSelected;
+ bool m_filesChecked;
+};
+
+SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() :
+ m_filesSelected(false),
+ m_filesChecked(false)
+{
+}
+
+SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) :
+ QWidget(parent),
+ m_d(new SubmitEditorWidgetPrivate)
+{
+ m_d->m_ui.setupUi(this);
+ // File List
+ m_d->m_ui.fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ connect(m_d->m_ui.fileList, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(triggerDiffSelected()));
+ connect(m_d->m_ui.fileList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(fileItemChanged(QListWidgetItem*)));
+ connect(m_d->m_ui.fileList, SIGNAL(itemSelectionChanged()), this, SLOT(fileSelectionChanged()));
+
+ // Text
+ m_d->m_ui.description->setFont(QFont(QLatin1String("Courier")));
+
+ setFocusPolicy(Qt::StrongFocus);
+ setFocusProxy(m_d->m_ui.description);
+}
+
+SubmitEditorWidget::~SubmitEditorWidget()
+{
+ delete m_d;
+}
+
+void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction, QAction *diffAction)
+{
+ if (editorUndoAction) {
+ editorUndoAction->setEnabled(m_d->m_ui.description->document()->isUndoAvailable());
+ connect(m_d->m_ui.description, SIGNAL(undoAvailable(bool)), editorUndoAction, SLOT(setEnabled(bool)));
+ connect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo()));
+ }
+ if (editorRedoAction) {
+ editorRedoAction->setEnabled(m_d->m_ui.description->document()->isRedoAvailable());
+ connect(m_d->m_ui.description, SIGNAL(redoAvailable(bool)), editorRedoAction, SLOT(setEnabled(bool)));
+ connect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo()));
+ }
+
+ if (submitAction) {
+ if (debug)
+ qDebug() << submitAction << m_d->m_ui.fileList->count() << "items" << m_d->m_filesChecked;
+ submitAction->setEnabled(m_d->m_filesChecked);
+ connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool)));
+ }
+ if (diffAction) {
+ if (debug)
+ qDebug() << diffAction << m_d->m_filesSelected;
+ diffAction->setEnabled(m_d->m_filesSelected);
+ connect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool)));
+ connect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected()));
+ }
+}
+
+void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction, QAction *diffAction)
+{
+ if (editorUndoAction) {
+ disconnect(m_d->m_ui.description, SIGNAL(undoAvailableChanged(bool)), editorUndoAction, SLOT(setEnabled(bool)));
+ disconnect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo()));
+ }
+ if (editorRedoAction) {
+ disconnect(m_d->m_ui.description, SIGNAL(redoAvailableChanged(bool)), editorRedoAction, SLOT(setEnabled(bool)));
+ disconnect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo()));
+ }
+
+ if (submitAction)
+ disconnect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool)));
+
+ if (diffAction) {
+ disconnect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool)));
+ disconnect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected()));
+ }
+}
+
+
+QString SubmitEditorWidget::trimmedDescriptionText() const
+{
+ // Make sure we have one terminating NL
+ QString text = descriptionText().trimmed();
+ text += QLatin1Char('\n');
+ return text;
+}
+
+QString SubmitEditorWidget::descriptionText() const
+{
+ return m_d->m_ui.description->toPlainText();
+}
+
+void SubmitEditorWidget::setDescriptionText(const QString &text)
+{
+ m_d->m_ui.description->setPlainText(text);
+}
+
+QStringList SubmitEditorWidget::fileList() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.fileList->count();
+ for (int i = 0; i < count; i++)
+ rc.push_back(m_d->m_ui.fileList->item(i)->text());
+ return rc;
+}
+
+void SubmitEditorWidget::addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable)
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << list << checked << userCheckable;
+ foreach (const QString &f, list) {
+ QListWidgetItem *item = new QListWidgetItem(f);
+ item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
+ if (!userCheckable)
+ item->setFlags(item->flags() & ~Qt::ItemIsUserCheckable);
+ m_d->m_ui.fileList->addItem(item);
+ }
+}
+
+void SubmitEditorWidget::addFiles(const QStringList &list, bool checked, bool userCheckable)
+{
+ if (list.empty())
+ return;
+
+ const bool blocked = m_d->m_ui.fileList->blockSignals(true);
+ addFilesUnblocked(list, checked, userCheckable);
+ m_d->m_ui.fileList->blockSignals(blocked);
+ // Did we gain any checked files..update action accordingly
+ if (!m_d->m_filesChecked && checked) {
+ m_d->m_filesChecked = true;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+}
+
+void SubmitEditorWidget::setFileList(const QStringList &list)
+{
+ // Trigger enabling of menu action
+ m_d->m_ui.fileList->clearSelection();
+
+ const bool blocked = m_d->m_ui.fileList->blockSignals(true);
+ m_d->m_ui.fileList->clear();
+ if (!list.empty()) {
+ addFilesUnblocked(list, true, true);
+ // Checked files added?
+ if (!m_d->m_filesChecked) {
+ m_d->m_filesChecked = true;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+ }
+ m_d->m_ui.fileList->blockSignals(blocked);
+}
+
+static bool containsCheckState(const QListWidget *lw, Qt::CheckState cs)
+{
+ const int count = lw->count();
+ for (int i = 0; i < count; i++)
+ if (lw->item(i)->checkState() == cs)
+ return true;
+ return false;
+}
+
+QStringList SubmitEditorWidget::selectedFiles() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.fileList->count();
+ for (int i = 0; i < count; i++) {
+ const QListWidgetItem *item = m_d->m_ui.fileList->item(i);
+ if (item->isSelected())
+ rc.push_back(item->text());
+ }
+ return rc;
+}
+
+QStringList SubmitEditorWidget::checkedFiles() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.fileList->count();
+ for (int i = 0; i < count; i++) {
+ const QListWidgetItem *item = m_d->m_ui.fileList->item(i);
+ if (item->checkState() == Qt::Checked)
+ rc.push_back(item->text());
+ }
+ return rc;
+}
+
+QPlainTextEdit *SubmitEditorWidget::descriptionEdit() const
+{
+ return m_d->m_ui.description;
+}
+
+void SubmitEditorWidget::triggerDiffSelected()
+{
+ const QStringList sel = selectedFiles();
+ if (!sel.empty())
+ emit diffSelected(sel);
+}
+
+void SubmitEditorWidget::fileItemChanged(QListWidgetItem *item)
+{
+ const Qt::CheckState st = item->checkState();
+ if (debug)
+ qDebug() << Q_FUNC_INFO << st << item->text() << m_d->m_filesChecked;
+ // Enable the actions according to check state
+ switch (st) {
+ case Qt::Unchecked: // Item was unchecked: Any checked items left?
+ if (m_d->m_filesChecked && !containsCheckState(m_d->m_ui.fileList, Qt::Checked)) {
+ m_d->m_filesChecked = false;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+ break;
+ case Qt::Checked:
+ // Item was Checked. First one?
+ if (!m_d->m_filesChecked) {
+ m_d->m_filesChecked = true;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+ break;
+ case Qt::PartiallyChecked: // Errm?
+ break;
+ }
+}
+
+void SubmitEditorWidget::fileSelectionChanged()
+{
+ const bool newFilesSelected = !m_d->m_ui.fileList->selectedItems().empty();
+ if (debug)
+ qDebug() << Q_FUNC_INFO << newFilesSelected;
+ if (m_d->m_filesSelected != newFilesSelected) {
+ m_d->m_filesSelected = newFilesSelected;
+ emit fileSelectionChanged(m_d->m_filesSelected);
+ if (debug)
+ qDebug() << Q_FUNC_INFO << m_d->m_filesSelected;
+ }
+}
+
+void SubmitEditorWidget::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void SubmitEditorWidget::insertTopWidget(QWidget *w)
+{
+ m_d->m_ui.vboxLayout->insertWidget(0, w);
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/submiteditorwidget.h b/src/libs/utils/submiteditorwidget.h
new file mode 100644
index 0000000000..3c40ccecba
--- /dev/null
+++ b/src/libs/utils/submiteditorwidget.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBMITEDITORWIDGET_H
+#define SUBMITEDITORWIDGET_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QPlainTextEdit;
+class QListWidgetItem;
+class QAction;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+struct SubmitEditorWidgetPrivate;
+
+/* The submit editor presents the commit message in a text editor and an
+ * checkable list of modified files in a list window. The user can delete
+ * files from the list by pressing unchecking them or diff the selection
+ * by doubleclicking.
+ *
+ * Additionally, standard creator actions can be registered:
+ * Undo/redo will be set up to work with the description editor.
+ * Submit will be set up to be enabled according to checkstate.
+ * Diff will be set up to trigger diffSelected().
+ *
+ * Note that the actions are connected by signals; in the rare event that there
+ * are several instances of the SubmitEditorWidget belonging to the same
+ * context active, the actions must be registered/unregistered in the editor
+ * change event.
+ * Care should be taken to ensure the widget is deleted properly when the
+ * editor closes. */
+
+class QWORKBENCH_UTILS_EXPORT SubmitEditorWidget : public QWidget {
+ Q_OBJECT
+ Q_DISABLE_COPY(SubmitEditorWidget)
+ Q_PROPERTY(QString descriptionText READ descriptionText WRITE setDescriptionText DESIGNABLE true)
+ Q_PROPERTY(QStringList fileList READ fileList WRITE setFileList DESIGNABLE true)
+public:
+ explicit SubmitEditorWidget(QWidget *parent = 0);
+ virtual ~SubmitEditorWidget();
+
+ void registerActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction = 0, QAction *diffAction = 0);
+ void unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction = 0, QAction *diffAction = 0);
+
+ QString descriptionText() const;
+ void setDescriptionText(const QString &text);
+ // Should be used to normalize newlines.
+ QString trimmedDescriptionText() const;
+
+ // The raw file list
+ QStringList fileList() const;
+ void addFiles(const QStringList&, bool checked = true, bool userCheckable = true);
+ void setFileList(const QStringList&);
+
+ // Files to be included in submit
+ QStringList checkedFiles() const;
+
+ // Selected files for diff
+ QStringList selectedFiles() const;
+
+ QPlainTextEdit *descriptionEdit() const;
+
+signals:
+ void diffSelected(const QStringList &);
+ void fileSelectionChanged(bool someFileSelected);
+ void fileCheckStateChanged(bool someFileChecked);
+
+protected:
+ virtual void changeEvent(QEvent *e);
+ void insertTopWidget(QWidget *w);
+
+private slots:
+ void triggerDiffSelected();
+ void fileItemChanged(QListWidgetItem *);
+ void fileSelectionChanged();
+
+private:
+ void addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable);
+
+ SubmitEditorWidgetPrivate *m_d;
+};
+
+}
+}
+#endif // SUBMITEDITORWIDGET_H
diff --git a/src/libs/utils/submiteditorwidget.ui b/src/libs/utils/submiteditorwidget.ui
new file mode 100644
index 0000000000..1a30e8b791
--- /dev/null
+++ b/src/libs/utils/submiteditorwidget.ui
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::SubmitEditorWidget</class>
+ <widget class="QWidget" name="Core::Utils::SubmitEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>582</width>
+ <height>502</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Subversion Submit</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox" name="descriptionBox">
+ <property name="title">
+ <string>Des&amp;cription</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QPlainTextEdit" name="description">
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>F&amp;iles</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QListWidget" name="fileList">
+ <property name="font">
+ <font/>
+ </property>
+ <property name="textElideMode">
+ <enum>Qt::ElideNone</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp
new file mode 100644
index 0000000000..71bcdffb6c
--- /dev/null
+++ b/src/libs/utils/synchronousprocess.cpp
@@ -0,0 +1,356 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "synchronousprocess.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+#include <QtCore/QEventLoop>
+#include <QtCore/QTextCodec>
+
+#include <QtGui/QApplication>
+
+enum { debug = 0 };
+
+enum { defaultMaxHangTimerCount = 10 };
+
+namespace Core {
+namespace Utils {
+
+// ----------- SynchronousProcessResponse
+SynchronousProcessResponse::SynchronousProcessResponse() :
+ result(StartFailed),
+ exitCode(-1)
+{
+}
+
+void SynchronousProcessResponse::clear()
+{
+ result = StartFailed;
+ exitCode = -1;
+ stdOut.clear();
+ stdErr.clear();
+}
+
+QWORKBENCH_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r)
+{
+ QDebug nsp = str.nospace();
+ nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n'
+ << r.stdOut.size() << " bytes stdout, stderr=" << r.stdErr << '\n';
+ return str;
+}
+
+// Data for one channel buffer (stderr/stdout)
+struct ChannelBuffer {
+ ChannelBuffer();
+ void clearForRun();
+ QByteArray linesRead();
+
+ QByteArray data;
+ bool firstData;
+ bool bufferedSignalsEnabled;
+ bool firstBuffer;
+ int bufferPos;
+};
+
+ChannelBuffer::ChannelBuffer() :
+ firstData(true),
+ bufferedSignalsEnabled(false),
+ firstBuffer(true),
+ bufferPos(0)
+{
+}
+
+void ChannelBuffer::clearForRun()
+{
+ firstData = true;
+ firstBuffer = true;
+ bufferPos = 0;
+}
+
+/* Check for complete lines read from the device and return them, moving the
+ * buffer position. This is based on the assumption that '\n' is the new line
+ * marker in any sane codec. */
+QByteArray ChannelBuffer::linesRead()
+{
+ // Any new lines?
+ const int lastLineIndex = data.lastIndexOf('\n');
+ if (lastLineIndex == -1 || lastLineIndex <= bufferPos)
+ return QByteArray();
+ const int nextBufferPos = lastLineIndex + 1;
+ const QByteArray lines = data.mid(bufferPos, nextBufferPos - bufferPos);
+ bufferPos = nextBufferPos;
+ return lines;
+}
+
+// ----------- SynchronousProcessPrivate
+struct SynchronousProcessPrivate {
+ SynchronousProcessPrivate();
+ void clearForRun();
+
+ QTextCodec *m_stdOutCodec;
+ QProcess m_process;
+ QTimer m_timer;
+ QEventLoop m_eventLoop;
+ SynchronousProcessResponse m_result;
+ int m_hangTimerCount;
+ int m_maxHangTimerCount;
+
+ ChannelBuffer m_stdOut;
+ ChannelBuffer m_stdErr;
+};
+
+SynchronousProcessPrivate::SynchronousProcessPrivate() :
+ m_stdOutCodec(0),
+ m_hangTimerCount(0),
+ m_maxHangTimerCount(defaultMaxHangTimerCount)
+{
+}
+
+void SynchronousProcessPrivate::clearForRun()
+{
+ m_hangTimerCount = 0;
+ m_stdOut.clearForRun();
+ m_stdErr.clearForRun();
+ m_result.clear();
+}
+
+// ----------- SynchronousProcess
+SynchronousProcess::SynchronousProcess() :
+ m_d(new SynchronousProcessPrivate)
+{
+ m_d->m_timer.setInterval(1000);
+ connect(&m_d->m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+ connect(&m_d->m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));
+ connect(&m_d->m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
+ connect(&m_d->m_process, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(stdOutReady()));
+ connect(&m_d->m_process, SIGNAL(readyReadStandardError()),
+ this, SLOT(stdErrReady()));
+}
+
+SynchronousProcess::~SynchronousProcess()
+{
+ delete m_d;
+}
+
+void SynchronousProcess::setTimeout(int timeoutMS)
+{
+ m_d->m_maxHangTimerCount = qMax(2, timeoutMS / 1000);
+}
+
+int SynchronousProcess::timeout() const
+{
+ return 1000 * m_d->m_maxHangTimerCount;
+}
+
+void SynchronousProcess::setStdOutCodec(QTextCodec *c)
+{
+ m_d->m_stdOutCodec = c;
+}
+
+QTextCodec *SynchronousProcess::stdOutCodec() const
+{
+ return m_d->m_stdOutCodec;
+}
+
+bool SynchronousProcess::stdOutBufferedSignalsEnabled() const
+{
+ return m_d->m_stdOut.bufferedSignalsEnabled;
+}
+
+void SynchronousProcess::setStdOutBufferedSignalsEnabled(bool v)
+{
+ m_d->m_stdOut.bufferedSignalsEnabled = v;
+}
+
+bool SynchronousProcess::stdErrBufferedSignalsEnabled() const
+{
+ return m_d->m_stdErr.bufferedSignalsEnabled;
+}
+
+void SynchronousProcess::setStdErrBufferedSignalsEnabled(bool v)
+{
+ m_d->m_stdErr.bufferedSignalsEnabled = v;
+}
+
+QStringList SynchronousProcess::environment() const
+{
+ return m_d->m_process.environment();
+}
+
+void SynchronousProcess::setEnvironment(const QStringList &e)
+{
+ m_d->m_process.setEnvironment(e);
+}
+
+SynchronousProcessResponse SynchronousProcess::run(const QString &binary,
+ const QStringList &args)
+{
+ if (debug)
+ qDebug() << '>' << Q_FUNC_INFO << binary << args;
+
+ m_d->clearForRun();
+ m_d->m_timer.start();
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+
+ m_d->m_process.start(binary, args, QIODevice::ReadOnly);
+ m_d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
+ if (m_d->m_result.result == SynchronousProcessResponse::Finished || m_d->m_result.result == SynchronousProcessResponse::FinishedError) {
+ processStdOut(false);
+ processStdErr(false);
+ }
+
+ m_d->m_result.stdOut = convertStdOut(m_d->m_stdOut.data);
+ m_d->m_result.stdErr = convertStdErr(m_d->m_stdErr.data);
+
+ m_d->m_timer.stop();
+ QApplication::restoreOverrideCursor();
+
+ if (debug)
+ qDebug() << '<' << Q_FUNC_INFO << binary << m_d->m_result;
+ return m_d->m_result;
+}
+
+void SynchronousProcess::slotTimeout()
+{
+ if (++m_d->m_hangTimerCount > m_d->m_maxHangTimerCount) {
+ m_d->m_process.kill();
+ m_d->m_result.result = SynchronousProcessResponse::Hang;
+ }
+
+ if (debug)
+ qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount;
+}
+
+void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e)
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << exitCode << e;
+ m_d->m_hangTimerCount = 0;
+ switch (e) {
+ case QProcess::NormalExit:
+ m_d->m_result.result = exitCode ? SynchronousProcessResponse::FinishedError : SynchronousProcessResponse::Finished;
+ m_d->m_result.exitCode = exitCode;
+ break;
+ case QProcess::CrashExit:
+ m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
+ m_d->m_result.exitCode = -1;
+ break;
+ }
+ m_d->m_eventLoop.quit();
+}
+
+void SynchronousProcess::error(QProcess::ProcessError e)
+{
+ m_d->m_hangTimerCount = 0;
+ if (debug)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_result.result = SynchronousProcessResponse::StartFailed;
+ m_d->m_eventLoop.quit();
+}
+
+void SynchronousProcess::stdOutReady()
+{
+ m_d->m_hangTimerCount = 0;
+ processStdOut(true);
+}
+
+void SynchronousProcess::stdErrReady()
+{
+ m_d->m_hangTimerCount = 0;
+ processStdErr(true);
+}
+
+QString SynchronousProcess::convertStdErr(const QByteArray &ba)
+{
+ return QString::fromLocal8Bit(ba).remove(QLatin1Char('\r'));
+}
+
+QString SynchronousProcess::convertStdOut(const QByteArray &ba) const
+{
+ QString stdOut = m_d->m_stdOutCodec ? m_d->m_stdOutCodec->toUnicode(ba) : QString::fromLocal8Bit(ba);
+ return stdOut.remove(QLatin1Char('\r'));
+}
+
+void SynchronousProcess::processStdOut(bool emitSignals)
+{
+ // Handle binary data
+ const QByteArray ba = m_d->m_process.readAllStandardOutput();
+ if (debug > 1)
+ qDebug() << Q_FUNC_INFO << emitSignals << ba;
+ if (!ba.isEmpty()) {
+ m_d->m_stdOut.data += ba;
+ if (emitSignals) {
+ // Emit binary signals
+ emit stdOut(ba, m_d->m_stdOut.firstData);
+ m_d->m_stdOut.firstData = false;
+ // Buffered. Emit complete lines?
+ if (m_d->m_stdOut.bufferedSignalsEnabled) {
+ const QByteArray lines = m_d->m_stdOut.linesRead();
+ if (!lines.isEmpty()) {
+ emit stdOutBuffered(convertStdOut(lines), m_d->m_stdOut.firstBuffer);
+ m_d->m_stdOut.firstBuffer = false;
+ }
+ }
+ }
+ }
+}
+
+void SynchronousProcess::processStdErr(bool emitSignals)
+{
+ // Handle binary data
+ const QByteArray ba = m_d->m_process.readAllStandardError();
+ if (debug > 1)
+ qDebug() << Q_FUNC_INFO << emitSignals << ba;
+ if (!ba.isEmpty()) {
+ m_d->m_stdErr.data += ba;
+ if (emitSignals) {
+ // Emit binary signals
+ emit stdErr(ba, m_d->m_stdErr.firstData);
+ m_d->m_stdErr.firstData = false;
+ if (m_d->m_stdErr.bufferedSignalsEnabled) {
+ // Buffered. Emit complete lines?
+ const QByteArray lines = m_d->m_stdErr.linesRead();
+ if (!lines.isEmpty()) {
+ emit stdErrBuffered(convertStdErr(lines), m_d->m_stdErr.firstBuffer);
+ m_d->m_stdErr.firstBuffer = false;
+ }
+ }
+ }
+ }
+}
+
+}
+}
diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h
new file mode 100644
index 0000000000..9458655d6b
--- /dev/null
+++ b/src/libs/utils/synchronousprocess.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SYNCHRONOUSPROCESS_H
+#define SYNCHRONOUSPROCESS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QStringList>
+
+#include "utils_global.h"
+
+QT_BEGIN_NAMESPACE
+class QTextCodec;
+class QDebug;
+class QByteArray;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+struct SynchronousProcessPrivate;
+
+/* Result of SynchronousProcess execution */
+struct QWORKBENCH_UTILS_EXPORT SynchronousProcessResponse {
+ enum Result {
+ // Finished with return code 0
+ Finished,
+ // Finished with return code != 0
+ FinishedError,
+ // Process terminated abnormally (kill)
+ TerminatedAbnormally,
+ // Executable could not be started
+ StartFailed,
+ // Hang, no output after time out
+ Hang };
+
+ SynchronousProcessResponse();
+ void clear();
+
+ Result result;
+ int exitCode;
+ QString stdOut;
+ QString stdErr;
+};
+
+QWORKBENCH_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &);
+
+/* SynchronousProcess: Runs a synchronous process in its own event loop
+ * that blocks only user input events. Thus, it allows for the gui to
+ * repaint and append output to log windows.
+ *
+ * The stdOut(), stdErr() signals are emitted unbuffered as the process
+ * writes them.
+ *
+ * The stdOutBuffered(), stdErrBuffered() signals are emitted with complete
+ * lines based on the '\n' marker if they are enabled using
+ * stdOutBufferedSignalsEnabled()/setStdErrBufferedSignalsEnabled().
+ * They would typically be used for log windows. */
+
+class QWORKBENCH_UTILS_EXPORT SynchronousProcess : public QObject {
+ Q_OBJECT
+public:
+ SynchronousProcess();
+ virtual ~SynchronousProcess();
+
+ /* Timeout for hanging processes (no reaction on stderr/stdout)*/
+ void setTimeout(int timeoutMS);
+ int timeout() const;
+
+ void setStdOutCodec(QTextCodec *c);
+ QTextCodec *stdOutCodec() const;
+
+ bool stdOutBufferedSignalsEnabled() const;
+ void setStdOutBufferedSignalsEnabled(bool);
+
+ bool stdErrBufferedSignalsEnabled() const;
+ void setStdErrBufferedSignalsEnabled(bool);
+
+ QStringList environment() const;
+ void setEnvironment(const QStringList &);
+
+ SynchronousProcessResponse run(const QString &binary, const QStringList &args);
+
+signals:
+ void stdOut(const QByteArray &data, bool firstTime);
+ void stdErr(const QByteArray &data, bool firstTime);
+
+ void stdOutBuffered(const QString &data, bool firstTime);
+ void stdErrBuffered(const QString &data, bool firstTime);
+
+private slots:
+ void slotTimeout();
+ void finished(int exitCode, QProcess::ExitStatus e);
+ void error(QProcess::ProcessError);
+ void stdOutReady();
+ void stdErrReady();
+
+private:
+ void processStdOut(bool emitSignals);
+ void processStdErr(bool emitSignals);
+ static QString convertStdErr(const QByteArray &);
+ QString convertStdOut(const QByteArray &) const;
+
+ SynchronousProcessPrivate *m_d;
+};
+
+}
+}
+#endif
diff --git a/src/libs/utils/utils.pri b/src/libs/utils/utils.pri
new file mode 100644
index 0000000000..4e173f2cad
--- /dev/null
+++ b/src/libs/utils/utils.pri
@@ -0,0 +1 @@
+LIBS *= -l$$qtLibraryTarget(Utils)
diff --git a/src/libs/utils/utils.pro b/src/libs/utils/utils.pro
new file mode 100644
index 0000000000..d98ca1d889
--- /dev/null
+++ b/src/libs/utils/utils.pro
@@ -0,0 +1,53 @@
+TEMPLATE = lib
+TARGET = Utils
+
+DEFINES += QWORKBENCH_UTILS_LIBRARY
+
+include(../../qworkbenchlibrary.pri)
+
+SOURCES += \
+ reloadpromptutils.cpp \
+ settingsutils.cpp \
+ filesearch.cpp \
+ pathchooser.cpp \
+ filewizardpage.cpp \
+ filewizarddialog.cpp \
+ projectintropage.cpp \
+ basevalidatinglineedit.cpp \
+ filenamevalidatinglineedit.cpp \
+ projectnamevalidatinglineedit.cpp \
+ codegeneration.cpp \
+ newclasswidget.cpp \
+ classnamevalidatinglineedit.cpp \
+ linecolumnlabel.cpp \
+ fancylineedit.cpp \
+ qtcolorbutton.cpp \
+ submiteditorwidget.cpp \
+ synchronousprocess.cpp
+
+HEADERS += \
+ utils_global.h \
+ reloadpromptutils.h \
+ settingsutils.h \
+ filesearch.h \
+ listutils.h \
+ pathchooser.h \
+ filewizardpage.h \
+ filewizarddialog.h \
+ projectintropage.h \
+ basevalidatinglineedit.h \
+ filenamevalidatinglineedit.h \
+ projectnamevalidatinglineedit.h \
+ codegeneration.h \
+ newclasswidget.h \
+ classnamevalidatinglineedit.h \
+ linecolumnlabel.h \
+ fancylineedit.h \
+ qtcolorbutton.h \
+ submiteditorwidget.h \
+ synchronousprocess.h
+
+FORMS += filewizardpage.ui \
+ projectintropage.ui \
+ newclasswidget.ui \
+ submiteditorwidget.ui
diff --git a/src/libs/utils/utils_global.h b/src/libs/utils/utils_global.h
new file mode 100644
index 0000000000..3a91f77a2b
--- /dev/null
+++ b/src/libs/utils/utils_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef UTILS_GLOBAL_H
+#define UTILS_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(QWORKBENCH_UTILS_LIBRARY)
+# define QWORKBENCH_UTILS_EXPORT Q_DECL_EXPORT
+#else
+# define QWORKBENCH_UTILS_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // UTILS_GLOBAL_H
diff --git a/src/plugins/bineditor/BinEditor.mimetypes.xml b/src/plugins/bineditor/BinEditor.mimetypes.xml
new file mode 100644
index 0000000000..4fcd960365
--- /dev/null
+++ b/src/plugins/bineditor/BinEditor.mimetypes.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/octet-stream">
+ <comment>unknown</comment>
+ <comment xml:lang="bg">ÐеизвеÑтен тип</comment>
+ <comment xml:lang="ca">desconegut</comment>
+ <comment xml:lang="cs">Neznámý</comment>
+ <comment xml:lang="cy">Anhysbys</comment>
+ <comment xml:lang="da">ukendt</comment>
+ <comment xml:lang="de">unbekannt</comment>
+ <comment xml:lang="el">αγνωστο</comment>
+ <comment xml:lang="eo">nekonata</comment>
+ <comment xml:lang="es">desconocido</comment>
+ <comment xml:lang="eu">ezezaguna</comment>
+ <comment xml:lang="fi">tuntematon</comment>
+ <comment xml:lang="fr">inconnu</comment>
+ <comment xml:lang="hu">ismeretlen</comment>
+ <comment xml:lang="it">Sconosciuto</comment>
+ <comment xml:lang="ja">ä¸æ˜Ž</comment>
+ <comment xml:lang="ko">ì•Œ 수 ì—†ìŒ</comment>
+ <comment xml:lang="lt">nežinoma</comment>
+ <comment xml:lang="ms">Entah</comment>
+ <comment xml:lang="nb">ukjent</comment>
+ <comment xml:lang="nl">onbekend</comment>
+ <comment xml:lang="nn">ukjend</comment>
+ <comment xml:lang="pl">nieznany typ</comment>
+ <comment xml:lang="pt">desconhecido</comment>
+ <comment xml:lang="pt_BR">Desconhecido</comment>
+ <comment xml:lang="ru">неизвеÑтный</comment>
+ <comment xml:lang="rw">itazwi</comment>
+ <comment xml:lang="sq">nuk njihet</comment>
+ <comment xml:lang="sr">непознато</comment>
+ <comment xml:lang="sv">okänd</comment>
+ <comment xml:lang="uk">невідомо</comment>
+ <comment xml:lang="vi">không rõ</comment>
+ <comment xml:lang="zh_CN">未知</comment>
+ <comment xml:lang="zh_TW">ä¸æ˜Ž</comment>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/bineditor/BinEditor.pluginspec b/src/plugins/bineditor/BinEditor.pluginspec
new file mode 100644
index 0000000000..9e09f93eec
--- /dev/null
+++ b/src/plugins/bineditor/BinEditor.pluginspec
@@ -0,0 +1,11 @@
+<plugin name="BinEditor" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Binary editor component.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="TextEditor" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/bineditor/bineditor.cpp b/src/plugins/bineditor/bineditor.cpp
new file mode 100644
index 0000000000..4ca6e18707
--- /dev/null
+++ b/src/plugins/bineditor/bineditor.cpp
@@ -0,0 +1,871 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "bineditor.h"
+
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorconstants.h>
+
+#include <QtGui/QScrollBar>
+#include <QtGui/QFontMetrics>
+#include <QtGui/QPainter>
+#include <QtGui/QScrollBar>
+#include <QtGui/QWheelEvent>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtCore/QDebug>
+
+using namespace BINEditor;
+
+static QByteArray calculateHexPattern(const QByteArray &pattern)
+{
+ QByteArray result;
+ if (pattern.size() % 2 == 0) {
+ bool ok = true;
+ int i = 0;
+ while (i < pattern.size()) {
+ ushort s = pattern.mid(i, 2).toUShort(&ok, 16);
+ if (!ok) {
+ return QByteArray();
+ }
+ result.append(s);
+ i += 2;
+ }
+ }
+ return result;
+}
+
+BinEditor::BinEditor(QWidget *parent)
+ : QAbstractScrollArea(parent)
+{
+ m_ieditor = 0;
+ init();
+ m_unmodifiedState = 0;
+ m_hexCursor = true;
+ m_cursorPosition = 0;
+ m_anchorPosition = 0;
+ m_lowNibble = false;
+ m_cursorVisible = false;
+ setFocusPolicy(Qt::WheelFocus);
+ m_addressString = QString(9, QLatin1Char(':'));
+}
+
+BinEditor::~BinEditor()
+{
+}
+
+void BinEditor::init()
+{
+ QFontMetrics fm(fontMetrics());
+ m_margin = 4;
+ m_descent = fm.descent();
+ m_ascent = fm.ascent();
+ m_lineHeight = fm.lineSpacing();
+ m_charWidth = fm.width(QChar(QLatin1Char('M')));
+ m_columnWidth = 2 * m_charWidth + fm.width(QChar(QLatin1Char(' ')));
+ m_numLines = m_data.size() / 16 + 1;
+ m_numVisibleLines = viewport()->height() / m_lineHeight;
+ m_textWidth = 16 * m_charWidth + m_charWidth;
+ int m_numberWidth = fm.width(QChar(QLatin1Char('9')));
+ m_labelWidth = 8 * m_numberWidth + 2 * m_charWidth;
+
+ int expectedCharWidth = m_columnWidth / 3;
+ const char *hex = "0123456789abcdef";
+ m_isMonospacedFont = true;
+ while (*hex) {
+ if (fm.width(QLatin1Char(*hex)) != expectedCharWidth) {
+ m_isMonospacedFont = false;
+ break;
+ }
+ ++hex;
+ }
+
+ horizontalScrollBar()->setRange(0, 2 * m_margin + 16 * m_columnWidth
+ + m_labelWidth + m_textWidth - viewport()->width());
+ horizontalScrollBar()->setPageStep(viewport()->width());
+ verticalScrollBar()->setRange(0, m_numLines - m_numVisibleLines);
+ verticalScrollBar()->setPageStep(m_numVisibleLines);
+}
+
+
+void BinEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ setFont(fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_TEXT)).font());
+}
+
+void BinEditor::setBlinkingCursorEnabled(bool enable)
+{
+ if (enable && QApplication::cursorFlashTime() > 0)
+ m_cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, this);
+ else
+ m_cursorBlinkTimer.stop();
+ m_cursorVisible = enable;
+ updateLines();
+}
+
+void BinEditor::focusInEvent(QFocusEvent *)
+{
+ setBlinkingCursorEnabled(true);
+}
+
+void BinEditor::focusOutEvent(QFocusEvent *)
+{
+ setBlinkingCursorEnabled(false);
+}
+
+void BinEditor::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == m_autoScrollTimer.timerId()) {
+ QRect visible = viewport()->rect();
+ QPoint pos;
+ const QPoint globalPos = QCursor::pos();
+ pos = viewport()->mapFromGlobal(globalPos);
+ QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ mouseMoveEvent(&ev);
+ int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
+ int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
+ int delta = qMax(deltaX, deltaY);
+ if (delta >= 0) {
+ if (delta < 7)
+ delta = 7;
+ int timeout = 4900 / (delta * delta);
+ m_autoScrollTimer.start(timeout, this);
+
+ if (deltaY > 0)
+ verticalScrollBar()->triggerAction(pos.y() < visible.center().y() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ if (deltaX > 0)
+ horizontalScrollBar()->triggerAction(pos.x() < visible.center().x() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ }
+ } else if (e->timerId() == m_cursorBlinkTimer.timerId()) {
+ m_cursorVisible = !m_cursorVisible;
+ updateLines();
+ }
+ QAbstractScrollArea::timerEvent(e);
+}
+
+
+void BinEditor::setModified(bool modified)
+{
+ int unmodifiedState = modified ? -1 : m_undoStack.size();
+ if (unmodifiedState == m_unmodifiedState)
+ return;
+ m_unmodifiedState = unmodifiedState;
+ emit modificationChanged(m_undoStack.size() != m_unmodifiedState);
+}
+
+bool BinEditor::isModified() const
+{
+ return (m_undoStack.size() != m_unmodifiedState);
+}
+
+void BinEditor::setData(const QByteArray &data)
+{
+ m_data = data;
+ m_unmodifiedState = 0;
+ m_undoStack.clear();
+ m_redoStack.clear();
+ init();
+ emit cursorPositionChanged(m_cursorPosition);
+
+ viewport()->update();
+}
+
+QByteArray BinEditor::data() const
+{
+ return m_data;
+}
+
+void BinEditor::resizeEvent(QResizeEvent *)
+{
+ init();
+}
+
+void BinEditor::scrollContentsBy(int dx, int dy)
+{
+ viewport()->scroll(isRightToLeft() ? -dx : dx, dy * m_lineHeight);
+}
+
+void BinEditor::changeEvent(QEvent *e)
+{
+ QAbstractScrollArea::changeEvent(e);
+ if(e->type() == QEvent::ActivationChange) {
+ if (!isActiveWindow())
+ m_autoScrollTimer.stop();
+ }
+ init();
+ viewport()->update();
+}
+
+
+void BinEditor::wheelEvent(QWheelEvent *e)
+{
+ if (e->modifiers() & Qt::ControlModifier) {
+ const int delta = e->delta();
+ if (delta < 0)
+ zoomOut();
+ else if (delta > 0)
+ zoomIn();
+ return;
+ }
+ QAbstractScrollArea::wheelEvent(e);
+}
+
+
+
+QRect BinEditor::cursorRect() const
+{
+ int topLine = verticalScrollBar()->value();
+ int line = m_cursorPosition / 16;
+ int y = (line - topLine) * m_lineHeight;
+ int xoffset = horizontalScrollBar()->value();
+ int column = m_cursorPosition % 16;
+ int x = m_hexCursor ?
+ (-xoffset + m_margin + m_labelWidth + column * m_columnWidth)
+ : (-xoffset + m_margin + m_labelWidth + 16 * m_columnWidth + m_charWidth + column * m_charWidth);
+ int w = m_hexCursor ? m_columnWidth : m_charWidth;
+ return QRect(x, y, w, m_lineHeight);
+}
+
+int BinEditor::posAt(const QPoint &pos) const
+{
+ int xoffset = horizontalScrollBar()->value();
+ int x = xoffset + pos.x() - m_margin - m_labelWidth;
+ int column = qMin(15, qMax(0,x) / m_columnWidth);
+ int topLine = verticalScrollBar()->value();
+ int line = pos.y() / m_lineHeight;
+
+
+ if (x > 16 * m_columnWidth + m_charWidth/2) {
+ x -= 16 * m_columnWidth + m_charWidth;
+ for (column = 0; column < 15; ++column) {
+ int pos = (topLine + line) * 16 + column;
+ if (pos < 0 || pos >= m_data.size())
+ break;
+ QChar qc(QLatin1Char(m_data.at(pos)));
+ if (!qc.isPrint())
+ qc = 0xB7;
+ x -= fontMetrics().width(qc);
+ if (x <= 0)
+ break;
+ }
+ }
+
+ return (qMin(m_data.size(), qMin(m_numLines, topLine + line) * 16) + column);
+}
+
+bool BinEditor::inTextArea(const QPoint &pos) const
+{
+ int xoffset = horizontalScrollBar()->value();
+ int x = xoffset + pos.x() - m_margin - m_labelWidth;
+ return (x > 16 * m_columnWidth + m_charWidth/2);
+}
+
+
+void BinEditor::updateLines(int fromPosition, int toPosition)
+{
+ if (fromPosition < 0)
+ fromPosition = m_cursorPosition;
+ if (toPosition < 0)
+ toPosition = fromPosition;
+ int topLine = verticalScrollBar()->value();
+ int firstLine = qMin(fromPosition, toPosition) / 16;
+ int lastLine = qMax(fromPosition, toPosition) / 16;
+ int y = (firstLine - topLine) * m_lineHeight;
+ int h = (lastLine - firstLine + 1 ) * m_lineHeight;
+
+ viewport()->update(0, y, viewport()->width(), h);
+}
+
+int BinEditor::find(const QByteArray &pattern, int from, QTextDocument::FindFlags findFlags)
+{
+ if (pattern.isEmpty())
+ return false;
+ bool backwards = (findFlags & QTextDocument::FindBackward);
+ int found = backwards ? m_data.lastIndexOf(pattern, from)
+ : m_data.indexOf(pattern, from);
+ int foundHex = -1;
+ QByteArray hexPattern = calculateHexPattern(pattern);
+ if (!hexPattern.isEmpty()) {
+ foundHex = backwards ? m_data.lastIndexOf(hexPattern, from)
+ : m_data.indexOf(hexPattern, from);
+ }
+
+ int pos = (found >= 0 && (foundHex < 0 || found < foundHex)) ? found : foundHex;
+ if (pos >= 0) {
+ setCursorPosition(pos);
+ setCursorPosition(pos + (found == pos ? pattern.size() : hexPattern.size()), KeepAnchor);
+ }
+
+ return pos;
+}
+
+int BinEditor::findPattern(const QByteArray &data, int from, int offset, int *match)
+{
+ if (m_searchPattern.isEmpty())
+ return -1;
+ int normal = m_searchPattern.isEmpty()? -1 : data.indexOf(m_searchPattern, from - offset);
+ int hex = m_searchPatternHex.isEmpty()? -1 : data.indexOf(m_searchPatternHex, from - offset);
+
+ if (normal >= 0 && (hex < 0 || normal < hex)) {
+ if (match)
+ *match = m_searchPattern.length();
+ return normal + offset;
+ }
+ if (hex >= 0) {
+ if (match)
+ *match = m_searchPatternHex.length();
+ return hex + offset;
+ }
+
+ return -1;
+}
+
+
+void BinEditor::drawItems(QPainter *painter, int x, int y, const QString &itemString)
+{
+ if (m_isMonospacedFont) {
+ painter->drawText(x, y, itemString);
+ } else {
+ for (int i = 0; i < 16; ++i)
+ painter->drawText(x + i*m_columnWidth, y, itemString.mid(i*3, 2));
+ }
+}
+
+QString BinEditor::addressString(uint address)
+{
+ QChar *addressStringData = m_addressString.data();
+ const char *hex = "0123456789abcdef";
+ for (int h = 0; h < 4; ++h) {
+ int shift = 4*(7-h);
+ addressStringData[h] = hex[(address & (0xf<<shift))>>shift];
+ }
+ for (int h = 4; h < 8; ++h) {
+ int shift = 4*(7-h);
+ addressStringData[h+1] = hex[(address & (0xf<<shift))>>shift];
+ }
+ return m_addressString;
+
+}
+
+void BinEditor::paintEvent(QPaintEvent *e)
+{
+ QPainter painter(viewport());
+ int topLine = verticalScrollBar()->value();
+ int xoffset = horizontalScrollBar()->value();
+ painter.drawLine(-xoffset + m_margin + m_labelWidth - m_charWidth/2, 0,
+ -xoffset + m_margin + m_labelWidth - m_charWidth/2, viewport()->height());
+ painter.drawLine(-xoffset + m_margin + m_labelWidth + 16 * m_columnWidth + m_charWidth/2, 0,
+ -xoffset + m_margin + m_labelWidth + 16 * m_columnWidth + m_charWidth/2, viewport()->height());
+
+
+ int viewport_height = viewport()->height();
+ QBrush alternate_base = palette().alternateBase();
+ for (int i = 0; i < 8; ++i) {
+ int bg_x = -xoffset + m_margin + (2 * i + 1) * m_columnWidth + m_labelWidth;
+ QRect r(bg_x - m_charWidth/2, 0, m_columnWidth, viewport_height);
+ painter.fillRect(e->rect() & r, palette().alternateBase());
+ }
+
+ int matchLength = 0;
+
+ QByteArray patternData;
+ int patternOffset = qMax(0, topLine*16 - m_searchPattern.size());
+ if (!m_searchPattern.isEmpty())
+ patternData = m_data.mid(patternOffset, m_numVisibleLines * 16);
+
+ int foundPatternAt = findPattern(patternData, patternOffset, patternOffset, &matchLength);
+
+ int selStart = qMin(m_cursorPosition, m_anchorPosition);
+ int selEnd = qMax(m_cursorPosition, m_anchorPosition);
+
+ QString itemString(QLatin1String("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+ QChar *itemStringData = itemString.data();
+ const char *hex = "0123456789abcdef";
+
+ painter.setPen(palette().text().color());
+ for (int i = 0; i <= m_numVisibleLines; ++i) {
+ int line = topLine + i;
+ if (line >= m_numLines)
+ break;
+
+ int y = i * m_lineHeight + m_ascent;
+ if (y - m_ascent > e->rect().bottom())
+ break;
+ if (y + m_descent < e->rect().top())
+ continue;
+
+
+ painter.drawText(-xoffset, i * m_lineHeight + m_ascent, addressString(((uint) line) * 16));
+ QString printable;
+ int cursor = -1;
+ for (int c = 0; c < 16; ++c) {
+ int pos = line * 16 + c;
+ if (pos >= m_data.size())
+ break;
+ QChar qc(QLatin1Char(m_data.at(pos)));
+ if (qc.unicode() >= 127 || !qc.isPrint())
+ qc = 0xB7;
+ printable += qc;
+ }
+
+ QRect selectionRect;
+ QRect printableSelectionRect;
+
+ bool isFullySelected = (selStart < selEnd && selStart <= line*16 && (line+1)*16 <= selEnd);
+
+ for (int c = 0; c < 16; ++c) {
+ int pos = line * 16 + c;
+ if (pos >= m_data.size()) {
+ while(c < 16) {
+ itemStringData[c*3] = itemStringData[c*3+1] = ' ';
+ ++c;
+ }
+ break;
+ }
+
+ if (foundPatternAt >= 0 && pos >= foundPatternAt + matchLength)
+ foundPatternAt = findPattern(patternData, foundPatternAt + matchLength, patternOffset, &matchLength);
+
+
+ uchar value = (uchar)m_data.at(pos);
+ itemStringData[c*3] = hex[value >> 4];
+ itemStringData[c*3+1] = hex[value & 0xf];
+
+ int item_x = -xoffset + m_margin + c * m_columnWidth + m_labelWidth;
+
+ if (foundPatternAt >= 0 && pos >= foundPatternAt && pos < foundPatternAt + matchLength) {
+ painter.fillRect(item_x, y-m_ascent, m_columnWidth, m_lineHeight, QColor(0xffef0b));
+ int printable_item_x = -xoffset + m_margin + m_labelWidth + 16 * m_columnWidth + m_charWidth
+ + painter.fontMetrics().width( printable.left(c));
+ painter.fillRect(printable_item_x, y-m_ascent,
+ painter.fontMetrics().width(printable.at(c)),
+ m_lineHeight, QColor(0xffef0b));
+ }
+
+ if (selStart < selEnd && !isFullySelected && pos >= selStart && pos < selEnd) {
+ selectionRect |= QRect(item_x, y-m_ascent, m_columnWidth, m_lineHeight);
+ int printable_item_x = -xoffset + m_margin + m_labelWidth + 16 * m_columnWidth + m_charWidth
+ + painter.fontMetrics().width( printable.left(c));
+ printableSelectionRect |= QRect(printable_item_x, y-m_ascent,
+ painter.fontMetrics().width(printable.at(c)),
+ m_lineHeight);
+ }
+
+ if (pos == m_cursorPosition)
+ cursor = c;
+
+ }
+
+ int x = -xoffset + m_margin + m_labelWidth;
+
+ if (isFullySelected) {
+ painter.save();
+ painter.fillRect(x, y-m_ascent, 16*m_columnWidth, m_lineHeight, palette().highlight());
+ painter.setPen(palette().highlightedText().color());
+ drawItems(&painter, x, y, itemString);
+ painter.restore();
+ } else {
+ drawItems(&painter, x, y, itemString);
+ if (!selectionRect.isEmpty()) {
+ painter.save();
+ painter.fillRect(selectionRect, palette().highlight());
+ painter.setPen(palette().highlightedText().color());
+ painter.setClipRect(selectionRect);
+ drawItems(&painter, x, y, itemString);
+ painter.restore();
+ }
+ }
+
+
+ if (cursor >= 0) {
+ int w = painter.fontMetrics().boundingRect(itemString.mid(cursor*3, 2)).width();
+ QRect cursorRect(x + cursor * m_columnWidth, y - m_ascent, w + 1, m_lineHeight);
+ painter.save();
+ painter.setPen(Qt::red);
+ painter.drawRect(cursorRect.adjusted(0, 0, 0, -1));
+ painter.restore();
+ if (m_hexCursor && m_cursorVisible) {
+ if (m_lowNibble)
+ cursorRect.adjust(painter.fontMetrics().width(itemString.left(1)), 0, 0, 0);
+ painter.fillRect(cursorRect, Qt::red);
+ painter.save();
+ painter.setClipRect(cursorRect);
+ painter.setPen(Qt::white);
+ drawItems(&painter, x, y, itemString);
+ painter.restore();
+ }
+ }
+
+ int text_x = -xoffset + m_margin + m_labelWidth + 16 * m_columnWidth + m_charWidth;
+
+ if (isFullySelected) {
+ painter.save();
+ painter.fillRect(text_x, y-m_ascent, painter.fontMetrics().width(printable), m_lineHeight,
+ palette().highlight());
+ painter.setPen(palette().highlightedText().color());
+ painter.drawText(text_x, y, printable);
+ painter.restore();
+ }else {
+ painter.drawText(text_x, y, printable);
+ if (!printableSelectionRect.isEmpty()) {
+ painter.save();
+ painter.fillRect(printableSelectionRect, palette().highlight());
+ painter.setPen(palette().highlightedText().color());
+ painter.setClipRect(printableSelectionRect);
+ painter.drawText(text_x, y, printable);
+ painter.restore();
+ }
+ }
+
+ if (cursor >= 0) {
+ QRect cursorRect(text_x + painter.fontMetrics().width(printable.left(cursor)),
+ y-m_ascent,
+ painter.fontMetrics().width(printable.at(cursor)),
+ m_lineHeight);
+ painter.save();
+ if (m_hexCursor || !m_cursorVisible) {
+ painter.setPen(Qt::red);
+ painter.drawRect(cursorRect.adjusted(0, 0, 0, -1));
+ } else {
+ painter.setClipRect(cursorRect);
+ painter.fillRect(cursorRect, Qt::red);
+ painter.setPen(Qt::white);
+ painter.drawText(text_x, y, printable);
+ }
+ painter.restore();
+ }
+ }
+}
+
+
+int BinEditor::cursorPosition() const
+{
+ return m_cursorPosition;
+}
+
+void BinEditor::setCursorPosition(int pos, MoveMode moveMode)
+{
+ pos = qMin(m_data.size()-1, qMax(0, pos));
+ if (pos == m_cursorPosition
+ && (m_anchorPosition == m_cursorPosition || moveMode == KeepAnchor)
+ && !m_lowNibble)
+ return;
+
+ int oldCursorPosition = m_cursorPosition;
+
+ bool hasSelection = m_anchorPosition != m_cursorPosition;
+ m_lowNibble = false;
+ if (!hasSelection)
+ updateLines();
+ m_cursorPosition = pos;
+ if (moveMode == MoveAnchor) {
+ if (hasSelection)
+ updateLines(m_anchorPosition, oldCursorPosition);
+ m_anchorPosition = m_cursorPosition;
+ }
+
+ hasSelection = m_anchorPosition != m_cursorPosition;
+ updateLines(hasSelection ? oldCursorPosition : m_cursorPosition, m_cursorPosition);
+ ensureCursorVisible();
+ if (hasSelection != (m_anchorPosition != m_anchorPosition))
+ emit copyAvailable(m_anchorPosition != m_cursorPosition);
+ emit cursorPositionChanged(m_cursorPosition);
+}
+
+
+void BinEditor::ensureCursorVisible()
+{
+ QRect cr = cursorRect();
+ QRect vr = viewport()->rect();
+ if (!vr.contains(cr)) {
+ if (cr.top() < vr.top())
+ verticalScrollBar()->setValue(m_cursorPosition / 16);
+ else if (cr.bottom() > vr.bottom())
+ verticalScrollBar()->setValue(m_cursorPosition / 16 - m_numVisibleLines + 1);
+ }
+}
+
+void BinEditor::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() != Qt::LeftButton)
+ return;
+ setCursorPosition(posAt(e->pos()));
+ setBlinkingCursorEnabled(true);
+ if (m_hexCursor == inTextArea(e->pos())) {
+ m_hexCursor = !m_hexCursor;
+ updateLines();
+ }
+}
+
+void BinEditor::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!(e->buttons() & Qt::LeftButton))
+ return;
+ setCursorPosition(posAt(e->pos()), KeepAnchor);
+ if (m_hexCursor == inTextArea(e->pos())) {
+ m_hexCursor = !m_hexCursor;
+ updateLines();
+ }
+ QRect visible = viewport()->rect();
+ if (visible.contains(e->pos()))
+ m_autoScrollTimer.stop();
+ else if (!m_autoScrollTimer.isActive())
+ m_autoScrollTimer.start(100, this);
+}
+
+void BinEditor::mouseReleaseEvent(QMouseEvent *)
+{
+ if (m_autoScrollTimer.isActive()) {
+ m_autoScrollTimer.stop();
+ ensureCursorVisible();
+ }
+}
+
+void BinEditor::selectAll()
+{
+ setCursorPosition(0);
+ setCursorPosition(m_data.size()-1, KeepAnchor);
+}
+
+void BinEditor::clear()
+{
+ setData(QByteArray());
+}
+
+bool BinEditor::event(QEvent *e) {
+ if (e->type() == QEvent::KeyPress) {
+ switch (static_cast<QKeyEvent*>(e)->key()) {
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ m_hexCursor = !m_hexCursor;
+ setBlinkingCursorEnabled(true);
+ ensureCursorVisible();
+ e->accept();
+ return true;
+ default:;
+ }
+ }
+ return QAbstractScrollArea::event(e);
+}
+
+void BinEditor::keyPressEvent(QKeyEvent *e)
+{
+
+ if (e == QKeySequence::SelectAll) {
+ e->accept();
+ selectAll();
+ return;
+ } else if (e == QKeySequence::Copy) {
+ e->accept();
+ copy();
+ return;
+ } else if (e == QKeySequence::Undo) {
+ e->accept();
+ undo();
+ return;
+ } else if (e == QKeySequence::Redo) {
+ e->accept();
+ redo();
+ return;
+ }
+
+
+ MoveMode moveMode = e->modifiers() & Qt::ShiftModifier ? KeepAnchor : MoveAnchor;
+ switch (e->key()) {
+ case Qt::Key_Up:
+ setCursorPosition(m_cursorPosition - 16, moveMode);
+ break;
+ case Qt::Key_Down:
+ setCursorPosition(m_cursorPosition + 16, moveMode);
+ break;
+ case Qt::Key_Right:
+ setCursorPosition(m_cursorPosition + 1, moveMode);
+ break;
+ case Qt::Key_Left:
+ setCursorPosition(m_cursorPosition - 1, moveMode);
+ break;
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown: {
+ int line = qMax(0, m_cursorPosition / 16 - verticalScrollBar()->value());
+ verticalScrollBar()->triggerAction(e->key() == Qt::Key_PageUp ?
+ QScrollBar::SliderPageStepSub : QScrollBar::SliderPageStepAdd);
+ setCursorPosition((verticalScrollBar()->value() + line) * 16 + m_cursorPosition % 16, moveMode);
+ } break;
+
+ case Qt::Key_Home:
+ setCursorPosition((e->modifiers() & Qt::ControlModifier) ?
+ 0 : (m_cursorPosition/16 * 16), moveMode);
+ break;
+ case Qt::Key_End:
+ setCursorPosition((e->modifiers() & Qt::ControlModifier) ?
+ (m_data.size()-1) : (m_cursorPosition/16 * 16 + 15), moveMode);
+ break;
+
+ default: {
+ QString text = e->text();
+ for (int i = 0; i < text.length(); ++i) {
+ QChar c = text.at(i);
+ if (m_hexCursor) {
+ c = c.toLower();
+ int nibble = -1;
+ if (c.unicode() >= 'a' && c.unicode() <= 'f')
+ nibble = c.unicode() - 'a' + 10;
+ else if (c.unicode() >= '0' && c.unicode() <= '9')
+ nibble = c.unicode() - '0';
+ if (nibble < 0)
+ continue;
+ if (m_lowNibble) {
+ changeData(m_cursorPosition, nibble + (m_data[m_cursorPosition] & 0xf0));
+ m_lowNibble = false;
+ setCursorPosition(m_cursorPosition + 1);
+ } else {
+ changeData(m_cursorPosition, (nibble << 4) + (m_data[m_cursorPosition] & 0x0f), true);
+ m_lowNibble = true;
+ updateLines();
+ }
+ } else {
+ if (c.unicode() >= 128 || !c.isPrint())
+ continue;
+ changeData(m_cursorPosition, c.unicode(), m_cursorPosition + 1);
+ setCursorPosition(m_cursorPosition + 1);
+ }
+ setBlinkingCursorEnabled(true);
+ }
+ }
+ }
+
+ e->accept();
+}
+
+void BinEditor::zoomIn(int range)
+{
+ QFont f = font();
+ const int newSize = f.pointSize() + range;
+ if (newSize <= 0)
+ return;
+ f.setPointSize(newSize);
+ setFont(f);
+}
+
+void BinEditor::zoomOut(int range)
+{
+ zoomIn(-range);
+}
+
+void BinEditor::copy()
+{
+ int selStart = qMin(m_cursorPosition, m_anchorPosition);
+ int selEnd = qMax(m_cursorPosition, m_anchorPosition);
+ if (selStart < selEnd)
+ QApplication::clipboard()->setText(QString::fromLatin1(m_data.mid(selStart, selEnd - selStart)));
+}
+
+void BinEditor::highlightSearchResults(const QByteArray &pattern, QTextDocument::FindFlags /*findFlags*/)
+{
+ if (m_searchPattern == pattern)
+ return;
+ m_searchPattern = pattern;
+ m_searchPatternHex = calculateHexPattern(pattern);
+ viewport()->update();
+}
+
+
+void BinEditor::changeData(int position, uchar character, bool highNibble)
+{
+ m_redoStack.clear();
+ if (m_unmodifiedState > m_undoStack.size())
+ m_unmodifiedState = -1;
+ BinEditorEditCommand cmd;
+ cmd.position = position;
+ cmd.character = (uchar) m_data[position];
+ cmd.highNibble = highNibble;
+
+ if (!highNibble && !m_undoStack.isEmpty() && m_undoStack.top().position == position && m_undoStack.top().highNibble) {
+ // compress
+ cmd.character = m_undoStack.top().character;
+ m_undoStack.pop();
+ }
+
+ m_data[position] = (char) character;
+ bool emitModificationChanged = (m_undoStack.size() == m_unmodifiedState);
+ m_undoStack.push(cmd);
+ if (emitModificationChanged) {
+ emit modificationChanged(m_undoStack.size() != m_unmodifiedState);
+ }
+
+ if (m_undoStack.size() == 1)
+ emit undoAvailable(true);
+}
+
+
+void BinEditor::undo()
+{
+ if (m_undoStack.isEmpty())
+ return;
+ bool emitModificationChanged = (m_undoStack.size() == m_unmodifiedState);
+ BinEditorEditCommand cmd = m_undoStack.pop();
+ emitModificationChanged |= (m_undoStack.size() == m_unmodifiedState);
+ uchar c = m_data[cmd.position];
+ m_data[cmd.position] = (char)cmd.character;
+ cmd.character = c;
+ m_redoStack.push(cmd);
+ setCursorPosition(cmd.position);
+ if (emitModificationChanged)
+ emit modificationChanged(m_undoStack.size() != m_unmodifiedState);
+ if (!m_undoStack.size())
+ emit undoAvailable(false);
+ if (m_redoStack.size() == 1)
+ emit redoAvailable(true);
+}
+
+void BinEditor::redo()
+{
+ if (m_redoStack.isEmpty())
+ return;
+ BinEditorEditCommand cmd = m_redoStack.pop();
+ uchar c = m_data[cmd.position];
+ m_data[cmd.position] = (char)cmd.character;
+ cmd.character = c;
+ bool emitModificationChanged = (m_undoStack.size() == m_unmodifiedState);
+ m_undoStack.push(cmd);
+ setCursorPosition(cmd.position + 1);
+ if (emitModificationChanged)
+ emit modificationChanged(m_undoStack.size() != m_unmodifiedState);
+ if (m_undoStack.size() == 1)
+ emit undoAvailable(true);
+ if (!m_redoStack.size())
+ emit redoAvailable(false);
+}
diff --git a/src/plugins/bineditor/bineditor.h b/src/plugins/bineditor/bineditor.h
new file mode 100644
index 0000000000..2eae59af1a
--- /dev/null
+++ b/src/plugins/bineditor/bineditor.h
@@ -0,0 +1,181 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BINEDITOR_H
+#define BINEDITOR_H
+
+#include <QtGui/qabstractscrollarea.h>
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qstack.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextformat.h>
+
+namespace Core {
+class IEditor;
+}
+
+namespace TextEditor {
+class FontSettings;
+}
+
+namespace BINEditor {
+
+class BinEditor : public QAbstractScrollArea
+{
+ Q_OBJECT
+ Q_PROPERTY(bool modified READ isModified WRITE setModified DESIGNABLE false)
+public:
+
+ BinEditor(QWidget *parent = 0);
+ ~BinEditor();
+
+ void setData(const QByteArray &data);
+ QByteArray data() const;
+
+ void zoomIn(int range = 1);
+ void zoomOut(int range = 1);
+
+ enum MoveMode {
+ MoveAnchor,
+ KeepAnchor
+ };
+
+ int cursorPosition() const;
+ void setCursorPosition(int pos, MoveMode moveMode = MoveAnchor);
+
+ void setModified(bool);
+ bool isModified() const;
+
+ int find(const QByteArray &pattern, int from = 0, QTextDocument::FindFlags findFlags = 0);
+
+ void selectAll();
+ void clear();
+
+ void undo();
+ void redo();
+
+ Core::IEditor *editorInterface() const { return m_ieditor; }
+ void setEditorInterface(Core::IEditor *ieditor) { m_ieditor = ieditor; }
+
+ bool hasSelection() const { return m_cursorPosition != m_anchorPosition; }
+ int selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); }
+ int selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); }
+
+ bool event(QEvent*);
+
+ bool isUndoAvailable() const { return m_undoStack.size(); }
+ bool isRedoAvailable() const { return m_redoStack.size(); }
+
+ QString addressString(uint address);
+
+
+public Q_SLOTS:
+ void setFontSettings(const TextEditor::FontSettings &fs);
+ void highlightSearchResults(const QByteArray &pattern, QTextDocument::FindFlags findFlags = 0);
+ void copy();
+
+Q_SIGNALS:
+ void modificationChanged(bool modified);
+ void undoAvailable(bool);
+ void redoAvailable(bool);
+ void copyAvailable(bool);
+ void cursorPositionChanged(int position);
+
+protected:
+ void scrollContentsBy(int dx, int dy);
+ void paintEvent(QPaintEvent *e);
+ void resizeEvent(QResizeEvent *);
+ void changeEvent(QEvent *);
+ void wheelEvent(QWheelEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void focusInEvent(QFocusEvent *);
+ void focusOutEvent(QFocusEvent *);
+ void timerEvent(QTimerEvent *);
+
+private:
+ QByteArray m_data;
+ int m_unmodifiedState;
+ int m_margin;
+ int m_descent;
+ int m_ascent;
+ int m_lineHeight;
+ int m_charWidth;
+ int m_labelWidth;
+ int m_textWidth;
+ int m_columnWidth;
+ int m_numLines;
+ int m_numVisibleLines;
+
+
+ bool m_cursorVisible;
+ int m_cursorPosition;
+ int m_anchorPosition;
+ bool m_hexCursor;
+ bool m_lowNibble;
+ bool m_isMonospacedFont;
+
+ QByteArray m_searchPattern;
+ QByteArray m_searchPatternHex;
+
+ QBasicTimer m_cursorBlinkTimer;
+
+ void init();
+ int posAt(const QPoint &pos) const;
+ bool inTextArea(const QPoint &pos) const;
+ QRect cursorRect() const;
+ void updateLines(int fromPosition = -1, int toPosition = -1);
+ void ensureCursorVisible();
+ void setBlinkingCursorEnabled(bool enable);
+
+ void changeData(int position, uchar character, bool highNibble = false);
+
+ int findPattern(const QByteArray &data, int from, int offset, int *match);
+ void drawItems(QPainter *painter, int x, int y, const QString &itemString);
+
+ struct BinEditorEditCommand {
+ int position;
+ uchar character;
+ bool highNibble;
+ };
+ QStack<BinEditorEditCommand> m_undoStack, m_redoStack;
+
+ QBasicTimer m_autoScrollTimer;
+ Core::IEditor *m_ieditor;
+ QString m_addressString;
+};
+
+} // namespace BINEditor
+
+#endif // BINEDITOR_H
diff --git a/src/plugins/bineditor/bineditor.pro b/src/plugins/bineditor/bineditor.pro
new file mode 100644
index 0000000000..08a67fdf05
--- /dev/null
+++ b/src/plugins/bineditor/bineditor.pro
@@ -0,0 +1,13 @@
+TEMPLATE = lib
+TARGET = BinEditor
+
+include(bineditor_dependencies.pri)
+
+HEADERS += bineditorplugin.h \
+ bineditor.h \
+ bineditorconstants.h
+
+SOURCES += bineditorplugin.cpp \
+ bineditor.cpp
+
+RESOURCES += bineditor.qrc
diff --git a/src/plugins/bineditor/bineditor.qrc b/src/plugins/bineditor/bineditor.qrc
new file mode 100644
index 0000000000..c7215495db
--- /dev/null
+++ b/src/plugins/bineditor/bineditor.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/bineditor" >
+ <file>BinEditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/bineditor/bineditor_dependencies.pri b/src/plugins/bineditor/bineditor_dependencies.pri
new file mode 100644
index 0000000000..30120bd3f5
--- /dev/null
+++ b/src/plugins/bineditor/bineditor_dependencies.pri
@@ -0,0 +1,4 @@
+include(../../qworkbenchplugin.pri)
+include(../../libs/utils/utils.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/bineditor/bineditorconstants.h b/src/plugins/bineditor/bineditorconstants.h
new file mode 100644
index 0000000000..f67d6c522d
--- /dev/null
+++ b/src/plugins/bineditor/bineditorconstants.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BINEDITORCONSTANTS_H
+#define BINEDITORCONSTANTS_H
+
+namespace BINEditor {
+ namespace Constants {
+ const char * const C_BINEDITOR = "Binary Editor";
+ const char * const C_BINEDITOR_MIMETYPE = "application/octet-stream";
+ }
+}
+
+#endif // BINEDITORCONSTANTS_H
diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp
new file mode 100644
index 0000000000..ee223f3dea
--- /dev/null
+++ b/src/plugins/bineditor/bineditorplugin.cpp
@@ -0,0 +1,503 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "bineditorplugin.h"
+#include "bineditor.h"
+#include "bineditorconstants.h"
+
+#include <QtCore/QFileInfo>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QMainWindow>
+#include <QtGui/QHBoxLayout>
+#include <QtCore/QFile>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/fontsettings.h>
+#include <find/ifindsupport.h>
+#include <utils/linecolumnlabel.h>
+#include <utils/reloadpromptutils.h>
+
+using namespace BINEditor;
+using namespace BINEditor::Internal;
+
+
+class BinEditorFind : public Find::IFindSupport
+{
+ Q_OBJECT
+public:
+ BinEditorFind(BinEditor *editor) { m_editor = editor; m_incrementalStartPos = -1; }
+ ~BinEditorFind() {}
+
+ bool supportsReplace() const { return false; }
+ void resetIncrementalSearch() { m_incrementalStartPos = -1; }
+ void clearResults() { m_editor->highlightSearchResults(QByteArray()); }
+ QString currentFindString() const { return QString(); }
+ QString completedFindString() const { return QString(); }
+
+
+ int find(const QByteArray &pattern, int pos, QTextDocument::FindFlags findFlags) {
+ if (pattern.isEmpty()) {
+ m_editor->setCursorPosition(pos);
+ return pos;
+ }
+
+ int found = m_editor->find(pattern, pos, findFlags);
+ if (found < 0)
+ found = m_editor->find(pattern,
+ (findFlags & QTextDocument::FindBackward)?m_editor->data().size()-1:0,
+ findFlags);
+ return found;
+ }
+
+ bool findIncremental(const QString &txt, QTextDocument::FindFlags findFlags) {
+ QByteArray pattern = txt.toLatin1();
+ if (m_incrementalStartPos < 0)
+ m_incrementalStartPos = m_editor->selectionStart();
+ int pos = m_incrementalStartPos;
+ findFlags &= ~QTextDocument::FindBackward;
+ int found = find(pattern, pos, findFlags);
+ if (found >= 0)
+ m_editor->highlightSearchResults(pattern, findFlags);
+ else
+ m_editor->highlightSearchResults(QByteArray(), 0);
+ return found >= 0;
+ }
+
+ bool findStep(const QString &txt, QTextDocument::FindFlags findFlags) {
+ QByteArray pattern = txt.toLatin1();
+ bool wasReset = (m_incrementalStartPos < 0);
+ int pos = m_editor->cursorPosition();
+ if (findFlags & QTextDocument::FindBackward)
+ pos = m_editor->selectionStart()-1;
+ int found = find(pattern, pos, findFlags);
+ if (found)
+ m_incrementalStartPos = found;
+ if (wasReset && found >= 0)
+ m_editor->highlightSearchResults(pattern, findFlags);
+ return found >= 0;
+ }
+ bool replaceStep(const QString &, const QString &,
+ QTextDocument::FindFlags) { return false;}
+ int replaceAll(const QString &, const QString &,
+ QTextDocument::FindFlags) { return 0; }
+
+private:
+ BinEditor *m_editor;
+ int m_incrementalStartPos;
+};
+
+
+class BinEditorFile : public Core::IFile
+{
+ Q_OBJECT
+public:
+ BinEditorFile(BinEditor *parent) :
+ Core::IFile(parent),
+ m_mimeType(QLatin1String(BINEditor::Constants::C_BINEDITOR_MIMETYPE))
+ {
+ m_editor = parent;
+ }
+ ~BinEditorFile() {}
+
+ virtual QString mimeType() const { return m_mimeType; }
+
+ bool save(const QString &fileName = QString()) {
+ QFile file(fileName);
+ if (file.open(QIODevice::WriteOnly)) {
+ file.write(m_editor->data());
+ file.close();
+ m_editor->setModified(false);
+ m_editor->editorInterface()->setDisplayName(QFileInfo(fileName).fileName());
+ m_fileName = fileName;
+ emit changed();
+ return true;
+ }
+ return false;
+ }
+
+ bool open(const QString &fileName) {
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ m_fileName = fileName;
+ m_editor->setData(file.readAll());
+ m_editor->editorInterface()->setDisplayName(QFileInfo(fileName).fileName());
+ file.close();
+ return true;
+ }
+ return false;
+ }
+
+
+ void setFilename(const QString &filename) {
+ m_fileName = filename;
+ }
+
+ QString fileName() const {
+ return m_fileName;
+ }
+
+ QString defaultPath() const { return QString(); }
+ QString suggestedFileName() const { return QString(); }
+ QString fileFilter() const { return QString(); }
+ QString fileExtension() const { return QString(); }
+
+ bool isModified() const {
+ return m_editor->isModified();
+ }
+ bool isReadOnly() const {
+ const QFileInfo fi(m_fileName);
+ return !fi.isWritable();
+ }
+
+ bool isSaveAsAllowed() const { return true; }
+
+ void modified(ReloadBehavior *behavior) {
+ const QString fileName = m_fileName;
+
+ switch (*behavior) {
+ case Core::IFile::ReloadNone:
+ return;
+ case Core::IFile::ReloadAll:
+ open(fileName);
+ return;
+ case Core::IFile::ReloadPermissions:
+ emit changed();
+ return;
+ case Core::IFile::AskForReload:
+ break;
+ }
+
+ switch (Core::Utils::reloadPrompt(fileName, BinEditorPlugin::core()->mainWindow())) {
+ case Core::Utils::ReloadCurrent:
+ open(fileName);
+ break;
+ case Core::Utils::ReloadAll:
+ open(fileName);
+ *behavior = Core::IFile::ReloadAll;
+ break;
+ case Core::Utils::ReloadSkipCurrent:
+ break;
+ case Core::Utils::ReloadNone:
+ *behavior = Core::IFile::ReloadNone;
+ break;
+ }
+ }
+
+private:
+ const QString m_mimeType;
+ BinEditor *m_editor;
+ QString m_fileName;
+};
+
+class BinEditorInterface : public Core::IEditor
+{
+ Q_OBJECT
+public:
+ BinEditorInterface(BinEditor *parent ) : Core::IEditor(parent) {
+ m_editor = parent;
+ m_file = new BinEditorFile(parent);
+ m_context << BinEditorPlugin::core()->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::K_DEFAULT_BINARY_EDITOR);
+ m_context << BinEditorPlugin::core()->uniqueIDManager()->uniqueIdentifier(Constants::C_BINEDITOR);
+ m_cursorPositionLabel = new Core::Utils::LineColumnLabel;
+
+ QHBoxLayout *l = new QHBoxLayout;
+ QWidget *w = new QWidget;
+ l->setMargin(0);
+ l->setContentsMargins(0, 0, 5, 0);
+ l->addStretch(1);
+ l->addWidget(m_cursorPositionLabel);
+ w->setLayout(l);
+
+ m_toolBar = new QToolBar;
+ m_toolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_toolBar->addWidget(w);
+
+ connect(m_editor, SIGNAL(cursorPositionChanged(int)), this, SLOT(updateCursorPosition(int)));
+ }
+ ~BinEditorInterface() {}
+
+ QWidget *widget() { return m_editor; }
+
+ QList<int> context() const { return m_context; }
+
+ bool createNew(const QString & /* contents */ = QString()) {
+ m_editor->setData(QByteArray());
+ m_file->setFilename(QString());
+ return true;
+ }
+ bool open(const QString &fileName = QString()) {
+ return m_file->open(fileName);
+ }
+ Core::IFile *file() { return m_file; }
+ const char *kind() const { return Core::Constants::K_DEFAULT_BINARY_EDITOR; }
+ QString displayName() const { return m_displayName; }
+ void setDisplayName(const QString &title) { m_displayName = title; emit changed(); }
+
+ bool duplicateSupported() const { return false; }
+ IEditor *duplicate(QWidget */*parent*/) { return 0; }
+
+ QByteArray saveState() const { return QByteArray();} // TODO
+ bool restoreState(const QByteArray &/*state*/) {return false;} // TODO
+
+ QToolBar *toolBar() { return m_toolBar; }
+
+signals:
+ void changed();
+
+public slots:
+ void updateCursorPosition(int position) {
+ m_cursorPositionLabel->setText(m_editor->addressString((uint)position),
+ m_editor->addressString((uint)m_editor->data().size()));
+ }
+
+private:
+ BinEditor *m_editor;
+ QString m_displayName;
+ BinEditorFile *m_file;
+ QList<int> m_context;
+ QToolBar *m_toolBar;
+ Core::Utils::LineColumnLabel *m_cursorPositionLabel;
+};
+
+
+
+
+///////////////////////////////// BinEditorFactory //////////////////////////////////
+
+BinEditorFactory::BinEditorFactory(BinEditorPlugin *owner) :
+ m_kind(QLatin1String(Core::Constants::K_DEFAULT_BINARY_EDITOR)),
+ m_mimeTypes(QLatin1String(BINEditor::Constants::C_BINEDITOR_MIMETYPE)),
+ m_owner(owner)
+{
+}
+
+QString BinEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *BinEditorFactory::open(const QString &fileName)
+{
+ Core::IEditor *iface = m_owner->m_core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *BinEditorFactory::createEditor(QWidget *parent)
+{
+ BinEditor *editor = new BinEditor(parent);
+ m_owner->initializeEditor(editor);
+ return editor->editorInterface();
+}
+
+QStringList BinEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
+
+///////////////////////////////// BinEditorPlugin //////////////////////////////////
+
+BinEditorPlugin *BinEditorPlugin::m_instance = 0;
+
+BinEditorPlugin::BinEditorPlugin() :
+ m_core(0)
+{
+ m_undoAction = m_redoAction = m_copyAction = m_selectAllAction = 0;
+ m_instance = this;
+}
+
+BinEditorPlugin::~BinEditorPlugin()
+{
+ m_instance = 0;
+}
+
+BinEditorPlugin *BinEditorPlugin::instance()
+{
+ return m_instance;
+}
+
+Core::ICore *BinEditorPlugin::core()
+{
+ return m_instance->m_core;
+}
+
+QAction *BinEditorPlugin::registerNewAction(const QString &id, const QString &title)
+{
+
+ QAction *result = new QAction(title, this);
+ m_core->actionManager()->registerAction(result, id, m_context);
+ return result;
+}
+
+QAction *BinEditorPlugin::registerNewAction(const QString &id,
+ QObject *receiver,
+ const char *slot,
+ const QString &title)
+{
+ QAction *rc = registerNewAction(id, title);
+ if (!rc)
+ return 0;
+
+ connect(rc, SIGNAL(triggered()), receiver, slot);
+ return rc;
+}
+
+void BinEditorPlugin::initializeEditor(BinEditor *editor)
+{
+ BinEditorInterface *editorInterface = new BinEditorInterface(editor);
+ QObject::connect(editor, SIGNAL(modificationChanged(bool)), editorInterface, SIGNAL(changed()));
+ editor->setEditorInterface(editorInterface);
+
+ m_context << BinEditorPlugin::core()->uniqueIDManager()->uniqueIdentifier(Constants::C_BINEDITOR);
+ if (!m_undoAction) {
+ m_undoAction = registerNewAction(QLatin1String(Core::Constants::UNDO),
+ this, SLOT(undoAction()),
+ tr("&Undo"));
+ m_redoAction = registerNewAction(QLatin1String(Core::Constants::REDO),
+ this, SLOT(redoAction()),
+ tr("&Redo"));
+ m_copyAction = registerNewAction(QLatin1String(Core::Constants::COPY),
+ this, SLOT(copyAction()));
+ m_selectAllAction = registerNewAction(QLatin1String(Core::Constants::SELECTALL),
+ this, SLOT(selectAllAction()));
+ }
+
+ // Font settings
+ TextEditor::TextEditorSettings *settings = TextEditor::TextEditorSettings::instance();
+ editor->setFontSettings(settings->fontSettings());
+ connect(settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
+ editor, SLOT(setFontSettings(TextEditor::FontSettings)));
+
+ QObject::connect(editor, SIGNAL(undoAvailable(bool)), this, SLOT(updateActions()));
+ QObject::connect(editor, SIGNAL(redoAvailable(bool)), this, SLOT(updateActions()));
+ QObject::connect(editor, SIGNAL(copyAvailable(bool)), this, SLOT(updateActions()));
+
+ Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
+ BinEditorFind *binEditorFind = new BinEditorFind(editor);
+ aggregate->add(binEditorFind);
+ aggregate->add(editor);
+}
+
+bool BinEditorPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!m_core->mimeDatabase()->addMimeTypes(QLatin1String(":/bineditor/BinEditor.mimetypes.xml"), errorMessage))
+ return false;
+
+ connect(m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
+ this, SLOT(updateCurrentEditor(Core::IContext *)));
+
+ addAutoReleasedObject(new BinEditorFactory(this));
+
+ return true;
+}
+
+void BinEditorPlugin::extensionsInitialized()
+{
+}
+
+void BinEditorPlugin::updateCurrentEditor(Core::IContext *object)
+{
+ do {
+ if (!object) {
+ if (!m_currentEditor)
+ return;
+
+ m_currentEditor = 0;
+ break;
+ }
+ BinEditor *editor = qobject_cast<BinEditor *>(object->widget());
+ if (!editor) {
+ if (!m_currentEditor)
+ return;
+
+ m_currentEditor = 0;
+ break;
+ }
+
+ if (editor == m_currentEditor)
+ return;
+
+ m_currentEditor = editor;
+
+ } while (false);
+ updateActions();
+}
+
+void BinEditorPlugin::updateActions()
+{
+ bool hasEditor = (m_currentEditor != 0);
+ if (m_selectAllAction)
+ m_selectAllAction->setEnabled(hasEditor);
+ if (m_undoAction)
+ m_undoAction->setEnabled(m_currentEditor && m_currentEditor->isUndoAvailable());
+ if (m_redoAction)
+ m_redoAction->setEnabled(m_currentEditor && m_currentEditor->isRedoAvailable());
+ if (m_copyAction)
+ m_copyAction->setEnabled(m_currentEditor && m_currentEditor->hasSelection());
+}
+
+void BinEditorPlugin::undoAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->undo();
+}
+
+void BinEditorPlugin::redoAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->redo();
+}
+
+void BinEditorPlugin::copyAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->copy();
+}
+
+void BinEditorPlugin::selectAllAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->selectAll();
+}
+
+
+Q_EXPORT_PLUGIN(BinEditorPlugin)
+
+#include "bineditorplugin.moc"
diff --git a/src/plugins/bineditor/bineditorplugin.h b/src/plugins/bineditor/bineditorplugin.h
new file mode 100644
index 0000000000..6bd0da64b3
--- /dev/null
+++ b/src/plugins/bineditor/bineditorplugin.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BINEDITORPLUGIN_H
+#define BINEDITORPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QPointer>
+#include <QtCore/QStringList>
+#include <QtGui/QAction>
+
+#include <extensionsystem/iplugin.h>
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+namespace Core {
+class ICore;
+class IWizard;
+}
+
+namespace BINEditor {
+class BinEditor;
+namespace Internal {
+class BinEditorFactory;
+
+
+class BinEditorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ BinEditorPlugin();
+ ~BinEditorPlugin();
+
+ static BinEditorPlugin *instance();
+ static Core::ICore *core();
+
+ bool initialize(const QStringList &arguments, QString *error_message = 0);
+ void extensionsInitialized();
+
+ // Connect editor to settings changed signals.
+ void initializeEditor(BinEditor *editor);
+
+private slots:
+ void undoAction();
+ void redoAction();
+ void copyAction();
+ void selectAllAction();
+ void updateActions();
+
+ void updateCurrentEditor(Core::IContext *object);
+private:
+ QList<int> m_context;
+ QAction *registerNewAction(const QString &id, const QString &title = QString());
+ QAction *registerNewAction(const QString &id, QObject *receiver, const char *slot,
+ const QString &title = QString());
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+ QAction *m_copyAction;
+ QAction *m_selectAllAction;
+
+ friend class BinEditorFactory;
+ Core::IEditor *createEditor(QWidget *parent);
+
+ static BinEditorPlugin *m_instance;
+
+ Core::ICore *m_core;
+ typedef QList<Core::IWizard *> WizardList;
+ WizardList m_wizards;
+ BinEditorFactory *m_factory;
+ QPointer<BinEditor> m_currentEditor;
+};
+
+class BinEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ explicit BinEditorFactory(BinEditorPlugin *owner);
+
+ virtual QStringList mimeTypes() const;
+
+ Core::IEditor *createEditor(QWidget *parent);
+ QString kind() const;
+ Core::IFile *open(const QString &fileName);
+
+private:
+ const QString m_kind;
+ const QStringList m_mimeTypes;
+ BinEditorPlugin *m_owner;
+};
+
+} // namespace Internal
+} // namespace BINEditor
+
+#endif // BINEDITORPLUGIN_H
diff --git a/src/plugins/bookmarks/Bookmarks.pluginspec b/src/plugins/bookmarks/Bookmarks.pluginspec
new file mode 100644
index 0000000000..359ab6d203
--- /dev/null
+++ b/src/plugins/bookmarks/Bookmarks.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="Bookmarks" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Bookmarks in text editors.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/bookmarks/bookmark.cpp b/src/plugins/bookmarks/bookmark.cpp
new file mode 100644
index 0000000000..41f4659cb7
--- /dev/null
+++ b/src/plugins/bookmarks/bookmark.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "bookmark.h"
+#include "bookmarkmanager.h"
+#include <QtCore/QDebug>
+#include <QtGui/QTextBlock>
+
+using namespace Bookmarks::Internal;
+
+const QIcon Bookmark::m_bookmarkIcon = QIcon(":/bookmarks/images/bookmark.png");
+
+Bookmark::Bookmark(const QString& fileName, int lineNumber, BookmarkManager *manager)
+ : BaseTextMark(fileName, lineNumber), m_manager(manager)
+{
+ m_fileName = fileName;
+ m_fileInfo.setFile(fileName);
+ m_onlyFile = m_fileInfo.fileName();
+ m_path = m_fileInfo.path();
+ m_lineNumber= lineNumber;
+}
+
+QIcon Bookmark::icon() const
+{
+ return m_bookmarkIcon;
+}
+
+void Bookmark::removedFromEditor()
+{
+ m_manager->removeBookmark(this);
+}
+
+void Bookmark::updateLineNumber(int lineNumber)
+{
+ if (lineNumber != m_lineNumber) {
+ m_lineNumber = lineNumber;
+ m_manager->updateBookmark(this);
+ }
+}
+
+void Bookmark::updateBlock(const QTextBlock &block)
+{
+ if (m_lineText != block.text()) {
+ m_lineText = block.text();
+ m_manager->updateBookmark(this);
+ }
+}
+
+QString Bookmark::lineText() const
+{
+ return m_lineText;
+}
+
+QString Bookmark::filePath() const
+{
+ return m_fileName;
+}
+
+QString Bookmark::fileName() const
+{
+ return m_onlyFile;
+}
+
+QString Bookmark::path() const
+{
+ return m_path;
+}
diff --git a/src/plugins/bookmarks/bookmark.h b/src/plugins/bookmarks/bookmark.h
new file mode 100644
index 0000000000..d54d6af3e5
--- /dev/null
+++ b/src/plugins/bookmarks/bookmark.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BOOKMARK_H
+#define BOOKMARK_H
+
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetextmark.h>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+#include <QtCore/QFileInfo>
+
+namespace Bookmarks {
+namespace Internal {
+
+class BookmarkManager;
+
+class Bookmark : public TextEditor::BaseTextMark
+{
+ Q_OBJECT
+public:
+ Bookmark(const QString& fileName, int lineNumber, BookmarkManager *manager);
+
+ QIcon icon() const;
+
+ void updateLineNumber(int lineNumber);
+ void updateBlock(const QTextBlock &block);
+ void removedFromEditor();
+
+ QString filePath() const;
+ QString fileName() const;
+ QString path() const;
+ QString lineText() const;
+
+ inline int lineNumber() const { return m_lineNumber; }
+
+private:
+ static const QIcon m_bookmarkIcon;
+
+ BookmarkManager *m_manager;
+ int m_lineNumber;
+ QString m_name;
+ QString m_fileName;
+ QString m_onlyFile;
+ QString m_path;
+ QString m_lineText;
+ QFileInfo m_fileInfo;
+};
+
+} // namespace Internal
+} // namespace Bookmarks
+
+#endif // BOOKMARK_H
diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp
new file mode 100644
index 0000000000..bb26bfbd4f
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarkmanager.cpp
@@ -0,0 +1,742 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "bookmarkmanager.h"
+#include "bookmark.h"
+#include "bookmarksplugin.h"
+#include "bookmarks_global.h"
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtGui/QAction>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtGui/QPainter>
+#include <QtGui/QContextMenuEvent>
+
+Q_DECLARE_METATYPE(Bookmarks::Internal::Bookmark*)
+
+using namespace Bookmarks;
+using namespace Bookmarks::Internal;
+using namespace ProjectExplorer;
+
+BookmarkDelegate::BookmarkDelegate(QObject *parent)
+ : QStyledItemDelegate(parent), m_normalPixmap(0), m_selectedPixmap(0)
+{
+}
+
+BookmarkDelegate::~BookmarkDelegate()
+{
+ delete m_normalPixmap;
+ delete m_selectedPixmap;
+}
+
+QSize BookmarkDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption(&opt, index);
+
+ QFontMetrics fm(option.font);
+ QSize s;
+ s.setWidth(option.rect.width());
+ s.setHeight(fm.height() * 2 + 10);
+ return s;
+}
+
+void BookmarkDelegate::generateGradientPixmap(int width, int height, QColor color, bool selected) const
+{
+
+ QColor c = color;
+ c.setAlpha(0);
+
+ QPixmap *pixmap = new QPixmap(width+1, height);
+ pixmap->fill(c);
+
+ QPainter painter(pixmap);
+ painter.setPen(Qt::NoPen);
+
+ QLinearGradient lg;
+ lg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ lg.setFinalStop(1,0);
+
+ lg.setColorAt(0, c);
+ lg.setColorAt(0.4, color);
+
+ painter.setBrush(lg);
+ painter.drawRect(0, 0, width+1, height);
+
+ if (selected)
+ m_selectedPixmap = pixmap;
+ else
+ m_normalPixmap = pixmap;
+}
+
+void BookmarkDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption(&opt, index);
+ painter->save();
+
+ QFontMetrics fm(opt.font);
+ static int lwidth = fm.width("8888") + 18;
+
+ QColor backgroundColor;
+ QColor textColor;
+
+ bool selected = opt.state & QStyle::State_Selected;
+
+ if (selected) {
+ painter->setBrush(opt.palette.highlight().color());
+ backgroundColor = opt.palette.highlight().color();
+ if (!m_selectedPixmap)
+ generateGradientPixmap(lwidth, fm.height()+1, backgroundColor, selected);
+ } else {
+ painter->setBrush(opt.palette.background().color());
+ backgroundColor = opt.palette.background().color();
+ if (!m_normalPixmap)
+ generateGradientPixmap(lwidth, fm.height(), backgroundColor, selected);
+ }
+ painter->setPen(Qt::NoPen);
+ painter->drawRect(opt.rect);
+
+ // Set Text Color
+ if (opt.state & QStyle::State_Selected)
+ textColor = opt.palette.highlightedText().color();
+ else
+ textColor = opt.palette.text().color();
+
+ painter->setPen(textColor);
+
+
+ // TopLeft
+ QString topLeft = index.data(BookmarkManager::Filename ).toString();
+ painter->drawText(6, 2 + opt.rect.top() + fm.ascent(), topLeft);
+
+ QString topRight = index.data(BookmarkManager::LineNumber).toString();
+ // Check wheter we need to be fancy and paint some background
+ int fwidth = fm.width(topLeft);
+ if (fwidth + lwidth > opt.rect.width()) {
+ int left = opt.rect.right() - lwidth;
+ painter->drawPixmap(left, opt.rect.top(), selected? *m_selectedPixmap : *m_normalPixmap);
+ }
+ // topRight
+ painter->drawText(opt.rect.right() - fm.width(topRight) - 6 , 2 + opt.rect.top() + fm.ascent(), topRight);
+
+ // Directory
+ QColor mix;
+ mix.setRgbF(0.7 * textColor.redF() + 0.3 * backgroundColor.redF(),
+ 0.7 * textColor.greenF() + 0.3 * backgroundColor.greenF(),
+ 0.7 * textColor.blueF() + 0.3 * backgroundColor.blueF());
+ painter->setPen(mix);
+//
+// QString directory = index.data(BookmarkManager::Directory).toString();
+// int availableSpace = opt.rect.width() - 12;
+// if (fm.width(directory) > availableSpace) {
+// // We need a shorter directory
+// availableSpace -= fm.width("...");
+//
+// int pos = directory.size();
+// int idx;
+// forever {
+// idx = directory.lastIndexOf("/", pos-1);
+// if(idx == -1) {
+// // Can't happen, this means the string did fit after all?
+// break;
+// }
+// int width = fm.width(directory.mid(idx, pos-idx));
+// if (width > availableSpace) {
+// directory = "..." + directory.mid(pos);
+// break;
+// } else {
+// pos = idx;
+// availableSpace -= width;
+// }
+// }
+// }
+//
+// painter->drawText(3, opt.rect.top() + fm.ascent() + fm.height() + 6, directory);
+
+ QString lineText = index.data(BookmarkManager::LineText).toString().trimmed();
+ painter->drawText(6, opt.rect.top() + fm.ascent() + fm.height() + 6, lineText);
+
+ // Separator lines
+ painter->setPen(QColor::fromRgb(150,150,150));
+ painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
+ painter->restore();
+}
+
+BookmarkView::BookmarkView(QWidget *parent)
+ : QListView(parent)
+{
+ setWindowTitle(tr("Bookmarks"));
+ setWindowIcon(QIcon(":/bookmarks/images/bookmark.png"));
+
+ connect(this, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(gotoBookmark(const QModelIndex &)));
+
+ m_bookmarkContext = new BookmarkContext(this);
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ core->addContextObject(m_bookmarkContext);
+
+ setItemDelegate(new BookmarkDelegate(this));
+ setFrameStyle(QFrame::NoFrame);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setFocusPolicy(Qt::NoFocus);
+}
+
+BookmarkView::~BookmarkView()
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ core->removeContextObject(m_bookmarkContext);
+}
+
+void BookmarkView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu menu;
+ QAction *remove = menu.addAction("&Remove Bookmark");
+ QAction *removeAll = menu.addAction("Remove all Bookmarks");
+ m_contextMenuIndex = indexAt(event->pos());
+ if (!m_contextMenuIndex.isValid())
+ remove->setEnabled(false);
+
+ if (model()->rowCount() == 0)
+ removeAll->setEnabled(false);
+
+ connect(remove, SIGNAL(triggered()),
+ this, SLOT(removeFromContextMenu()));
+ connect(removeAll, SIGNAL(triggered()),
+ this, SLOT(removeAll()));
+
+
+ menu.exec(mapToGlobal(event->pos()));
+}
+
+void BookmarkView::removeFromContextMenu()
+{
+
+ removeBookmark(m_contextMenuIndex);
+}
+
+void BookmarkView::removeBookmark(const QModelIndex& index)
+{
+ BookmarkManager *manager = static_cast<BookmarkManager *>(model());
+ Bookmark *bm = manager->bookmarkForIndex(index);
+ manager->removeBookmark(bm);
+}
+
+// The perforcemance of this function could be greatly improved.
+//
+void BookmarkView::removeAll()
+{
+ BookmarkManager *manager = static_cast<BookmarkManager *>(model());
+ while (manager->rowCount()) {
+ QModelIndex index = manager->index(0, 0);
+ removeBookmark(index);
+ }
+}
+
+void BookmarkView::setModel(QAbstractItemModel *model)
+{
+ BookmarkManager *manager = qobject_cast<BookmarkManager *>(model);
+ Q_ASSERT(manager);
+ QListView::setModel(model);
+ setSelectionModel(manager->selectionModel());
+ setSelectionMode(QAbstractItemView::SingleSelection);
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+}
+
+void BookmarkView::gotoBookmark(const QModelIndex &index)
+{
+ static_cast<BookmarkManager *>(model())->gotoBookmark(index);
+}
+
+////
+// BookmarkContext
+////
+
+BookmarkContext::BookmarkContext(BookmarkView *widget)
+ : m_bookmarkView(widget)
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ m_context << core->uniqueIDManager()->uniqueIdentifier(Constants::BOOKMARKS_CONTEXT);
+}
+
+QList<int> BookmarkContext::context() const
+{
+ return m_context;
+}
+
+QWidget *BookmarkContext::widget()
+{
+ return m_bookmarkView;
+}
+
+////
+// BookmarkManager
+////
+
+BookmarkManager::BookmarkManager() :
+ m_core(BookmarksPlugin::core()),
+ m_bookmarkIcon(QIcon(QLatin1String(":/bookmarks/images/bookmark.png")))
+{
+ m_selectionModel = new QItemSelectionModel(this, this);
+
+ connect(m_core, SIGNAL(contextChanged(Core::IContext*)),
+ this, SLOT(updateActionStatus()));
+
+ ExtensionSystem::PluginManager *pm = m_core->pluginManager();
+ ProjectExplorerPlugin *projectExplorer = pm->getObject<ProjectExplorerPlugin>();
+
+ connect(projectExplorer->session(), SIGNAL(sessionLoaded()),
+ this, SLOT(loadBookmarks()));
+
+ updateActionStatus();
+}
+
+BookmarkManager::~BookmarkManager()
+{
+ DirectoryFileBookmarksMap::iterator it, end;
+ end = m_bookmarksMap.end();
+ for (it = m_bookmarksMap.begin(); it != end; ++it) {
+ FileNameBookmarksMap *bookmarks = it.value();
+ qDeleteAll(bookmarks->values());
+ delete bookmarks;
+ }
+}
+
+QItemSelectionModel *BookmarkManager::selectionModel() const
+{
+ return m_selectionModel;
+}
+
+QModelIndex BookmarkManager::index(int row, int column, const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return QModelIndex();
+ else
+ return createIndex(row, column, 0);
+}
+
+QModelIndex BookmarkManager::parent(const QModelIndex &) const
+{
+ return QModelIndex();
+}
+
+int BookmarkManager::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ else
+ return m_bookmarksList.count();
+}
+
+int BookmarkManager::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return 3;
+}
+
+QVariant BookmarkManager::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.column() !=0 || index.row() < 0 || index.row() >= m_bookmarksList.count())
+ return QVariant();
+
+ if (role == BookmarkManager::Filename)
+ return m_bookmarksList.at(index.row())->fileName();
+ else if (role == BookmarkManager::LineNumber)
+ return m_bookmarksList.at(index.row())->lineNumber();
+ else if (role == BookmarkManager::Directory)
+ return m_bookmarksList.at(index.row())->path();
+ else if (role == BookmarkManager::LineText)
+ return m_bookmarksList.at(index.row())->lineText();
+ else if (role == Qt::ToolTipRole)
+ return m_bookmarksList.at(index.row())->filePath();
+
+ return QVariant();
+}
+
+void BookmarkManager::toggleBookmark()
+{
+ TextEditor::ITextEditor *editor = currentTextEditor();
+ if (!editor)
+ return;
+
+ const QFileInfo fi(editor->file()->fileName());
+ const int editorLine = editor->currentLine();
+
+ // Remove any existing bookmark on this line
+ if (Bookmark *mark = findBookmark(fi.path(), fi.fileName(), editorLine)) {
+ // TODO check if the bookmark is really on the same markable Interface
+ removeBookmark(mark);
+ return;
+ }
+
+ // Add a new bookmark if no bookmark existed on this line
+ Bookmark *bookmark = new Bookmark(fi.filePath(), editorLine, this);
+ addBookmark(bookmark);
+}
+
+void BookmarkManager::updateBookmark(Bookmark *bookmark)
+{
+ int idx = m_bookmarksList.indexOf(bookmark);
+ emit dataChanged(index(idx, 0, QModelIndex()), index(idx, 2, QModelIndex()));
+ saveBookmarks();
+}
+
+void BookmarkManager::removeBookmark(Bookmark *bookmark)
+{
+ const QFileInfo fi(bookmark->filePath() );
+ FileNameBookmarksMap *files = m_bookmarksMap.value(fi.path());
+
+ FileNameBookmarksMap::iterator i = files->begin();
+ while (i != files->end()) {
+ if (i.value() == bookmark) {
+ files->erase(i);
+ delete bookmark;
+ break;
+ }
+ ++i;
+ }
+ if (files->count() <= 0) {
+ m_bookmarksMap.remove(fi.path());
+ delete files;
+ }
+
+ int idx = m_bookmarksList.indexOf(bookmark);
+ beginRemoveRows(QModelIndex(), idx, idx);
+ m_bookmarksList.removeAt(idx);
+ endRemoveRows();
+
+ if (selectionModel()->currentIndex().isValid())
+ selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::Select | QItemSelectionModel::Clear);
+
+ updateActionStatus();
+ saveBookmarks();
+}
+
+Bookmark *BookmarkManager::bookmarkForIndex(QModelIndex index)
+{
+ if (!index.isValid() || index.row() >= m_bookmarksList.size())
+ return 0;
+ return m_bookmarksList.at(index.row());
+}
+
+void BookmarkManager::gotoBookmark(const QModelIndex &idx)
+{
+ gotoBookmark(m_bookmarksList.at(idx.row()));
+}
+
+void BookmarkManager::gotoBookmark(Bookmark* bookmark)
+{
+ TextEditor::BaseTextEditor::openEditorAt(bookmark->filePath(),
+ bookmark->lineNumber());
+}
+
+void BookmarkManager::nextInDocument()
+{
+ documentPrevNext(true);
+}
+
+void BookmarkManager::prevInDocument()
+{
+ documentPrevNext(false);
+}
+
+void BookmarkManager::documentPrevNext(bool next)
+{
+ TextEditor::ITextEditor *editor = currentTextEditor();
+ int editorLine = editor->currentLine();
+ QFileInfo fi(editor->file()->fileName());
+ if (!m_bookmarksMap.contains(fi.path()))
+ return;
+
+ int firstLine = -1;
+ int lastLine = -1;
+ int prevLine = -1;
+ int nextLine = -1;
+ const QList<Bookmark*> marks = m_bookmarksMap.value(fi.path())->values(fi.fileName());
+ for (int i = 0; i < marks.count(); ++i) {
+ int markLine = marks.at(i)->lineNumber();
+ if (firstLine == -1 || firstLine > markLine)
+ firstLine = markLine;
+ if (lastLine < markLine)
+ lastLine = markLine;
+ if (markLine < editorLine && prevLine < markLine)
+ prevLine = markLine;
+ if (markLine > editorLine &&
+ (nextLine == -1 || nextLine > markLine))
+ nextLine = markLine;
+ }
+
+ m_core->editorManager()->addCurrentPositionToNavigationHistory(true);
+ if (next) {
+ if (nextLine == -1)
+ editor->gotoLine(firstLine);
+ else
+ editor->gotoLine(nextLine);
+ } else {
+ if (prevLine == -1)
+ editor->gotoLine(lastLine);
+ else
+ editor->gotoLine(prevLine);
+ }
+ m_core->editorManager()->addCurrentPositionToNavigationHistory();
+}
+
+void BookmarkManager::next()
+{
+ QModelIndex current = selectionModel()->currentIndex();
+ if (!current.isValid())
+ return;
+ int row = current.row() + 1;
+ if (row == m_bookmarksList.size())
+ row = 0;
+ QModelIndex newIndex = current.sibling(row, current.column());
+ selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::Select | QItemSelectionModel::Clear);
+ gotoBookmark(newIndex);
+}
+
+void BookmarkManager::prev()
+{
+ QModelIndex current = selectionModel()->currentIndex();
+ if (!current.isValid())
+ return;
+ int row = current.row();
+ if (row == 0)
+ row = m_bookmarksList.size();
+ --row;
+ QModelIndex newIndex = current.sibling(row, current.column());
+ selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::Select | QItemSelectionModel::Clear);
+ gotoBookmark(newIndex);
+}
+
+TextEditor::ITextEditor *BookmarkManager::currentTextEditor() const
+{
+ Core::IEditor *currEditor = m_core->editorManager()->currentEditor();
+ if (!currEditor)
+ return 0;
+ return qobject_cast<TextEditor::ITextEditor *>(currEditor);
+}
+
+/* Returns the current session. */
+SessionManager* BookmarkManager::sessionManager() const
+{
+ ExtensionSystem::PluginManager *pm = m_core->pluginManager();
+ ProjectExplorerPlugin *pe = pm->getObject<ProjectExplorerPlugin>();
+ return pe->session();
+}
+
+BookmarkManager::State BookmarkManager::state() const
+{
+ if (m_bookmarksMap.empty())
+ return NoBookMarks;
+
+ TextEditor::ITextEditor *editor = currentTextEditor();
+ if (!editor)
+ return HasBookMarks;
+
+ const QFileInfo fi(editor->file()->fileName());
+
+ const DirectoryFileBookmarksMap::const_iterator dit = m_bookmarksMap.constFind(fi.path());
+ if (dit == m_bookmarksMap.constEnd())
+ return HasBookMarks;
+
+ return HasBookmarksInDocument;
+}
+
+void BookmarkManager::updateActionStatus()
+{
+ emit updateActions(state());
+}
+
+void BookmarkManager::moveUp()
+{
+ QModelIndex current = selectionModel()->currentIndex();
+ int row = current.row();
+ if (row == 0)
+ row = m_bookmarksList.size();
+ --row;
+
+ // swap current.row() and row
+
+ Bookmark *b = m_bookmarksList.at(row);
+ m_bookmarksList[row] = m_bookmarksList.at(current.row());
+ m_bookmarksList[current.row()] = b;
+
+ QModelIndex topLeft = current.sibling(row, 0);
+ QModelIndex bottomRight = current.sibling(current.row(), 2);
+ emit dataChanged(topLeft, bottomRight);
+ selectionModel()->setCurrentIndex(current.sibling(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Clear);
+}
+
+void BookmarkManager::moveDown()
+{
+ QModelIndex current = selectionModel()->currentIndex();
+ int row = current.row();
+ ++row;
+ if (row == m_bookmarksList.size())
+ row = 0;
+
+ // swap current.row() and row
+ Bookmark *b = m_bookmarksList.at(row);
+ m_bookmarksList[row] = m_bookmarksList.at(current.row());
+ m_bookmarksList[current.row()] = b;
+
+ QModelIndex topLeft = current.sibling(current.row(), 0);
+ QModelIndex bottomRight = current.sibling(row, 2);
+ emit dataChanged(topLeft, bottomRight);
+ selectionModel()->setCurrentIndex(current.sibling(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Clear);
+}
+
+/* Returns the bookmark at the given file and line number, or 0 if no such bookmark exists. */
+Bookmark* BookmarkManager::findBookmark(const QString &path, const QString &fileName, int lineNumber)
+{
+ if (m_bookmarksMap.contains(path)) {
+ foreach (Bookmark *bookmark, m_bookmarksMap.value(path)->values(fileName)) {
+ if (bookmark->lineNumber() == lineNumber)
+ return bookmark;
+ }
+ }
+ return 0;
+}
+
+/* Adds a bookmark to the internal data structures. The 'userset' parameter
+ * determines whether action status should be updated and whether the bookmarks
+ * should be saved to the session settings.
+ */
+void BookmarkManager::addBookmark(Bookmark *bookmark, bool userset)
+{
+ beginInsertRows(QModelIndex(), m_bookmarksList.size(), m_bookmarksList.size());
+ const QFileInfo fi(bookmark->filePath());
+ const QString &path = fi.path();
+
+ if (!m_bookmarksMap.contains(path))
+ m_bookmarksMap.insert(path, new FileNameBookmarksMap());
+ m_bookmarksMap.value(path)->insert(fi.fileName(), bookmark);
+
+ m_bookmarksList.append(bookmark);
+
+ endInsertRows();
+ if (userset) {
+ updateActionStatus();
+ saveBookmarks();
+ }
+ selectionModel()->setCurrentIndex(index(m_bookmarksList.size()-1 , 0, QModelIndex()), QItemSelectionModel::Select | QItemSelectionModel::Clear);
+}
+
+/* Adds a new bookmark based on information parsed from the string. */
+void BookmarkManager::addBookmark(const QString &s)
+{
+ int index2 = s.lastIndexOf(':');
+ int index1 = s.indexOf(':');
+ if (index2 != -1 || index1 != -1) {
+ const QString &filePath = s.mid(index1+1, index2-index1-1);
+ const int lineNumber = s.mid(index2 + 1).toInt();
+ const QFileInfo fi(filePath);
+
+ if (!filePath.isEmpty() && !findBookmark(fi.path(), fi.fileName(), lineNumber)) {
+ Bookmark *b = new Bookmark(filePath, lineNumber, this);
+ addBookmark(b, false);
+ }
+ } else {
+ qDebug() << "BookmarkManager::addBookmark() Invalid bookmark string:" << s;
+ }
+}
+
+/* Puts the bookmark in a string for storing it in the settings. */
+QString BookmarkManager::bookmarkToString(const Bookmark *b)
+{
+ const QLatin1Char colon(':');
+ // Empty string was the name of the bookmark, which now is always ""
+ return QLatin1String("") + colon + b->filePath() + colon + QString::number(b->lineNumber());
+}
+
+/* Saves the bookmarks to the session settings. */
+void BookmarkManager::saveBookmarks()
+{
+ SessionManager *s = sessionManager();
+ if (!s)
+ return;
+
+ QStringList list;
+ foreach (const FileNameBookmarksMap *bookmarksMap, m_bookmarksMap)
+ foreach (const Bookmark *bookmark, *bookmarksMap)
+ list << bookmarkToString(bookmark);
+
+ s->setValue("Bookmarks", list);
+}
+
+/* Loads the bookmarks from the session settings. */
+void BookmarkManager::loadBookmarks()
+{
+ SessionManager *s = sessionManager();
+ if (!s)
+ return;
+
+ const QStringList &list = s->value("Bookmarks").toStringList();
+ foreach (const QString &bookmarkString, list)
+ addBookmark(bookmarkString);
+
+ updateActionStatus();
+}
+
+// BookmarkViewFactory
+
+BookmarkViewFactory::BookmarkViewFactory(BookmarkManager *bm)
+ : m_manager(bm)
+{
+
+}
+
+QString BookmarkViewFactory::displayName()
+{
+ return "Bookmarks";
+}
+
+QKeySequence BookmarkViewFactory::activationSequence()
+{
+ return QKeySequence(Qt::ALT + Qt::Key_M);
+}
+
+Core::NavigationView BookmarkViewFactory::createWidget()
+{
+ BookmarkView *bookmarkView = new BookmarkView();
+ bookmarkView->setModel(m_manager);
+ Core::NavigationView view;
+ view.widget = bookmarkView;
+ return view;
+}
diff --git a/src/plugins/bookmarks/bookmarkmanager.h b/src/plugins/bookmarks/bookmarkmanager.h
new file mode 100644
index 0000000000..45e4bf3b7b
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarkmanager.h
@@ -0,0 +1,193 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BOOKMARKMANAGER_H
+#define BOOKMARKMANAGER_H
+
+#include <QtCore/QAbstractItemModel>
+#include <QtGui/QListView>
+#include <QtCore/QList>
+#include <QtGui/QPixmap>
+#include <QtGui/QStyledItemDelegate>
+
+#include <coreplugin/icontext.h>
+#include <coreplugin/inavigationwidgetfactory.h>
+
+namespace ProjectExplorer {
+class SessionManager;
+}
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace Bookmarks {
+namespace Internal {
+
+class Bookmark;
+class BookmarksPlugin;
+class BookmarkContext;
+
+class BookmarkManager : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ BookmarkManager();
+ ~BookmarkManager();
+ void updateBookmark(Bookmark *bookmark);
+ void removeBookmark(Bookmark *bookmark); // Does not remove the mark
+ Bookmark *bookmarkForIndex(QModelIndex index);
+
+ enum State { NoBookMarks, HasBookMarks, HasBookmarksInDocument };
+ State state() const;
+
+ // Model stuff
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ void gotoBookmark(const QModelIndex &);
+
+ // this QItemSelectionModel is shared by all views
+ QItemSelectionModel *selectionModel() const;
+
+ enum Roles {Filename = Qt::UserRole, LineNumber = Qt::UserRole + 1, Directory = Qt::UserRole + 2, LineText = Qt::UserRole + 3};
+
+public slots:
+ void toggleBookmark();
+ void nextInDocument();
+ void prevInDocument();
+ void next();
+ void prev();
+ void moveUp();
+ void moveDown();
+
+signals:
+ void updateActions(int state);
+ void currentIndexChanged(const QModelIndex &);
+
+private slots:
+ void updateActionStatus();
+ void gotoBookmark(Bookmark *bookmark);
+ void loadBookmarks();
+private:
+ TextEditor::ITextEditor *currentTextEditor() const;
+ ProjectExplorer::SessionManager* sessionManager() const;
+
+ void documentPrevNext(bool next);
+
+ Bookmark* findBookmark(const QString &path, const QString &fileName, int lineNumber);
+ void addBookmark(Bookmark *bookmark, bool userset = true);
+ void addBookmark(const QString &s);
+ static QString bookmarkToString(const Bookmark *b);
+ void saveBookmarks();
+
+ typedef QMultiMap<QString, Bookmark*> FileNameBookmarksMap;
+ typedef QMap<QString, FileNameBookmarksMap*> DirectoryFileBookmarksMap;
+
+ DirectoryFileBookmarksMap m_bookmarksMap;
+ Core::ICore *m_core;
+
+ QIcon m_bookmarkIcon;
+
+ QList<Bookmark *> m_bookmarksList;
+ QItemSelectionModel *m_selectionModel;
+};
+
+class BookmarkView : public QListView {
+ Q_OBJECT
+public:
+ BookmarkView(QWidget *parent = 0);
+ ~BookmarkView();
+ void setModel(QAbstractItemModel * model);
+public slots:
+ void gotoBookmark(const QModelIndex &index);
+protected slots:
+ void removeFromContextMenu();
+ void removeAll();
+protected:
+ void contextMenuEvent(QContextMenuEvent *event);
+ void removeBookmark(const QModelIndex& index);
+private:
+ BookmarkContext *m_bookmarkContext;
+ QModelIndex m_contextMenuIndex;
+};
+
+class BookmarkContext : public Core::IContext
+{
+public:
+ BookmarkContext(BookmarkView *widget);
+ virtual QList<int> context() const;
+ virtual QWidget *widget();
+private:
+ BookmarkView *m_bookmarkView;
+ QList<int> m_context;
+};
+
+class BookmarkViewFactory : public Core::INavigationWidgetFactory
+{
+public:
+ BookmarkViewFactory(BookmarkManager *bm);
+ virtual QString displayName();
+ virtual QKeySequence activationSequence();
+ virtual Core::NavigationView createWidget();
+private:
+ BookmarkManager *m_manager;
+};
+
+class BookmarkDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ BookmarkDelegate(QObject * parent = 0);
+ ~BookmarkDelegate();
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+private:
+ void generateGradientPixmap(int width, int height, QColor color, bool selected) const;
+ mutable QPixmap *m_normalPixmap;
+ mutable QPixmap *m_selectedPixmap;
+};
+
+} // namespace Internal
+} // namespace Bookmarks
+
+#endif // BOOKMARKMANAGER_H
diff --git a/src/plugins/bookmarks/bookmarks.pro b/src/plugins/bookmarks/bookmarks.pro
new file mode 100644
index 0000000000..1fcbffff7b
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarks.pro
@@ -0,0 +1,18 @@
+TEMPLATE = lib
+TARGET = Bookmarks
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
+
+HEADERS += bookmarksplugin.h \
+ bookmark.h \
+ bookmarkmanager.h \
+ bookmarks_global.h
+
+SOURCES += bookmarksplugin.cpp \
+ bookmark.cpp \
+ bookmarkmanager.cpp
+
+RESOURCES += bookmarks.qrc
diff --git a/src/plugins/bookmarks/bookmarks.qrc b/src/plugins/bookmarks/bookmarks.qrc
new file mode 100644
index 0000000000..f0a890bf37
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarks.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/bookmarks" >
+ <file>images/bookmark.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/bookmarks/bookmarks_global.h b/src/plugins/bookmarks/bookmarks_global.h
new file mode 100644
index 0000000000..e29f4e5865
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarks_global.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BOOKMARKS_GLOBAL_H
+#define BOOKMARKS_GLOBAL_H
+
+namespace Bookmarks {
+namespace Constants {
+
+const char * const BOOKMARKS_TOGGLE_ACTION = "Bookmarks.Toggle";
+const char * const BOOKMARKS_MOVEUP_ACTION = "Bookmarks.MoveUp";
+const char * const BOOKMARKS_MOVEDOWN_ACTION = "Bookmarks.MoveDown";
+const char * const BOOKMARKS_PREV_ACTION = "Bookmarks.Previous";
+const char * const BOOKMARKS_NEXT_ACTION = "Bookmarks.Next";
+const char * const BOOKMARKS_PREVDIR_ACTION = "Bookmarks.Previous.Directory";
+const char * const BOOKMARKS_NEXTDIR_ACTION = "Bookmarks.Next.Directory";
+const char * const BOOKMARKS_PREVDOC_ACTION = "Bookmarks.Previous.Document";
+const char * const BOOKMARKS_NEXTDOC_ACTION = "Bookmarks.Next.Document";
+
+const char * const BOOKMARKS_MENU = "Bookmarks.Menu";
+const char * const BOOKMARKS_CONTEXT = "Bookmarks";
+
+} //namespace Constants
+} //namespace Bookmarks
+
+#endif //BOOKMARKS_GLOBAL_H
+
diff --git a/src/plugins/bookmarks/bookmarksplugin.cpp b/src/plugins/bookmarks/bookmarksplugin.cpp
new file mode 100644
index 0000000000..76df8e5777
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarksplugin.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "bookmarksplugin.h"
+#include "bookmarkmanager.h"
+#include "bookmarks_global.h"
+
+#include <QtCore/qplugin.h>
+#include <QtGui/QMenu>
+#include <QDebug>
+
+#include <texteditor/texteditorconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+
+using namespace Bookmarks::Constants;
+using namespace Bookmarks::Internal;
+
+BookmarksPlugin *BookmarksPlugin::m_instance = 0;
+
+BookmarksPlugin::BookmarksPlugin():
+ m_bookmarkManager(0),
+ m_core(0)
+{
+ m_instance = this;
+}
+
+void BookmarksPlugin::extensionsInitialized()
+{
+}
+
+bool BookmarksPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ QList<int> context = QList<int>() << m_core->uniqueIDManager()->
+ uniqueIdentifier(Constants::BOOKMARKS_CONTEXT);
+ QList<int> textcontext, globalcontext;
+ textcontext << m_core->uniqueIDManager()->
+ uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+
+ Core::IActionContainer *mtools =
+ am->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *mbm =
+ am->createMenu(QLatin1String(BOOKMARKS_MENU));
+ mbm->menu()->setTitle(tr("&Bookmarks"));
+ mtools->addMenu(mbm);
+
+ //Toggle
+ m_toggleAction = new QAction(tr("Toggle Bookmark"), this);
+ Core::ICommand *cmd =
+ am->registerAction(m_toggleAction, BOOKMARKS_TOGGLE_ACTION, textcontext);
+#ifndef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+M")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Meta+M")));
+#endif
+ mbm->addAction(cmd);
+
+ QAction *sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("Bookmarks.Sep.Toggle"), textcontext);
+ mbm->addAction(cmd);
+
+ // Move Up
+ m_moveUpAction = new QAction(tr("Move Up"), this);
+ cmd = am->registerAction(m_moveUpAction, BOOKMARKS_MOVEUP_ACTION, context);
+ mbm->addAction(cmd);
+
+ // Move Down
+ m_moveDownAction = new QAction(tr("Move Down"), this);
+ cmd = am->registerAction(m_moveDownAction, BOOKMARKS_MOVEDOWN_ACTION, context);
+ mbm->addAction(cmd);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("Bookmarks.Sep.Navigation"), context);
+ mbm->addAction(cmd);
+
+ //Previous
+ m_prevAction = new QAction(tr("Previous Bookmark"), this);
+ cmd = am->registerAction(m_prevAction, BOOKMARKS_PREV_ACTION, globalcontext);
+#ifndef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+,")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Meta+,")));
+#endif
+ mbm->addAction(cmd);
+
+ //Next
+ m_nextAction = new QAction(tr("Next Bookmark"), this);
+ cmd = am->registerAction(m_nextAction, BOOKMARKS_NEXT_ACTION, globalcontext);
+#ifndef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+.")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Meta+.")));
+#endif
+ mbm->addAction(cmd);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("Bookmarks.Sep.DirNavigation"), globalcontext);
+ mbm->addAction(cmd);
+
+ //Previous Doc
+ m_docPrevAction = new QAction(tr("Previous Bookmark In Document"), this);
+ cmd = am->registerAction(m_docPrevAction, BOOKMARKS_PREVDOC_ACTION, globalcontext);
+ mbm->addAction(cmd);
+
+ //Next Doc
+ m_docNextAction = new QAction(tr("Next Bookmark In Document"), this);
+ cmd = am->registerAction(m_docNextAction, BOOKMARKS_NEXTDOC_ACTION, globalcontext);
+ mbm->addAction(cmd);
+
+ m_bookmarkManager = new BookmarkManager;
+
+ connect(m_toggleAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(toggleBookmark()));
+ connect(m_prevAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(prev()));
+ connect(m_nextAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(next()));
+ connect(m_docPrevAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(prevInDocument()));
+ connect(m_docNextAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(nextInDocument()));
+ connect(m_moveUpAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(moveUp()));
+ connect(m_moveDownAction, SIGNAL(triggered()), m_bookmarkManager, SLOT(moveDown()));
+ connect(m_bookmarkManager, SIGNAL(updateActions(int)), this, SLOT(updateActions(int)));
+ updateActions(m_bookmarkManager->state());
+ addAutoReleasedObject(new BookmarkViewFactory(m_bookmarkManager));
+
+ return true;
+}
+
+BookmarksPlugin::~BookmarksPlugin()
+{
+ delete m_bookmarkManager;
+}
+
+void BookmarksPlugin::updateActions(int state)
+{
+
+ const bool hasbm = state >= BookmarkManager::HasBookMarks;
+ const bool hasdocbm = state == BookmarkManager::HasBookmarksInDocument;
+
+ m_toggleAction->setEnabled(true);
+ m_prevAction->setEnabled(hasbm);
+ m_nextAction->setEnabled(hasbm);
+ m_docPrevAction->setEnabled(hasdocbm);
+ m_docNextAction->setEnabled(hasdocbm);
+ m_moveUpAction->setEnabled(hasbm);
+ m_moveDownAction->setEnabled(hasbm);
+}
+
+Q_EXPORT_PLUGIN(BookmarksPlugin)
diff --git a/src/plugins/bookmarks/bookmarksplugin.h b/src/plugins/bookmarks/bookmarksplugin.h
new file mode 100644
index 0000000000..7da45ef5ee
--- /dev/null
+++ b/src/plugins/bookmarks/bookmarksplugin.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BOOKMARKS_H
+#define BOOKMARKS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QMultiMap>
+
+#include <extensionsystem/iplugin.h>
+
+QT_FORWARD_DECLARE_CLASS(QAction)
+
+namespace Core {
+class ICore;
+}
+
+namespace Bookmarks {
+namespace Internal {
+
+class BookmarkManager;
+
+class BookmarksPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ BookmarksPlugin();
+ ~BookmarksPlugin();
+
+ static BookmarksPlugin *instance() { return m_instance; }
+ static Core::ICore *core() { return m_instance->m_core; }
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+public slots:
+ void updateActions(int stateMask);
+
+private:
+ static BookmarksPlugin *m_instance;
+ BookmarkManager *m_bookmarkManager;
+ Core::ICore *m_core;
+
+ QAction *m_toggleAction;
+ QAction *m_prevAction;
+ QAction *m_nextAction;
+ QAction *m_docPrevAction;
+ QAction *m_docNextAction;
+ QAction *m_moveUpAction;
+ QAction *m_moveDownAction;
+};
+
+} // namespace Internal
+} // namespace Bookmarks
+
+#endif // BOOKMARKS_H
diff --git a/src/plugins/bookmarks/images/bookmark.png b/src/plugins/bookmarks/images/bookmark.png
new file mode 100644
index 0000000000..7b2e5fd0ce
--- /dev/null
+++ b/src/plugins/bookmarks/images/bookmark.png
Binary files differ
diff --git a/src/plugins/cmakeprojectmanager/CMakeProject.mimetypes.xml b/src/plugins/cmakeprojectmanager/CMakeProject.mimetypes.xml
new file mode 100644
index 0000000000..d3c8f41b8d
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/CMakeProject.mimetypes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="text/x-cmake">
+ <sub-class-of type="text/plain"/>
+ <comment>CMake Project file</comment>
+ <glob pattern="CMakeLists.txt"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/cmakeprojectmanager/CMakeProjectManager.pluginspec b/src/plugins/cmakeprojectmanager/CMakeProjectManager.pluginspec
new file mode 100644
index 0000000000..84eefae0ee
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/CMakeProjectManager.pluginspec
@@ -0,0 +1,14 @@
+<plugin name="CMakeProjectManager" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>### TODO</license>
+ <description>CMake support</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="CppTools" version="0.9.1"/>
+ <dependency name="CppEditor" version="0.9.1"/>
+ <dependency name="Help" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
new file mode 100644
index 0000000000..2c98124bb9
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -0,0 +1,441 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cmakeproject.h"
+#include "cmakeprojectconstants.h"
+#include "cmakeprojectnodes.h"
+#include <extensionsystem/pluginmanager.h>
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <QtCore/QDebug>
+
+using namespace CMakeProjectManager;
+using namespace CMakeProjectManager::Internal;
+
+CMakeProject::CMakeProject(CMakeManager *manager, const QString &fileName)
+ : m_manager(manager), m_fileName(fileName), m_rootNode(new CMakeProjectNode(m_fileName))
+{
+ //TODO
+ m_file = new CMakeFile(this, fileName);
+ QDir dir = QFileInfo(m_fileName).absoluteDir();
+ QString cbpFile = findCbpFile(dir);
+ if (cbpFile.isEmpty())
+ cbpFile = createCbpFile(dir);
+ QList<ProjectExplorer::FileNode *> fileList;
+ QStringList includeFiles;
+ if (parseCbpFile(cbpFile, fileList, includeFiles)) {
+ buildTree(m_rootNode, fileList);
+ foreach(ProjectExplorer::FileNode *fn, fileList)
+ m_files.append(fn->path());
+ m_files.sort();
+
+ includeFiles.sort();
+ includeFiles.removeDuplicates();
+ CppTools::CppModelManagerInterface *modelmanager = ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
+ if (modelmanager) {
+ CppTools::CppModelManagerInterface::ProjectInfo *pinfo = modelmanager->projectInfo(this);
+ pinfo->includePaths = includeFiles;
+ pinfo->sourceFiles = m_files; // TODO we only want C++ files, not all other stuff that might be in the project
+ // TODO defines
+ }
+ } else {
+ // TODO report error
+ }
+}
+
+CMakeProject::~CMakeProject()
+{
+ delete m_rootNode;
+}
+
+QString CMakeProject::findCbpFile(const QDir &directory)
+{
+ // Find the cbp file
+ // TODO the cbp file is named like the project() command in the CMakeList.txt file
+ // so this method below could find the wrong cbp file, if the user changes the project()
+ // name
+ foreach(const QString &cbpFile , directory.entryList())
+ {
+ if (cbpFile.endsWith(".cbp")) {
+ return directory.path() + "/" + cbpFile;
+ }
+ }
+ return QString::null;
+}
+
+
+QString CMakeProject::createCbpFile(const QDir &)
+{
+ // TODO create a cbp file.
+ // Issue: Where to create it? We want to do that in the build directory
+ // but at this stage we don't know the build directory yet
+ // So create it in a temp directory?
+ // Issue: We want to reuse whatever CMakeCache.txt that is alread there, which
+ // would indicate, creating it in the build directory
+ // Or we could use a temp directory and use -C builddirectory
+ return QString::null;
+}
+
+bool CMakeProject::parseCbpFile(const QString &fileName, QList<ProjectExplorer::FileNode *> &fileList, QStringList &includeFiles)
+{
+ QFile fi(fileName);
+ if (fi.exists() && fi.open(QFile::ReadOnly)) {
+ QXmlStreamReader stream(&fi);
+
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.name() == "CodeBlocks_project_file") {
+ parseCodeBlocks_project_file(stream, fileList, includeFiles);
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+ fi.close();
+ return true;
+ }
+ return false;
+}
+
+void CMakeProject::parseCodeBlocks_project_file(QXmlStreamReader &stream, QList<ProjectExplorer::FileNode *> &fileList, QStringList &includeFiles)
+{
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.name() == "Project") {
+ parseProject(stream, fileList, includeFiles);
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+
+void CMakeProject::parseProject(QXmlStreamReader &stream, QList<ProjectExplorer::FileNode *> &fileList, QStringList &includeFiles)
+{
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.name() == "Unit") {
+ parseUnit(stream, fileList);
+ } else if (stream.name() == "Build") {
+ parseBuild(stream, includeFiles);
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+
+void CMakeProject::parseBuild(QXmlStreamReader &stream, QStringList &includeFiles)
+{
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.name() == "Target") {
+ parseTarget(stream, includeFiles);
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+
+void CMakeProject::parseTarget(QXmlStreamReader &stream, QStringList &includeFiles)
+{
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.name() == "Compiler") {
+ parseCompiler(stream, includeFiles);
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+
+void CMakeProject::parseCompiler(QXmlStreamReader &stream, QStringList &includeFiles)
+{
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.name() == "Add") {
+ parseAdd(stream, includeFiles);
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+
+void CMakeProject::parseAdd(QXmlStreamReader &stream, QStringList &includeFiles)
+{
+ includeFiles.append(stream.attributes().value("directory").toString());
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+
+void CMakeProject::parseUnit(QXmlStreamReader &stream, QList<ProjectExplorer::FileNode *> &fileList)
+{
+ //qDebug()<<stream.attributes().value("filename");
+ QString fileName = stream.attributes().value("filename").toString();
+ if (!fileName.endsWith(".rule"))
+ fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::SourceType, false));
+ while(!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isEndElement()) {
+ return;
+ } else if (stream.isStartElement()) {
+ parseUnknownElement(stream);
+ }
+ }
+}
+void CMakeProject::parseUnknownElement(QXmlStreamReader &stream)
+{
+ Q_ASSERT(stream.isStartElement());
+
+ while (!stream.atEnd()) {
+ stream.readNext();
+
+ if (stream.isEndElement())
+ break;
+
+ if (stream.isStartElement())
+ parseUnknownElement(stream);
+ }
+}
+
+void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list)
+{
+ //m_rootNode->addFileNodes(fileList, m_rootNode);
+ qSort(list.begin(), list.end(), ProjectExplorer::ProjectNode::sortNodesByPath);
+ foreach( ProjectExplorer::FileNode *fn, list) {
+ // Get relative path to rootNode
+ QString parentDir = QFileInfo(fn->path()).absolutePath();
+ ProjectExplorer::FolderNode *folder = findOrCreateFolder(rootNode, parentDir);
+ rootNode->addFileNodes(QList<ProjectExplorer::FileNode *>()<< fn, folder);
+ }
+ //m_rootNode->addFileNodes(list, rootNode);
+}
+
+ProjectExplorer::FolderNode *CMakeProject::findOrCreateFolder(CMakeProjectNode *rootNode, QString directory)
+{
+ QString relativePath = QDir(QFileInfo(rootNode->path()).path()).relativeFilePath(directory);
+ QStringList parts = relativePath.split("/");
+ ProjectExplorer::FolderNode *parent = rootNode;
+ foreach(const QString &part, parts) {
+ // Find folder in subFolders
+ bool found = false;
+ foreach(ProjectExplorer::FolderNode *folder, parent->subFolderNodes()) {
+ if (QFileInfo(folder->path()).fileName() == part) {
+ // yeah found something :)
+ parent = folder;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // No FolderNode yet, so create it
+ ProjectExplorer::FolderNode *tmp = new ProjectExplorer::FolderNode(part);
+ rootNode->addFolderNodes(QList<ProjectExplorer::FolderNode *>() << tmp, parent);
+ parent = tmp;
+ }
+ }
+ return parent;
+}
+
+QString CMakeProject::name() const
+{
+ // TODO
+ return "";
+}
+
+Core::IFile *CMakeProject::file() const
+{
+ return m_file;
+}
+
+ProjectExplorer::IProjectManager *CMakeProject::projectManager() const
+{
+ return m_manager;
+}
+
+QList<Core::IFile *> CMakeProject::dependencies()
+{
+ return QList<Core::IFile *>();
+}
+
+QList<ProjectExplorer::Project *> CMakeProject::dependsOn()
+{
+ return QList<Project *>();
+}
+
+bool CMakeProject::isApplication() const
+{
+ return true;
+}
+
+ProjectExplorer::Environment CMakeProject::environment(const QString &buildConfiguration) const
+{
+ Q_UNUSED(buildConfiguration)
+ //TODO
+ return ProjectExplorer::Environment::systemEnvironment();
+}
+
+QString CMakeProject::buildDirectory(const QString &buildConfiguration) const
+{
+ Q_UNUSED(buildConfiguration)
+ //TODO
+ return "";
+}
+
+ProjectExplorer::BuildStepConfigWidget *CMakeProject::createConfigWidget()
+{
+ return new CMakeBuildSettingsWidget;
+}
+
+QList<ProjectExplorer::BuildStepConfigWidget*> CMakeProject::subConfigWidgets()
+{
+ return QList<ProjectExplorer::BuildStepConfigWidget*>();
+}
+
+// This method is called for new build configurations
+// You should probably set some default values in this method
+ void CMakeProject::newBuildConfiguration(const QString &buildConfiguration)
+ {
+ Q_UNUSED(buildConfiguration);
+ //TODO
+ }
+
+ProjectExplorer::ProjectNode *CMakeProject::rootProjectNode() const
+{
+ return m_rootNode;
+}
+
+
+QStringList CMakeProject::files(FilesMode fileMode) const
+{
+ Q_UNUSED(fileMode);
+ // TODO
+ return m_files;
+}
+
+void CMakeProject::saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer)
+{
+ // TODO
+ Q_UNUSED(writer)
+}
+
+void CMakeProject::restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader &reader)
+{
+ // TODO
+ Q_UNUSED(reader)
+}
+
+
+CMakeFile::CMakeFile(CMakeProject *parent, QString fileName)
+ : Core::IFile(parent), m_project(parent), m_fileName(fileName)
+{
+
+}
+
+bool CMakeFile::save(const QString &fileName)
+{
+ // TODO
+ // Once we have an texteditor open for this file, we probably do
+ // need to implement this, don't we.
+ Q_UNUSED(fileName);
+ return false;
+}
+
+QString CMakeFile::fileName() const
+{
+ return m_fileName;
+}
+
+QString CMakeFile::defaultPath() const
+{
+ return QString();
+}
+
+QString CMakeFile::suggestedFileName() const
+{
+ return QString();
+}
+
+QString CMakeFile::mimeType() const
+{
+ return Constants::CMAKEMIMETYPE;
+}
+
+
+bool CMakeFile::isModified() const
+{
+ return false;
+}
+
+bool CMakeFile::isReadOnly() const
+{
+ return true;
+}
+
+bool CMakeFile::isSaveAsAllowed() const
+{
+ return false;
+}
+
+void CMakeFile::modified(ReloadBehavior *behavior)
+{
+ Q_UNUSED(behavior);
+}
+
+
+CMakeBuildSettingsWidget::CMakeBuildSettingsWidget()
+{
+
+}
+
+QString CMakeBuildSettingsWidget::displayName() const
+{
+ return "CMake";
+}
+
+void CMakeBuildSettingsWidget::init(const QString &buildConfiguration)
+{
+ Q_UNUSED(buildConfiguration);
+ // TODO
+}
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h
new file mode 100644
index 0000000000..b5a8d0b6b4
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CMAKEPROJECT_H
+#define CMAKEPROJECT_H
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectnodes.h>
+#include <projectexplorer/buildstep.h>
+#include <coreplugin/ifile.h>
+#include <QtCore/QXmlStreamReader>
+
+#include "cmakeprojectmanager.h"
+#include "cmakeprojectnodes.h"
+
+namespace CMakeProjectManager {
+namespace Internal{
+
+class CMakeFile;
+
+class CMakeProject : public ProjectExplorer::Project
+{
+ Q_OBJECT
+public:
+ CMakeProject(CMakeManager *manager, const QString &filename);
+ ~CMakeProject();
+
+ virtual QString name() const;
+ virtual Core::IFile *file() const;
+ virtual ProjectExplorer::IProjectManager *projectManager() const;
+
+ virtual QList<Core::IFile *> dependencies(); //NBS TODO remove
+ virtual QList<ProjectExplorer::Project *> dependsOn(); //NBS TODO implement dependsOn
+
+ virtual bool isApplication() const;
+
+ virtual ProjectExplorer::Environment environment(const QString &buildConfiguration) const;
+ virtual QString buildDirectory(const QString &buildConfiguration) const;
+
+ virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
+ virtual QList<ProjectExplorer::BuildStepConfigWidget*> subConfigWidgets();
+
+ // This method is called for new build configurations
+ // You should probably set some default values in this method
+ virtual void newBuildConfiguration(const QString &buildConfiguration);
+
+// // Returns the list of different views (such as "File View" or "Project View") the project supports.
+// virtual QStringList supportedModels() const = 0;
+//
+// // Returns the tree representing the requested view.
+// virtual QModelIndex model(const QString &modelId) const = 0;
+
+ virtual ProjectExplorer::ProjectNode *rootProjectNode() const;
+
+// // Conversion functions
+// virtual QModelIndex indexForNode(const Node *node, const QString &modelId) const = 0;
+// virtual Node *nodeForIndex(const QModelIndex &index) const = 0;
+// virtual Node *nodeForFile(const QString &filePath) const = 0;
+
+ virtual QStringList files(FilesMode fileMode) const;
+
+private:
+ QString findCbpFile(const QDir &);
+ QString createCbpFile(const QDir &);
+ bool parseCbpFile(const QString &fileName, QList<ProjectExplorer::FileNode *> &fileList, QStringList &includeFiles);
+ void parseCodeBlocks_project_file(QXmlStreamReader &stream, QList<ProjectExplorer::FileNode *> &fileList, QStringList &includeFiles);
+ void parseProject(QXmlStreamReader &stream, QList<ProjectExplorer::FileNode *> &fileList, QStringList &includeFiles);
+ void parseBuild(QXmlStreamReader &stream, QStringList &includeFiles);
+ void parseTarget(QXmlStreamReader &stream, QStringList &includeFiles);
+ void parseCompiler(QXmlStreamReader &stream, QStringList &includeFiles);
+ void parseAdd(QXmlStreamReader &stream, QStringList &includeFiles);
+ void parseUnit(QXmlStreamReader &stream, QList<ProjectExplorer::FileNode *> &fileList);
+ void parseUnknownElement(QXmlStreamReader &stream);
+ void buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list);
+ ProjectExplorer::FolderNode *findOrCreateFolder(CMakeProjectNode *rootNode, QString directory);
+
+
+ CMakeManager *m_manager;
+ QString m_fileName;
+ CMakeFile *m_file;
+
+ // TODO probably need a CMake specific node structure
+ CMakeProjectNode* m_rootNode;
+ QStringList m_files;
+
+protected:
+ virtual void saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer);
+ virtual void restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader &reader);
+
+};
+
+class CMakeFile : public Core::IFile
+{
+ Q_OBJECT
+public:
+ CMakeFile(CMakeProject *parent, QString fileName);
+
+ bool save(const QString &fileName = QString());
+ QString fileName() const;
+
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+ QString mimeType() const;
+
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+
+ void modified(ReloadBehavior *behavior);
+private:
+ CMakeProject *m_project;
+ QString m_fileName;
+};
+
+class CMakeBuildSettingsWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+public:
+ CMakeBuildSettingsWidget();
+ virtual QString displayName() const;
+
+ // This is called to set up the config widget before showing it
+ // buildConfiguration is QString::null for the non buildConfiguration specific page
+ virtual void init(const QString &buildConfiguration);
+};
+
+}
+}
+
+#endif // CMAKEPROJECT_H
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.qrc b/src/plugins/cmakeprojectmanager/cmakeproject.qrc
new file mode 100644
index 0000000000..e9ae51f460
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/cmakeproject" >
+ <file>CMakeProject.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
new file mode 100644
index 0000000000..02c76f6682
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CMAKEPROJECTCONSTANTS_H
+#define CMAKEPROJECTCONSTANTS_H
+
+namespace CMakeProjectManager {
+namespace Constants {
+
+const char * const PROJECTCONTEXT = "CMakeProject.ProjectContext";
+const char * const CMAKEMIMETYPE = "text/x-cmake"; // TOOD check that this is correct
+
+}
+}
+
+#endif // CMAKEPROJECTCONSTANTS_H
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
new file mode 100644
index 0000000000..4a179967cc
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cmakeprojectmanager.h"
+#include "cmakeprojectconstants.h"
+#include "cmakeproject.h"
+#include "cmakeprojectconstants.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
+
+using namespace CMakeProjectManager::Internal;
+
+CMakeManager::CMakeManager()
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ m_projectContext = core->uniqueIDManager()->uniqueIdentifier(CMakeProjectManager::Constants::PROJECTCONTEXT);
+ m_projectLanguage = core->uniqueIDManager()->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
+}
+
+int CMakeManager::projectContext() const
+{
+ return m_projectContext;
+}
+
+int CMakeManager::projectLanguage() const
+{
+ return m_projectLanguage;
+}
+
+ProjectExplorer::Project *CMakeManager::openProject(const QString &fileName)
+{
+ // TODO check wheter this project is already opened
+ return new CMakeProject(this, fileName);
+}
+
+QString CMakeManager::mimeType() const
+{
+ return Constants::CMAKEMIMETYPE;
+}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h
new file mode 100644
index 0000000000..3808b72efb
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CMAKEPROJECTMANAGER_H
+#define CMAKEPROJECTMANAGER_H
+
+#include <projectexplorer/iprojectmanager.h>
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class CMakeManager : public ProjectExplorer::IProjectManager
+{
+ Q_OBJECT
+public:
+ CMakeManager();
+
+ virtual int projectContext() const;
+ virtual int projectLanguage() const;
+
+ //virtual bool canOpenProject(const QString &fileName);
+ virtual ProjectExplorer::Project *openProject(const QString &fileName);
+ virtual QString mimeType() const;
+ //virtual QString fileFilter() const;
+private:
+ int m_projectContext;
+ int m_projectLanguage;
+};
+}
+}
+#endif // CMAKEPROJECTMANAGER_H
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
new file mode 100644
index 0000000000..d7825c8167
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
@@ -0,0 +1,14 @@
+TEMPLATE = lib
+TARGET = CMakeProjectManager
+include(../../qworkbenchplugin.pri)
+include(cmakeprojectmanager_dependencies.pri)
+HEADERS = cmakeproject.h \
+ cmakeprojectplugin.h \
+ cmakeprojectmanager.h \
+ cmakeprojectconstants.h \
+ cmakeprojectnodes.h
+SOURCES = cmakeproject.cpp \
+ cmakeprojectplugin.cpp \
+ cmakeprojectmanager.cpp \
+ cmakeprojectnodes.cpp
+RESOURCES += cmakeproject.qrc
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager_dependencies.pri b/src/plugins/cmakeprojectmanager/cmakeprojectmanager_dependencies.pri
new file mode 100644
index 0000000000..80118ad122
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager_dependencies.pri
@@ -0,0 +1,4 @@
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/cpptools/cpptools.pri)
+include(../../plugins/cppeditor/cppeditor.pri)
+include(../../plugins/texteditor/texteditor.pri)
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
new file mode 100644
index 0000000000..338750158f
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cmakeprojectnodes.h"
+
+using namespace CMakeProjectManager;
+using namespace CMakeProjectManager::Internal;
+
+CMakeProjectNode::CMakeProjectNode(const QString &fileName)
+ : ProjectExplorer::ProjectNode(fileName)
+{
+}
+
+bool CMakeProjectNode::hasTargets() const
+{
+ // TODO
+ return true;
+}
+
+QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions() const
+{
+ return QList<ProjectAction>();
+}
+
+bool CMakeProjectNode::addSubProjects(const QStringList &proFilePaths)
+{
+ Q_UNUSED(proFilePaths);
+ return false;
+}
+
+bool CMakeProjectNode::removeSubProjects(const QStringList &proFilePaths)
+{
+ Q_UNUSED(proFilePaths);
+ return false;
+}
+
+bool CMakeProjectNode::addFiles(const ProjectExplorer::FileType fileType, const QStringList &filePaths, QStringList *notAdded)
+{
+ Q_UNUSED(fileType);
+ Q_UNUSED(filePaths);
+ Q_UNUSED(notAdded);
+ return false;
+}
+
+// TODO: Maybe remove fileType, can be detected by project
+bool CMakeProjectNode::removeFiles(const ProjectExplorer::FileType fileType, const QStringList &filePaths, QStringList *notRemoved)
+{
+ Q_UNUSED(fileType);
+ Q_UNUSED(filePaths);
+ Q_UNUSED(notRemoved);
+ return false;
+}
+
+bool CMakeProjectNode::renameFile(const ProjectExplorer::FileType fileType, const QString &filePath, const QString &newFilePath)
+{
+ Q_UNUSED(fileType);
+ Q_UNUSED(filePath);
+ Q_UNUSED(newFilePath);
+ return false;
+}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
new file mode 100644
index 0000000000..a0a9453a47
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CMAKEPROJECTNODE_H
+#define CMAKEPROJECTNODE_H
+
+#include <projectexplorer/projectnodes.h>
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class CMakeProjectNode : public ProjectExplorer::ProjectNode
+{
+public:
+ CMakeProjectNode(const QString &fileName);
+ virtual bool hasTargets() const;
+ virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+ virtual bool addSubProjects(const QStringList &proFilePaths);
+ virtual bool removeSubProjects(const QStringList &proFilePaths);
+ virtual bool addFiles(const ProjectExplorer::FileType fileType,
+ const QStringList &filePaths,
+ QStringList *notAdded = 0);
+ virtual bool removeFiles(const ProjectExplorer::FileType fileType,
+ const QStringList &filePaths,
+ QStringList *notRemoved = 0);
+ virtual bool renameFile(const ProjectExplorer::FileType fileType,
+ const QString &filePath,
+ const QString &newFilePath);
+
+ // TODO is protected in base class, and that's correct
+ using ProjectNode::addFileNodes;
+ using ProjectNode::addFolderNodes;
+};
+}
+}
+
+#endif // CMAKEPROJECTNODE_H
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
new file mode 100644
index 0000000000..45c8c5d213
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cmakeprojectplugin.h"
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+
+#include "cmakeprojectmanager.h"
+
+using namespace CMakeProjectManager::Internal;
+
+CMakeProjectPlugin::CMakeProjectPlugin()
+{
+}
+
+CMakeProjectPlugin::~CMakeProjectPlugin()
+{
+}
+
+bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ QString errorMessage;
+ core->mimeDatabase()->addMimeTypes(QLatin1String(":cmakeproject/CMakeProject.mimetypes.xml"), &errorMessage);
+ addAutoReleasedObject(new CMakeManager());
+ return true;
+}
+
+void CMakeProjectPlugin::extensionsInitialized()
+{
+
+}
+
+Q_EXPORT_PLUGIN(CMakeProjectPlugin)
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h
new file mode 100644
index 0000000000..0620220667
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CMAKEPROJECTPLUGIN_H
+#define CMAKEPROJECTPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class CMakeProjectPlugin
+ : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ CMakeProjectPlugin();
+ ~CMakeProjectPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+
+ void extensionsInitialized();
+
+
+private:
+};
+
+} // namespace Internal
+} // namespace CMakeProject
+
+#endif // CMAKEPROJECTPLUGIN_H
diff --git a/src/plugins/coreplugin/Core.pluginspec b/src/plugins/coreplugin/Core.pluginspec
new file mode 100644
index 0000000000..28b9067ed2
--- /dev/null
+++ b/src/plugins/coreplugin/Core.pluginspec
@@ -0,0 +1,7 @@
+<plugin name="Core" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>The core plugin for the Qt IDE.</description>
+ <url>http://www.trolltech.com/</url>
+</plugin>
diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
new file mode 100644
index 0000000000..ab30677a62
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
@@ -0,0 +1,696 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "actioncontainer.h"
+#include "command.h"
+#include "coreimpl.h"
+
+#include "coreconstants.h"
+#include "uniqueidmanager.h"
+
+#include <QtCore/QDebug>
+#include <QtGui/QAction>
+#include <QtGui/QToolBar>
+#include <QtGui/QMenuBar>
+
+Q_DECLARE_METATYPE(Core::Internal::MenuActionContainer*)
+
+using namespace Core;
+using namespace Core::Internal;
+
+/*!
+ \class IActionContainer
+ \mainclass
+ \ingroup qwb
+ \inheaderfile iactioncontainer.h
+
+ \brief The class...
+
+ The Action Container interface...
+*/
+
+/*!
+ \enum IActionContainer::ContainerType
+*/
+
+/*!
+ \enum IActionContainer::EmptyAction
+*/
+
+/*!
+ \fn virtual IActionContainer::setEmptyAction(EmptyAction ea)
+*/
+
+/*!
+ \fn virtual int IActionContainer::id() const
+*/
+
+/*!
+ \fn virtual ContainerType IActionContainer::type() const
+*/
+
+/*!
+ \fn virtual QMenu *IActionContainer::menu() const
+*/
+
+/*!
+ \fn virtual QToolBar *IActionContainer::toolBar() const
+*/
+
+/*!
+ \fn virtual QMenuBar *IActionContainer::menuBar() const
+*/
+
+/*!
+ \fn virtual QAction *IActionContainer::insertLocation(const QString &group) const
+*/
+
+/*!
+ \fn virtual void IActionContainer::appendGroup(const QString &group, bool global)
+*/
+
+/*!
+ \fn virtual void IActionContainer::addAction(Core::ICommand *action, const QString &group)
+*/
+
+/*!
+ \fn virtual void IActionContainer::addMenu(Core::IActionContainer *menu, const QString &group)
+*/
+
+/*!
+ \fn virtual bool IActionContainer::update()
+*/
+
+/*!
+ \fn virtual IActionContainer::~IActionContainer()
+*/
+
+// ---------- ActionContainer ------------
+
+/*!
+ \class ActionContainer
+ \ingroup qwb
+ \inheaderfile actioncontainer.h
+*/
+
+/*!
+ \enum ActionContainer::ContainerState
+*/
+
+/*!
+\fn ActionContainer::ActionContainer(ContainerType type, int id)
+*/
+ActionContainer::ActionContainer(ContainerType type, int id)
+ : m_data(CS_None), m_type(type), m_id(id)
+{
+
+}
+
+/*!
+ \fn virtual ActionContainer::~ActionContainer()
+*/
+
+/*!
+ ...
+*/
+void ActionContainer::setEmptyAction(EmptyAction ea)
+{
+ m_data = ((m_data & ~EA_Mask) | ea);
+}
+
+/*!
+ ...
+*/
+bool ActionContainer::hasEmptyAction(EmptyAction ea) const
+{
+ return (m_data & EA_Mask) == ea;
+}
+
+/*!
+ ...
+*/
+void ActionContainer::setState(ContainerState state)
+{
+ m_data |= state;
+}
+
+/*!
+ ...
+*/
+bool ActionContainer::hasState(ContainerState state) const
+{
+ return (m_data & state);
+}
+
+/*!
+ ...
+*/
+void ActionContainer::appendGroup(const QString &group, bool global)
+{
+ UniqueIDManager *idmanager = CoreImpl::instance()->uniqueIDManager();
+ int gid = idmanager->uniqueIdentifier(group);
+ m_groups << gid;
+ if (global)
+ ActionManager::instance()->registerGlobalGroup(gid, m_id);
+}
+
+/*!
+ ...
+*/
+QAction *ActionContainer::insertLocation(const QString &group) const
+{
+ UniqueIDManager *idmanager = CoreImpl::instance()->uniqueIDManager();
+ int grpid = idmanager->uniqueIdentifier(group);
+ int prevKey = 0;
+ int pos = ((grpid << 16) | 0xFFFF);
+ return beforeAction(pos, &prevKey);
+}
+
+/*!
+\fn virtual void ActionContainer::insertAction(QAction *before, QAction *action) = 0
+*/
+
+/*!
+\fn virtual void ActionContainer::insertMenu(QAction *before, QMenu *menu) = 0
+*/
+
+/*!
+\fn QList<ICommand *> ActionContainer::commands() const
+*/
+
+/*!
+\fn QList<IActionContainer *> ActionContainer::subContainers() const
+*/
+
+/*!
+ ...
+*/
+void ActionContainer::addAction(ICommand *action, const QString &group)
+{
+ if (!canAddAction(action))
+ return;
+
+ ActionManager *am = ActionManager::instance();
+ Action *a = static_cast<Action *>(action);
+ if (a->stateFlags() & Command::CS_PreLocation) {
+ QList<CommandLocation> locs = a->locations();
+ for (int i=0; i<locs.size(); ++i) {
+ if (IActionContainer *aci = am->actionContainer(locs.at(i).m_container)) {
+ ActionContainer *ac = static_cast<ActionContainer *>(aci);
+ ac->addAction(action, locs.at(i).m_position, false);
+ }
+ }
+ a->setStateFlags(a->stateFlags() | Command::CS_Initialized);
+ } else {
+ UniqueIDManager *idmanager = CoreImpl::instance()->uniqueIDManager();
+ int grpid = idmanager->uniqueIdentifier(Constants::G_DEFAULT_TWO);
+ if (!group.isEmpty())
+ grpid = idmanager->uniqueIdentifier(group);
+ if (!m_groups.contains(grpid) && !am->defaultGroups().contains(grpid))
+ qWarning() << "*** addAction(): Unknown group: " << group;
+ int pos = ((grpid << 16) | 0xFFFF);
+ addAction(action, pos, true);
+ }
+}
+
+/*!
+ ...
+*/
+void ActionContainer::addMenu(IActionContainer *menu, const QString &group)
+{
+ if (!canAddMenu(menu))
+ return;
+
+ ActionManager *am = ActionManager::instance();
+ MenuActionContainer *mc = static_cast<MenuActionContainer *>(menu);
+ if (mc->hasState(ActionContainer::CS_PreLocation)) {
+ CommandLocation loc = mc->location();
+ if (IActionContainer *aci = am->actionContainer(loc.m_container)) {
+ ActionContainer *ac = static_cast<ActionContainer *>(aci);
+ ac->addMenu(menu, loc.m_position, false);
+ }
+ mc->setState(ActionContainer::CS_Initialized);
+ } else {
+ UniqueIDManager *idmanager = CoreImpl::instance()->uniqueIDManager();
+ int grpid = idmanager->uniqueIdentifier(Constants::G_DEFAULT_TWO);
+ if (!group.isEmpty())
+ grpid = idmanager->uniqueIdentifier(group);
+ if (!m_groups.contains(grpid) && !am->defaultGroups().contains(grpid))
+ qWarning() << "*** addMenu(): Unknown group: " << group;
+ int pos = ((grpid << 16) | 0xFFFF);
+ addMenu(menu, pos, true);
+ }
+}
+
+/*!
+ ...
+*/
+int ActionContainer::id() const
+{
+ return m_id;
+}
+
+/*!
+ ...
+*/
+IActionContainer::ContainerType ActionContainer::type() const
+{
+ return m_type;
+}
+
+/*!
+ ...
+*/
+QMenu *ActionContainer::menu() const
+{
+ return 0;
+}
+
+/*!
+ ...
+*/
+QToolBar *ActionContainer::toolBar() const
+{
+ return 0;
+}
+
+/*!
+ ...
+*/
+QMenuBar *ActionContainer::menuBar() const
+{
+ return 0;
+}
+
+/*!
+ ...
+*/
+bool ActionContainer::canAddAction(ICommand *action) const
+{
+ if (action->type() != ICommand::CT_OverridableAction)
+ return false;
+
+ Command *cmd = static_cast<Command *>(action);
+ if (cmd->stateFlags() & Command::CS_Initialized)
+ return false;
+
+ return true;
+}
+
+/*!
+ ...
+*/
+bool ActionContainer::canAddMenu(IActionContainer *menu) const
+{
+ if (menu->type() != IActionContainer::CT_Menu)
+ return false;
+
+ ActionContainer *container = static_cast<ActionContainer *>(menu);
+ if (container->hasState(ActionContainer::CS_Initialized))
+ return false;
+
+ return true;
+}
+
+/*!
+ ...
+*/
+void ActionContainer::addAction(ICommand *action, int pos, bool setpos)
+{
+ Action *a = static_cast<Action *>(action);
+
+ int prevKey = 0;
+ QAction *ba = beforeAction(pos, &prevKey);
+
+ if (setpos) {
+ pos = calcPosition(pos, prevKey);
+ CommandLocation loc;
+ loc.m_container = m_id;
+ loc.m_position = pos;
+ QList<CommandLocation> locs = a->locations();
+ locs.append(loc);
+ a->setLocations(locs);
+ }
+
+ m_commands.append(action);
+ m_posmap.insert(pos, action->id());
+ insertAction(ba, a->action());
+}
+
+/*!
+ ...
+*/
+void ActionContainer::addMenu(IActionContainer *menu, int pos, bool setpos)
+{
+ MenuActionContainer *mc = static_cast<MenuActionContainer *>(menu);
+
+ int prevKey = 0;
+ QAction *ba = beforeAction(pos, &prevKey);
+
+ if (setpos) {
+ pos = calcPosition(pos, prevKey);
+ CommandLocation loc;
+ loc.m_container = m_id;
+ loc.m_position = pos;
+ mc->setLocation(loc);
+ }
+
+ m_subContainers.append(menu);
+ m_posmap.insert(pos, menu->id());
+ insertMenu(ba, mc->menu());
+}
+
+/*!
+ ...
+ \internal
+*/
+QAction *ActionContainer::beforeAction(int pos, int *prevKey) const
+{
+ ActionManager *am = ActionManager::instance();
+
+ int baId = -1;
+
+ (*prevKey) = -1;
+
+ QMap<int, int>::const_iterator i = m_posmap.constBegin();
+ while (i != m_posmap.constEnd()) {
+ if (i.key() > pos) {
+ baId = i.value();
+ break;
+ }
+ (*prevKey) = i.key();
+ ++i;
+ }
+
+ if (baId == -1)
+ return 0;
+
+ if (ICommand *cmd = am->command(baId))
+ return cmd->action();
+ if (IActionContainer *container = am->actionContainer(baId))
+ if (QMenu *menu = container->menu())
+ return menu->menuAction();
+
+ return 0;
+}
+
+/*!
+ ...
+ \internal
+*/
+int ActionContainer::calcPosition(int pos, int prevKey) const
+{
+ int grp = (pos & 0xFFFF0000);
+ if (prevKey == -1)
+ return grp;
+
+ int prevgrp = (prevKey & 0xFFFF0000);
+
+ if (grp != prevgrp)
+ return grp;
+
+ return grp + (prevKey & 0xFFFF) + 10;
+}
+
+// ---------- MenuActionContainer ------------
+
+/*!
+ \class MenuActionContainer
+ \ingroup qwb
+ \inheaderfile actioncontainer.h
+*/
+
+/*!
+ ...
+*/
+MenuActionContainer::MenuActionContainer(int id)
+ : ActionContainer(CT_Menu, id), m_menu(0)
+{
+ setEmptyAction(EA_Disable);
+}
+
+/*!
+ ...
+*/
+void MenuActionContainer::setMenu(QMenu *menu)
+{
+ m_menu = menu;
+
+ QVariant v;
+ qVariantSetValue<MenuActionContainer*>(v, this);
+
+ m_menu->menuAction()->setData(v);
+}
+
+/*!
+ ...
+*/
+QMenu *MenuActionContainer::menu() const
+{
+ return m_menu;
+}
+
+/*!
+ ...
+*/
+void MenuActionContainer::insertAction(QAction *before, QAction *action)
+{
+ m_menu->insertAction(before, action);
+}
+
+/*!
+ ...
+*/
+void MenuActionContainer::insertMenu(QAction *before, QMenu *menu)
+{
+ m_menu->insertMenu(before, menu);
+}
+
+/*!
+ ...
+*/
+void MenuActionContainer::setLocation(const CommandLocation &location)
+{
+ m_location = location;
+}
+
+/*!
+ ...
+*/
+CommandLocation MenuActionContainer::location() const
+{
+ return m_location;
+}
+
+/*!
+ ...
+*/
+bool MenuActionContainer::update()
+{
+ if (hasEmptyAction(EA_None))
+ return true;
+
+ bool hasitems = false;
+
+ foreach (IActionContainer *container, subContainers()) {
+ if (container == this) {
+ qWarning() << Q_FUNC_INFO << "container" << (this->menu() ? this->menu()->title() : "") << "contains itself as subcontainer";
+ continue;
+ }
+ if (container->update()) {
+ hasitems = true;
+ break;
+ }
+ }
+ if (!hasitems) {
+ foreach (ICommand *command, commands()) {
+ if (command->isActive()) {
+ hasitems = true;
+ break;
+ }
+ }
+ }
+
+ if (hasEmptyAction(EA_Hide))
+ m_menu->setVisible(hasitems);
+ else if (hasEmptyAction(EA_Disable))
+ m_menu->setEnabled(hasitems);
+
+ return hasitems;
+}
+
+// ---------- ToolBarActionContainer ------------
+
+/*!
+ \class ToolBarActionContainer
+ \ingroup qwb
+ \inheaderfile actioncontainer.h
+*/
+
+/*!
+ ...
+*/
+ToolBarActionContainer::ToolBarActionContainer(int id)
+ : ActionContainer(CT_ToolBar, id), m_toolBar(0)
+{
+ setEmptyAction(EA_None);
+}
+
+/*!
+ ...
+*/
+void ToolBarActionContainer::setToolBar(QToolBar *toolBar)
+{
+ m_toolBar = toolBar;
+}
+
+/*!
+ ...
+*/
+QToolBar *ToolBarActionContainer::toolBar() const
+{
+ return m_toolBar;
+}
+
+/*!
+ ...
+*/
+void ToolBarActionContainer::insertAction(QAction *before, QAction *action)
+{
+ m_toolBar->insertAction(before, action);
+}
+
+/*!
+ ...
+*/
+void ToolBarActionContainer::insertMenu(QAction *, QMenu *)
+{
+ // not implemented
+}
+
+/*!
+ ...
+*/
+bool ToolBarActionContainer::update()
+{
+ if (hasEmptyAction(EA_None))
+ return true;
+
+ bool hasitems = false;
+ foreach (ICommand *command, commands()) {
+ if (command->isActive()) {
+ hasitems = true;
+ break;
+ }
+ }
+
+ if (hasEmptyAction(EA_Hide))
+ m_toolBar->setVisible(hasitems);
+ else if (hasEmptyAction(EA_Disable))
+ m_toolBar->setEnabled(hasitems);
+
+ return hasitems;
+}
+
+// ---------- MenuBarActionContainer ------------
+
+/*!
+ \class MenuBarActionContainer
+ \ingroup qwb
+ \inheaderfile actioncontainer.h
+*/
+
+/*!
+ ...
+*/
+MenuBarActionContainer::MenuBarActionContainer(int id)
+ : ActionContainer(CT_ToolBar, id), m_menuBar(0)
+{
+ setEmptyAction(EA_None);
+}
+
+/*!
+ ...
+*/
+void MenuBarActionContainer::setMenuBar(QMenuBar *menuBar)
+{
+ m_menuBar = menuBar;
+}
+
+/*!
+ ...
+*/
+QMenuBar *MenuBarActionContainer::menuBar() const
+{
+ return m_menuBar;
+}
+
+/*!
+ ...
+*/
+void MenuBarActionContainer::insertAction(QAction *before, QAction *action)
+{
+ m_menuBar->insertAction(before, action);
+}
+
+/*!
+ ...
+*/
+void MenuBarActionContainer::insertMenu(QAction *before, QMenu *menu)
+{
+ m_menuBar->insertMenu(before, menu);
+}
+
+/*!
+ ...
+*/
+bool MenuBarActionContainer::update()
+{
+ if (hasEmptyAction(EA_None))
+ return true;
+
+ bool hasitems = false;
+ QList<QAction *> actions = m_menuBar->actions();
+ for (int i=0; i<actions.size(); ++i) {
+ if (actions.at(i)->isVisible()) {
+ hasitems = true;
+ break;
+ }
+ }
+
+ if (hasEmptyAction(EA_Hide))
+ m_menuBar->setVisible(hasitems);
+ else if (hasEmptyAction(EA_Disable))
+ m_menuBar->setEnabled(hasitems);
+
+ return hasitems;
+}
diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.h b/src/plugins/coreplugin/actionmanager/actioncontainer.h
new file mode 100644
index 0000000000..8f629410a4
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer.h
@@ -0,0 +1,157 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ACTIONCONTAINER_H
+#define ACTIONCONTAINER_H
+
+#include "actionmanager.h"
+
+#include <coreplugin/actionmanager/iactioncontainer.h>
+#include <coreplugin/actionmanager/icommand.h>
+
+namespace Core {
+namespace Internal {
+
+class ActionContainer : public Core::IActionContainer
+{
+public:
+ enum ContainerState {
+ CS_None = 0x000000,
+ CS_Initialized = 0x010000,
+ CS_PreLocation = 0x020000,
+ CS_UserDefined = 0x040000
+ };
+
+ ActionContainer(ContainerType type, int id);
+ virtual ~ActionContainer() {}
+
+ void setEmptyAction(EmptyAction ea);
+ bool hasEmptyAction(EmptyAction ea) const;
+
+ void setState(ContainerState state);
+ bool hasState(ContainerState state) const;
+
+ QAction *insertLocation(const QString &group) const;
+ void appendGroup(const QString &group, bool global = false);
+ void addAction(ICommand *action, const QString &group = QString());
+ void addMenu(IActionContainer *menu, const QString &group = QString());
+
+ int id() const;
+ ContainerType type() const;
+
+ QMenu *menu() const;
+ QToolBar *toolBar() const;
+ QMenuBar *menuBar() const;
+
+ virtual void insertAction(QAction *before, QAction *action) = 0;
+ virtual void insertMenu(QAction *before, QMenu *menu) = 0;
+
+ QList<ICommand *> commands() const { return m_commands; }
+ QList<IActionContainer *> subContainers() const { return m_subContainers; }
+protected:
+ bool canAddAction(ICommand *action) const;
+ bool canAddMenu(IActionContainer *menu) const;
+
+ void addAction(ICommand *action, int pos, bool setpos);
+ void addMenu(IActionContainer *menu, int pos, bool setpos);
+
+private:
+ QAction *beforeAction(int pos, int *prevKey) const;
+ int calcPosition(int pos, int prevKey) const;
+
+ QList<int> m_groups;
+ int m_data;
+ ContainerType m_type;
+ int m_id;
+ QMap<int, int> m_posmap;
+ QList<IActionContainer *> m_subContainers;
+ QList<ICommand *> m_commands;
+};
+
+class MenuActionContainer : public ActionContainer
+{
+public:
+ MenuActionContainer(int id);
+
+ void setMenu(QMenu *menu);
+ QMenu *menu() const;
+
+ void setLocation(const CommandLocation &location);
+ CommandLocation location() const;
+
+ void insertAction(QAction *before, QAction *action);
+ void insertMenu(QAction *before, QMenu *menu);
+ bool update();
+
+private:
+ QMenu *m_menu;
+ CommandLocation m_location;
+};
+
+class ToolBarActionContainer : public ActionContainer
+{
+public:
+ ToolBarActionContainer(int id);
+
+ void setToolBar(QToolBar *toolBar);
+ QToolBar *toolBar() const;
+
+ void insertAction(QAction *before, QAction *action);
+ void insertMenu(QAction *before, QMenu *menu);
+ bool update();
+
+private:
+ QToolBar *m_toolBar;
+};
+
+class MenuBarActionContainer : public ActionContainer
+{
+public:
+ MenuBarActionContainer(int id);
+
+ void setMenuBar(QMenuBar *menuBar);
+ QMenuBar *menuBar() const;
+
+ void insertAction(QAction *before, QAction *action);
+ void insertMenu(QAction *before, QMenu *menu);
+ bool update();
+
+private:
+ QMenuBar *m_menuBar;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //ACTIONCONTAINER_H
+
+
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
new file mode 100644
index 0000000000..f218a84c73
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
@@ -0,0 +1,560 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "actionmanager.h"
+#include "mainwindow.h"
+#include "actioncontainer.h"
+#include "command.h"
+#include "uniqueidmanager.h"
+
+#include <coreplugin/coreconstants.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QShortcut>
+#include <QtGui/QToolBar>
+#include <QtGui/QMenuBar>
+
+namespace {
+ enum { warnAboutFindFailures = 0 };
+}
+
+/*!
+ \class Core::ActionManagerInterface
+ \mainclass
+ \ingroup qwb
+ \inheaderfile actionmanagerinterface.h
+
+ \brief All actions should be registered in the ActionManager, since this enables the user to
+ e.g. change their shortcuts at a central place.
+
+ The ActionManagerInterface is the central bookkeeper of actions and their shortcuts and layout.
+ You get the only implementation of this class from the core interface (ICore::actionManager()).
+
+ The main reasons for the need of this class is to provide a central place where the user
+ can specify all his keyboard shortcuts, and to provide a solution for actions that should
+ behave differently in different contexts (like the copy/replace/undo/redo actions).
+
+ All actions that are registered with the same string id (but different context lists)
+ are considered to be overloads of the same command. The action that is visible to the user
+ is the one returned by ICommand::action(). (If you provide yourself a user visible
+ representation of your action be sure to always use ICommand::action() for this.)
+ If this action is invoked by the user, the signal is forwarded to the registered action that
+ is valid for the current context.
+
+ You use this class also to add items to registered
+ action containers like the applications menu bar. For this you register your action via the
+ registerAction methods, get the action container for a specific id (like specified in
+ Core::Constants) with a call of
+ actionContainer(const QString&) and add your command to this container.
+
+ Guidelines:
+ \list
+ \o Always register your actions and shortcuts!
+ \o When registering an action with cmd=registerAction(action, id, contexts) be sure to connect
+ your own action connect(action, SIGNAL...) but make cmd->action() visible to the user, i.e.
+ widget->addAction(cmd->action()).
+ \o Use this class to add actions to the applications menus
+ \endlist
+
+ \sa Core::ICore, Core::ICommand
+ \sa Core::IActionContainer
+*/
+
+/*!
+ \fn virtual IActionContainer *ActionManagerInterface::createMenu(const QString &id) = 0
+ ...
+*/
+
+/*!
+ \fn virtual IActionContainer *ActionManagerInterface::createMenuBar(const QString &id) = 0
+ ...
+*/
+
+/*!
+ \fn virtual ICommand *ActionManagerInterface::registerAction(QAction *action, const QString &id, const QList<int> &context) = 0
+ ...
+*/
+
+/*!
+ \fn virtual ICommand *ActionManagerInterface::registerShortcut(QShortcut *shortcut, const QString &id, const QList<int> &context) = 0
+ ...
+*/
+
+/*!
+ \fn virtual ICommand *ActionManagerInterface::registerAction(QAction *action, const QString &id) = 0
+ ...
+*/
+
+/*!
+ \fn virtual void ActionManagerInterface::addAction(ICommand *action, const QString &globalGroup) = 0
+ ...
+*/
+
+/*!
+ \fn virtual void ActionManagerInterface::addMenu(IActionContainer *menu, const QString &globalGroup) = 0
+ ...
+*/
+
+/*!
+ \fn virtual ICommand *ActionManagerInterface::command(const QString &id) const = 0
+ ...
+*/
+
+/*!
+ \fn virtual IActionContainer *ActionManagerInterface::actionContainer(const QString &id) const = 0
+ ...
+*/
+
+/*!
+ \fn virtual ActionManagerInterface::~ActionManagerInterface()
+ ...
+*/
+
+using namespace Core;
+using namespace Core::Internal;
+
+ActionManager* ActionManager::m_instance = 0;
+
+/*!
+ \class ActionManager
+ \ingroup qwb
+ \inheaderfile actionmanager.h
+
+ \sa ActionContainer
+*/
+
+/*!
+ ...
+*/
+ActionManager::ActionManager(MainWindow *mainWnd, UniqueIDManager *uidmgr) :
+ ActionManagerInterface(mainWnd),
+ m_mainWnd(mainWnd)
+{
+ m_defaultGroups << uidmgr->uniqueIdentifier(Constants::G_DEFAULT_ONE);
+ m_defaultGroups << uidmgr->uniqueIdentifier(Constants::G_DEFAULT_TWO);
+ m_defaultGroups << uidmgr->uniqueIdentifier(Constants::G_DEFAULT_THREE);
+ m_instance = this;
+
+}
+
+/*!
+ ...
+*/
+ActionManager::~ActionManager()
+{
+ qDeleteAll(m_idCmdMap.values());
+ qDeleteAll(m_idContainerMap.values());
+}
+
+/*!
+ ...
+*/
+ActionManager* ActionManager::instance()
+{
+ return m_instance;
+}
+
+/*!
+ ...
+*/
+QList<int> ActionManager::defaultGroups() const
+{
+ return m_defaultGroups;
+}
+
+/*!
+ ...
+*/
+QList<Command *> ActionManager::commands() const
+{
+ return m_idCmdMap.values();
+}
+
+/*!
+ ...
+*/
+QList<ActionContainer *> ActionManager::containers() const
+{
+ return m_idContainerMap.values();
+}
+
+/*!
+ ...
+*/
+void ActionManager::registerGlobalGroup(int groupId, int containerId)
+{
+ if (m_globalgroups.contains(groupId)) {
+ qWarning() << "registerGlobalGroup: Global group "
+ << m_mainWnd->uniqueIDManager()->stringForUniqueIdentifier(groupId)
+ << " already registered";
+ } else {
+ m_globalgroups.insert(groupId, containerId);
+ }
+}
+
+/*!
+ ...
+*/
+bool ActionManager::hasContext(int context) const
+{
+ return m_context.contains(context);
+}
+
+/*!
+ ...
+*/
+void ActionManager::setContext(const QList<int> &context)
+{
+ // here are possibilities for speed optimization if necessary:
+ // let commands (de-)register themselves for contexts
+ // and only update commands that are either in old or new contexts
+ m_context = context;
+ const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd();
+ for (IdCmdMap::const_iterator it = m_idCmdMap.constBegin(); it != cmdcend; ++it)
+ it.value()->setCurrentContext(m_context);
+
+ const IdContainerMap::const_iterator acend = m_idContainerMap.constEnd();
+ for ( IdContainerMap::const_iterator it = m_idContainerMap.constBegin(); it != acend; ++it)
+ it.value()->update();
+}
+
+/*!
+ \internal
+*/
+bool ActionManager::hasContext(QList<int> context) const
+{
+ for (int i=0; i<m_context.count(); ++i) {
+ if (context.contains(m_context.at(i)))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ ...
+*/
+IActionContainer *ActionManager::createMenu(const QString &id)
+{
+ const int uid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(id);
+ const IdContainerMap::const_iterator it = m_idContainerMap.constFind(uid);
+ if (it != m_idContainerMap.constEnd())
+ return it.value();
+
+ QMenu *m = new QMenu(m_mainWnd);
+ m->setObjectName(id);
+
+ MenuActionContainer *mc = new MenuActionContainer(uid);
+ mc->setMenu(m);
+
+ m_idContainerMap.insert(uid, mc);
+
+ return mc;
+}
+
+/*!
+ ...
+*/
+IActionContainer *ActionManager::createMenuBar(const QString &id)
+{
+ const int uid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(id);
+ const IdContainerMap::const_iterator it = m_idContainerMap.constFind(uid);
+ if (it != m_idContainerMap.constEnd())
+ return it.value();
+
+ QMenuBar *mb = new QMenuBar; // No parent (System menu bar on Mac OS X)
+ mb->setObjectName(id);
+
+ MenuBarActionContainer *mbc = new MenuBarActionContainer(uid);
+ mbc->setMenuBar(mb);
+
+ m_idContainerMap.insert(uid, mbc);
+
+ return mbc;
+}
+
+/*!
+ ...
+*/
+ICommand *ActionManager::registerAction(QAction *action, const QString &id, const QList<int> &context)
+{
+ OverrideableAction *a = 0;
+ ICommand *c = registerOverridableAction(action, id, false);
+ a = static_cast<OverrideableAction *>(c);
+ if (a)
+ a->addOverrideAction(action, context);
+ return a;
+}
+
+/*!
+ ...
+*/
+ICommand *ActionManager::registerAction(QAction *action, const QString &id)
+{
+ return registerOverridableAction(action, id, true);
+}
+
+/*!
+ \internal
+*/
+ICommand *ActionManager::registerOverridableAction(QAction *action, const QString &id, bool checkUnique)
+{
+ OverrideableAction *a = 0;
+ const int uid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(id);
+ if (Command *c = m_idCmdMap.value(uid, 0)) {
+ if (c->type() != ICommand::CT_OverridableAction) {
+ qWarning() << "registerAction: id" << id << "is registered with a different command type.";
+ return c;
+ }
+ a = static_cast<OverrideableAction *>(c);
+ }
+ if (!a) {
+ a = new OverrideableAction(uid);
+ m_idCmdMap.insert(uid, a);
+ }
+
+ if (!a->action()) {
+ QAction *baseAction = new QAction(m_mainWnd);
+ baseAction->setObjectName(id);
+ baseAction->setCheckable(action->isCheckable());
+ baseAction->setIcon(action->icon());
+ baseAction->setIconText(action->iconText());
+ baseAction->setText(action->text());
+ baseAction->setToolTip(action->toolTip());
+ baseAction->setStatusTip(action->statusTip());
+ baseAction->setWhatsThis(action->whatsThis());
+ baseAction->setChecked(action->isChecked());
+ baseAction->setSeparator(action->isSeparator());
+ baseAction->setShortcutContext(Qt::ApplicationShortcut);
+ baseAction->setEnabled(false);
+ baseAction->setObjectName(id);
+ baseAction->setParent(m_mainWnd);
+#ifdef Q_OS_MAC
+ baseAction->setIconVisibleInMenu(false);
+#endif
+ a->setAction(baseAction);
+ m_mainWnd->addAction(baseAction);
+ a->setKeySequence(a->keySequence());
+ a->setDefaultKeySequence(QKeySequence());
+ } else if (checkUnique) {
+ qWarning() << "registerOverridableAction: id" << id << "is already registered.";
+ }
+
+ return a;
+}
+
+/*!
+ ...
+*/
+ICommand *ActionManager::registerShortcut(QShortcut *shortcut, const QString &id, const QList<int> &context)
+{
+ Shortcut *sc = 0;
+ int uid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(id);
+ if (Command *c = m_idCmdMap.value(uid, 0)) {
+ if (c->type() != ICommand::CT_Shortcut) {
+ qWarning() << "registerShortcut: id" << id << "is registered with a different command type.";
+ return c;
+ }
+ sc = static_cast<Shortcut *>(c);
+ } else {
+ sc = new Shortcut(uid);
+ m_idCmdMap.insert(uid, sc);
+ }
+
+ if (sc->shortcut()) {
+ qWarning() << "registerShortcut: action already registered (id" << id << ".";
+ return sc;
+ }
+
+ if (!hasContext(context))
+ shortcut->setEnabled(false);
+ shortcut->setObjectName(id);
+ shortcut->setParent(m_mainWnd);
+ sc->setShortcut(shortcut);
+
+ if (context.isEmpty())
+ sc->setContext(QList<int>() << 0);
+ else
+ sc->setContext(context);
+
+ sc->setKeySequence(shortcut->key());
+ sc->setDefaultKeySequence(QKeySequence());
+
+ return sc;
+}
+
+/*!
+ \fn void ActionManager::addAction(Core::ICommand *action, const QString &globalGroup)
+*/
+void ActionManager::addAction(ICommand *action, const QString &globalGroup)
+{
+ const int gid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(globalGroup);
+ if (!m_globalgroups.contains(gid)) {
+ qWarning() << "addAction: Unknown global group " << globalGroup;
+ return;
+ }
+
+ const int cid = m_globalgroups.value(gid);
+ if (IActionContainer *aci = actionContainer(cid)) {
+ aci->addAction(action, globalGroup);
+ } else {
+ qWarning() << "addAction: Cannot find container." << cid << '/' << gid;
+ }
+}
+
+/*!
+ \fn void ActionManager::addMenu(Core::IActionContainer *menu, const QString &globalGroup)
+
+*/
+void ActionManager::addMenu(IActionContainer *menu, const QString &globalGroup)
+{
+ const int gid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(globalGroup);
+ if (!m_globalgroups.contains(gid)) {
+ qWarning() << "addAction: Unknown global group " << globalGroup;
+ return;
+ }
+
+ const int cid = m_globalgroups.value(gid);
+ if (IActionContainer *aci = actionContainer(cid)) {
+ aci->addMenu(menu, globalGroup);
+ } else {
+ qWarning() << "addAction: Cannot find container." << cid << '/' << gid;
+ }
+}
+
+/*!
+ ...
+*/
+ICommand *ActionManager::command(const QString &id) const
+{
+ const int uid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(id);
+ const IdCmdMap::const_iterator it = m_idCmdMap.constFind(uid);
+ if (it == m_idCmdMap.constEnd()) {
+ if (warnAboutFindFailures)
+ qWarning() << "ActionManager::command(): failed to find :" << id << '/' << uid;
+ return 0;
+ }
+ return it.value();
+}
+
+/*!
+ ...
+*/
+IActionContainer *ActionManager::actionContainer(const QString &id) const
+{
+ const int uid = m_mainWnd->uniqueIDManager()->uniqueIdentifier(id);
+ const IdContainerMap::const_iterator it = m_idContainerMap.constFind(uid);
+ if ( it == m_idContainerMap.constEnd()) {
+ if (warnAboutFindFailures)
+ qWarning() << "ActionManager::actionContainer(): failed to find :" << id << '/' << uid;
+ return 0;
+ }
+ return it.value();
+}
+
+/*!
+ ...
+*/
+ICommand *ActionManager::command(int uid) const
+{
+ const IdCmdMap::const_iterator it = m_idCmdMap.constFind(uid);
+ if (it == m_idCmdMap.constEnd()) {
+ if (warnAboutFindFailures)
+ qWarning() << "ActionManager::command(): failed to find :" << m_mainWnd->uniqueIDManager()->stringForUniqueIdentifier(uid) << '/' << uid;
+ return 0;
+ }
+ return it.value();
+}
+
+/*!
+ ...
+*/
+IActionContainer *ActionManager::actionContainer(int uid) const
+{
+ const IdContainerMap::const_iterator it = m_idContainerMap.constFind(uid);
+ if (it == m_idContainerMap.constEnd()) {
+ if (warnAboutFindFailures)
+ qWarning() << "ActionManager::actionContainer(): failed to find :" << m_mainWnd->uniqueIDManager()->stringForUniqueIdentifier(uid) << uid;
+ return 0;
+ }
+ return it.value();
+}
+static const char *settingsGroup = "KeyBindings";
+static const char *idKey = "ID";
+static const char *sequenceKey = "Keysequence";
+
+/*!
+ \internal
+*/
+void ActionManager::initialize()
+{
+ QSettings *settings = m_mainWnd->settings();
+ const int shortcuts = settings->beginReadArray(QLatin1String(settingsGroup));
+ for (int i=0; i<shortcuts; ++i) {
+ settings->setArrayIndex(i);
+ const QString sid = settings->value(QLatin1String(idKey)).toString();
+ const QKeySequence key(settings->value(QLatin1String(sequenceKey)).toString());
+ const int id = m_mainWnd->uniqueIDManager()->uniqueIdentifier(sid);
+
+ ICommand *cmd = command(id);
+ if (cmd)
+ cmd->setKeySequence(key);
+ }
+ settings->endArray();
+}
+
+/*!
+ ...
+*/
+void ActionManager::saveSettings(QSettings *settings)
+{
+ settings->beginWriteArray(QLatin1String(settingsGroup));
+ int count = 0;
+
+ const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd();
+ for (IdCmdMap::const_iterator j = m_idCmdMap.constBegin(); j != cmdcend; ++j) {
+ const int id = j.key();
+ Command *cmd = j.value();
+ QKeySequence key = cmd->keySequence();
+ if (key != cmd->defaultKeySequence()) {
+ const QString sid = m_mainWnd->uniqueIDManager()->stringForUniqueIdentifier(id);
+ settings->setArrayIndex(count);
+ settings->setValue(QLatin1String(idKey), sid);
+ settings->setValue(QLatin1String(sequenceKey), key.toString());
+ count++;
+ }
+ }
+
+ settings->endArray();
+}
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.h b/src/plugins/coreplugin/actionmanager/actionmanager.h
new file mode 100644
index 0000000000..c0279e3b69
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ACTIONMANAGER_H
+#define ACTIONMANAGER_H
+
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QHash>
+#include <QtCore/QMultiHash>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+struct CommandLocation {
+ int m_container;
+ int m_position;
+};
+
+namespace Core {
+
+class UniqueIDManager;
+
+namespace Internal {
+
+class ActionContainer;
+class MainWindow;
+class Command;
+
+class ActionManager : public Core::ActionManagerInterface
+{
+ Q_OBJECT
+
+public:
+ ActionManager(MainWindow *mainWnd, UniqueIDManager *uidmgr);
+ ~ActionManager();
+
+ void setContext(const QList<int> &context);
+ static ActionManager* instance();
+
+ void saveSettings(QSettings *settings);
+ QList<int> defaultGroups() const;
+
+ QList<Command *> commands() const;
+ QList<ActionContainer *> containers() const;
+
+ bool hasContext(int context) const;
+
+ ICommand *command(int uid) const;
+ IActionContainer *actionContainer(int uid) const;
+
+ void registerGlobalGroup(int groupId, int containerId);
+
+ void initialize();
+
+ //ActionManager Interface
+ IActionContainer *createMenu(const QString &id);
+ IActionContainer *createMenuBar(const QString &id);
+
+ ICommand *registerAction(QAction *action, const QString &id,
+ const QList<int> &context);
+ ICommand *registerAction(QAction *action, const QString &id);
+ ICommand *registerShortcut(QShortcut *shortcut, const QString &id,
+ const QList<int> &context);
+
+ void addAction(Core::ICommand *action, const QString &globalGroup);
+ void addMenu(Core::IActionContainer *menu, const QString &globalGroup);
+
+ Core::ICommand *command(const QString &id) const;
+ Core::IActionContainer *actionContainer(const QString &id) const;
+
+private:
+ bool hasContext(QList<int> context) const;
+ ICommand *registerOverridableAction(QAction *action, const QString &id,
+ bool checkUnique);
+
+ static ActionManager* m_instance;
+ QList<int> m_defaultGroups;
+
+ typedef QHash<int, Command *> IdCmdMap;
+ IdCmdMap m_idCmdMap;
+
+ typedef QHash<int, ActionContainer *> IdContainerMap;
+ IdContainerMap m_idContainerMap;
+
+ typedef QMap<int, int> GlobalGroupMap;
+ GlobalGroupMap m_globalgroups;
+
+ QList<int> m_context;
+
+ MainWindow *m_mainWnd;
+};
+
+} // namespace Internal
+} // namespace Core
+
+
+#endif //ACTIONMANAGER_H
diff --git a/src/plugins/coreplugin/actionmanager/actionmanagerinterface.h b/src/plugins/coreplugin/actionmanager/actionmanagerinterface.h
new file mode 100644
index 0000000000..9a3760ed76
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/actionmanagerinterface.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ACTIONMANAGERINTERFACE_H
+#define ACTIONMANAGERINTERFACE_H
+
+#include "coreplugin/core_global.h"
+
+#include <coreplugin/actionmanager/iactioncontainer.h>
+#include <coreplugin/actionmanager/icommand.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QShortcut;
+class QString;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class CORE_EXPORT ActionManagerInterface : public QObject
+{
+ Q_OBJECT
+public:
+ ActionManagerInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ActionManagerInterface() {}
+
+ virtual IActionContainer *createMenu(const QString &id) = 0;
+ virtual IActionContainer *createMenuBar(const QString &id) = 0;
+
+ virtual ICommand *registerAction(QAction *action, const QString &id, const QList<int> &context) = 0;
+ virtual ICommand *registerShortcut(QShortcut *shortcut, const QString &id, const QList<int> &context) = 0;
+
+ virtual ICommand *registerAction(QAction *action, const QString &id) = 0;
+
+ virtual void addAction(ICommand *action, const QString &globalGroup) = 0;
+ virtual void addMenu(IActionContainer *menu, const QString &globalGroup) = 0;
+
+ virtual ICommand *command(const QString &id) const = 0;
+ virtual IActionContainer *actionContainer(const QString &id) const = 0;
+};
+
+} // namespace Core
+
+#endif // ACTIONMANAGERINTERFACE_H
diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp
new file mode 100644
index 0000000000..d5e0b17b36
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/command.cpp
@@ -0,0 +1,579 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtGui/QAction>
+#include <QtGui/QShortcut>
+
+#include "command.h"
+
+/*!
+ \class Core::ICommand
+ \mainclass
+ \ingroup qwb
+ \inheaderfile icommand.h
+
+ \brief The class...
+
+ The Command interface...
+*/
+
+/*!
+ \enum ICommand::CommandType
+*/
+
+/*!
+ \enum ICommand::CommandAttribute
+*/
+
+/*!
+ \fn void ICommand::setCategory(const QString &name)
+
+ Sets the category to \a name.
+*/
+
+/*!
+ \fn virtual void ICommand::setDefaultKeySequence(const QKeySequence &key)
+*/
+
+/*!
+ \fn virtual int ICommand::id() const
+*/
+
+/*!
+ \fn virtual CommandType ICommand::type() const
+*/
+
+/*!
+ \fn virtual QAction *ICommand::action() const
+*/
+
+/*!
+ \fn virtual QShortcut *ICommand::shortcut() const
+*/
+
+/*!
+ \fn virtual void ICommand::setAttribute(CommandAttribute attr)
+*/
+
+/*!
+ \fn virtual void ICommand::removeAttribute(CommandAttribute attr)
+*/
+
+/*!
+ \fn virtual bool ICommand::hasAttribute(CommandAttribute attr) const
+*/
+
+/*!
+ \fn virtual bool ICommand::isActive() const
+*/
+
+/*!
+ \fn virtual ICommand::~ICommand()
+*/
+
+using namespace Core::Internal;
+
+/*!
+ \class Command
+ \ingroup qwb
+ \inheaderfile command.h
+*/
+
+/*!
+ \enum Command::CommandState
+*/
+
+/*!
+ \fn Command::Command(CommandType type, int id)
+*/
+Command::Command(CommandType type, int id)
+ : m_type(type), m_id(id)
+{
+}
+
+/*!
+ \fn virtual Command::~Command()
+*/
+
+/*!
+ ...
+*/
+void Command::setStateFlags(int state)
+{
+ m_type |= (state & CS_Mask);
+}
+
+/*!
+ ...
+*/
+int Command::stateFlags() const
+{
+ return (m_type & CS_Mask);
+}
+
+/*!
+ \fn virtual QString Command::name() const
+*/
+
+/*!
+ ...
+*/
+void Command::setCategory(const QString &name)
+{
+ m_category = name;
+}
+
+/*!
+ ...
+*/
+QString Command::category() const
+{
+ if (m_category.isEmpty())
+ return QObject::tr("Other");
+ return m_category;
+}
+
+/*!
+ ...
+*/
+void Command::setDefaultKeySequence(const QKeySequence &key)
+{
+ m_defaultKey = key;
+}
+
+/*!
+ ...
+*/
+QKeySequence Command::defaultKeySequence() const
+{
+ return m_defaultKey;
+}
+
+void Command::setDefaultText(const QString &text)
+{
+ m_defaultText = text;
+}
+
+QString Command::defaultText() const
+{
+ return m_defaultText;
+}
+
+/*!
+ ...
+*/
+int Command::id() const
+{
+ return m_id;
+}
+
+/*!
+ ...
+*/
+Command::CommandType Command::type() const
+{
+ return (CommandType)(m_type & CT_Mask);
+}
+
+/*!
+ ...
+*/
+QAction *Command::action() const
+{
+ return 0;
+}
+
+/*!
+ ...
+*/
+QShortcut *Command::shortcut() const
+{
+ return 0;
+}
+
+/*!
+ ...
+*/
+void Command::setAttribute(CommandAttribute attr)
+{
+ m_type |= attr;
+}
+
+/*!
+ ...
+*/
+void Command::removeAttribute(CommandAttribute attr)
+{
+ m_type &= ~attr;
+}
+
+/*!
+ ...
+*/
+bool Command::hasAttribute(CommandAttribute attr) const
+{
+ return (m_type & attr);
+}
+
+QString Command::stringWithAppendedShortcut(const QString &str) const
+{
+ return QString("%1 <span style=\"color: gray; font-size: small\">%2</span>").arg(str).arg(
+ keySequence().toString(QKeySequence::NativeText));
+}
+
+/*!
+ \fn virtual bool Command::setCurrentContext(const QList<int> &context) = 0
+*/
+
+// ---------- Shortcut ------------
+
+/*!
+ \class Shortcut
+ \ingroup qwb
+ \inheaderfile command.h
+*/
+
+/*!
+ ...
+*/
+Shortcut::Shortcut(int id)
+ : Command(CT_Shortcut, id), m_shortcut(0)
+{
+
+}
+
+/*!
+ ...
+*/
+QString Shortcut::name() const
+{
+ if (!m_shortcut)
+ return QString();
+
+ return m_shortcut->whatsThis();
+}
+
+/*!
+ ...
+*/
+void Shortcut::setShortcut(QShortcut *shortcut)
+{
+ m_shortcut = shortcut;
+}
+
+/*!
+ ...
+*/
+QShortcut *Shortcut::shortcut() const
+{
+ return m_shortcut;
+}
+
+/*!
+ ...
+*/
+void Shortcut::setContext(const QList<int> &context)
+{
+ m_context = context;
+}
+
+/*!
+ ...
+*/
+QList<int> Shortcut::context() const
+{
+ return m_context;
+}
+
+/*!
+ ...
+*/
+void Shortcut::setDefaultKeySequence(const QKeySequence &key)
+{
+ setKeySequence(key);
+ Command::setDefaultKeySequence(key);
+}
+
+void Shortcut::setKeySequence(const QKeySequence &key)
+{
+ m_shortcut->setKey(key);
+ emit keySequenceChanged();
+}
+
+QKeySequence Shortcut::keySequence() const
+{
+ return m_shortcut->key();
+}
+
+void Shortcut::setDefaultText(const QString &text)
+{
+ m_defaultText = text;
+}
+
+QString Shortcut::defaultText() const
+{
+ return m_defaultText;
+}
+
+/*!
+ ...
+*/
+bool Shortcut::setCurrentContext(const QList<int> &context)
+{
+ foreach (int ctxt, m_context) {
+ if (context.contains(ctxt)) {
+ m_shortcut->setEnabled(true);
+ return true;
+ }
+ }
+ m_shortcut->setEnabled(false);
+ return false;
+}
+
+/*!
+ ...
+*/
+bool Shortcut::isActive() const
+{
+ return m_shortcut->isEnabled();
+}
+
+// ---------- Action ------------
+
+/*!
+ \class Action
+ \ingroup qwb
+ \inheaderfile command.h
+*/
+
+/*!
+ ...
+*/
+Action::Action(CommandType type, int id)
+ : Command(type, id), m_action(0)
+{
+
+}
+
+/*!
+ ...
+*/
+QString Action::name() const
+{
+ if (!m_action)
+ return QString();
+
+ return m_action->text();
+}
+
+/*!
+ ...
+*/
+void Action::setAction(QAction *action)
+{
+ m_action = action;
+ if (m_action) {
+ m_action->setParent(this);
+ m_toolTip = m_action->toolTip();
+ }
+}
+
+/*!
+ ...
+*/
+QAction *Action::action() const
+{
+ return m_action;
+}
+
+/*!
+ ...
+*/
+void Action::setLocations(const QList<CommandLocation> &locations)
+{
+ m_locations = locations;
+}
+
+/*!
+ ...
+*/
+QList<CommandLocation> Action::locations() const
+{
+ return m_locations;
+}
+
+/*!
+ ...
+*/
+void Action::setDefaultKeySequence(const QKeySequence &key)
+{
+ setKeySequence(key);
+ Command::setDefaultKeySequence(key);
+}
+
+void Action::setKeySequence(const QKeySequence &key)
+{
+ m_action->setShortcut(key);
+ updateToolTipWithKeySequence();
+ emit keySequenceChanged();
+}
+
+void Action::updateToolTipWithKeySequence()
+{
+ if (m_action->shortcut().isEmpty())
+ m_action->setToolTip(m_toolTip);
+ else
+ m_action->setToolTip(stringWithAppendedShortcut(m_toolTip));
+}
+
+QKeySequence Action::keySequence() const
+{
+ return m_action->shortcut();
+}
+
+// ---------- OverrideableAction ------------
+
+/*!
+ \class OverrideableAction
+ \ingroup qwb
+ \inheaderfile command.h
+*/
+
+/*!
+ ...
+*/
+OverrideableAction::OverrideableAction(int id)
+ : Action(CT_OverridableAction, id), m_currentAction(0), m_active(false),
+ m_contextInitialized(false)
+{
+}
+
+/*!
+ ...
+*/
+void OverrideableAction::setAction(QAction *action)
+{
+ Action::setAction(action);
+}
+
+/*!
+ ...
+*/
+bool OverrideableAction::setCurrentContext(const QList<int> &context)
+{
+ m_context = context;
+
+ QAction *oldAction = m_currentAction;
+ m_currentAction = 0;
+ for (int i = 0; i < m_context.size(); ++i) {
+ if (QAction *a = m_contextActionMap.value(m_context.at(i), 0)) {
+ m_currentAction = a;
+ break;
+ }
+ }
+
+ if (m_currentAction == oldAction && m_contextInitialized)
+ return true;
+ m_contextInitialized = true;
+
+ if (oldAction) {
+ disconnect(oldAction, SIGNAL(changed()), this, SLOT(actionChanged()));
+ disconnect(m_action, SIGNAL(triggered(bool)), oldAction, SIGNAL(triggered(bool)));
+ disconnect(m_action, SIGNAL(toggled(bool)), oldAction, SLOT(setChecked(bool)));
+ }
+ if (m_currentAction) {
+ connect(m_currentAction, SIGNAL(changed()), this, SLOT(actionChanged()));
+ // we want to avoid the toggling semantic on slot trigger(), so we just connect the signals
+ connect(m_action, SIGNAL(triggered(bool)), m_currentAction, SIGNAL(triggered(bool)));
+ // we need to update the checked state, so we connect to setChecked slot, which also fires a toggled signal
+ connect(m_action, SIGNAL(toggled(bool)), m_currentAction, SLOT(setChecked(bool)));
+ actionChanged();
+ m_active = true;
+ return true;
+ }
+ if (hasAttribute(CA_Hide))
+ m_action->setVisible(false);
+ m_action->setEnabled(false);
+ m_active = false;
+ return false;
+}
+
+/*!
+ ...
+*/
+void OverrideableAction::addOverrideAction(QAction *action, const QList<int> &context)
+{
+ if (context.isEmpty()) {
+ m_contextActionMap.insert(0, action);
+ } else {
+ for (int i=0; i<context.size(); ++i) {
+ int k = context.at(i);
+ if (m_contextActionMap.contains(k))
+ qWarning() << QString("addOverrideAction: action already registered for context when registering '%1'").arg(action->text());
+ m_contextActionMap.insert(k, action);
+ }
+ }
+}
+
+/*!
+ ...
+*/
+void OverrideableAction::actionChanged()
+{
+ if (hasAttribute(CA_UpdateIcon)) {
+ m_action->setIcon(m_currentAction->icon());
+ m_action->setIconText(m_currentAction->iconText());
+ }
+ if (hasAttribute(CA_UpdateText)) {
+ m_action->setText(m_currentAction->text());
+ m_toolTip = m_currentAction->toolTip();
+ updateToolTipWithKeySequence();
+ m_action->setStatusTip(m_currentAction->statusTip());
+ m_action->setWhatsThis(m_currentAction->whatsThis());
+ }
+
+ bool block = m_action->blockSignals(true);
+ m_action->setChecked(m_currentAction->isChecked());
+ m_action->blockSignals(block);
+
+ m_action->setEnabled(m_currentAction->isEnabled());
+ m_action->setVisible(m_currentAction->isVisible());
+}
+
+/*!
+ ...
+*/
+bool OverrideableAction::isActive() const
+{
+ return m_active;
+}
diff --git a/src/plugins/coreplugin/actionmanager/command.h b/src/plugins/coreplugin/actionmanager/command.h
new file mode 100644
index 0000000000..2d227d6542
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/command.h
@@ -0,0 +1,178 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMMAND_H
+#define COMMAND_H
+
+#include "icommand.h"
+#include "actionmanager.h"
+
+#include <QtCore/QList>
+#include <QtCore/QMultiMap>
+#include <QtCore/QPointer>
+#include <QtGui/QKeySequence>
+
+namespace Core {
+namespace Internal {
+
+class Command : public Core::ICommand
+{
+ Q_OBJECT
+public:
+ enum CommandState {
+ CS_PreLocation = 0x020000,
+ CS_LocationChanged = 0x040000,
+ CS_Initialized = 0x080000,
+ CS_Mask = 0xFF0000
+ };
+
+ Command(CommandType type, int id);
+ virtual ~Command() {}
+
+ void setStateFlags(int state);
+ int stateFlags() const;
+
+ virtual QString name() const = 0;
+
+ void setCategory(const QString &name);
+ QString category() const;
+
+ void setDefaultKeySequence(const QKeySequence &key);
+ QKeySequence defaultKeySequence() const;
+
+ void setDefaultText(const QString &text);
+ QString defaultText() const;
+
+ int id() const;
+ CommandType type() const;
+
+ QAction *action() const;
+ QShortcut *shortcut() const;
+
+ void setAttribute(CommandAttribute attr);
+ void removeAttribute(CommandAttribute attr);
+ bool hasAttribute(CommandAttribute attr) const;
+
+ virtual bool setCurrentContext(const QList<int> &context) = 0;
+
+ QString stringWithAppendedShortcut(const QString &str) const;
+
+protected:
+ QString m_category;
+ int m_type;
+ int m_id;
+ QKeySequence m_defaultKey;
+ QString m_defaultText;
+};
+
+class Shortcut : public Command
+{
+ Q_OBJECT
+public:
+ Shortcut(int id);
+
+ QString name() const;
+
+ void setDefaultKeySequence(const QKeySequence &key);
+ void setKeySequence(const QKeySequence &key);
+ QKeySequence keySequence() const;
+
+ virtual void setDefaultText(const QString &key);
+ virtual QString defaultText() const;
+
+ void setShortcut(QShortcut *shortcut);
+ QShortcut *shortcut() const;
+
+ void setContext(const QList<int> &context);
+ QList<int> context() const;
+ bool setCurrentContext(const QList<int> &context);
+
+ bool isActive() const;
+private:
+ QList<int> m_context;
+ QShortcut *m_shortcut;
+ QString m_defaultText;
+};
+
+class Action : public Command
+{
+ Q_OBJECT
+public:
+ Action(CommandType type, int id);
+
+ QString name() const;
+
+ void setDefaultKeySequence(const QKeySequence &key);
+ void setKeySequence(const QKeySequence &key);
+ QKeySequence keySequence() const;
+
+ virtual void setAction(QAction *action);
+ QAction *action() const;
+
+ void setLocations(const QList<CommandLocation> &locations);
+ QList<CommandLocation> locations() const;
+
+protected:
+ void updateToolTipWithKeySequence();
+
+ QAction *m_action;
+ QList<CommandLocation> m_locations;
+ QString m_toolTip;
+};
+
+class OverrideableAction : public Action
+{
+ Q_OBJECT
+
+public:
+ OverrideableAction(int id);
+
+ void setAction(QAction *action);
+ bool setCurrentContext(const QList<int> &context);
+ void addOverrideAction(QAction *action, const QList<int> &context);
+ bool isActive() const;
+
+private slots:
+ void actionChanged();
+
+private:
+ QPointer<QAction> m_currentAction;
+ QList<int> m_context;
+ QMap<int, QPointer<QAction> > m_contextActionMap;
+ bool m_active;
+ bool m_contextInitialized;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //COMMAND_H
diff --git a/src/plugins/coreplugin/actionmanager/commandsfile.cpp b/src/plugins/coreplugin/actionmanager/commandsfile.cpp
new file mode 100644
index 0000000000..6849dd9771
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/commandsfile.cpp
@@ -0,0 +1,126 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "coreimpl.h"
+#include "commandsfile.h"
+#include "shortcutsettings.h"
+#include "command.h"
+
+#include <coreplugin/uniqueidmanager.h>
+
+#include <QtCore/QFile>
+#include <QtXml/QDomDocument>
+
+using namespace Core;
+using namespace Core::Internal;
+
+/*!
+ \class CommandsFile
+ \brief The CommandsFile class provides a collection of import and export commands.
+ \ingroup qwb
+ \inheaderfile commandsfile.h
+*/
+
+/*!
+ ...
+*/
+CommandsFile::CommandsFile(const QString &filename)
+ : m_filename(filename)
+{
+
+}
+
+/*!
+ ...
+*/
+QMap<QString, QKeySequence> CommandsFile::importCommands() const
+{
+ QMap<QString, QKeySequence> result;
+
+ QFile file(m_filename);
+ if (!file.open(QIODevice::ReadOnly))
+ return result;
+
+ QDomDocument doc("KeyboardMappingScheme");
+ if (!doc.setContent(&file))
+ return result;
+
+ QDomElement root = doc.documentElement();
+ if (root.nodeName() != QLatin1String("mapping"))
+ return result;
+
+ QDomElement ks = root.firstChildElement();
+ for (; !ks.isNull(); ks = ks.nextSiblingElement()) {
+ if (ks.nodeName() == QLatin1String("shortcut")) {
+ QString id = ks.attribute(QLatin1String("id"));
+ QKeySequence shortcutkey;
+ QDomElement keyelem = ks.firstChildElement("key");
+ if (!keyelem.isNull())
+ shortcutkey = QKeySequence(keyelem.attribute("value"));
+ result.insert(id, shortcutkey);
+ }
+ }
+
+ file.close();
+ return result;
+}
+
+/*!
+ ...
+*/
+bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
+{
+ UniqueIDManager *idmanager = CoreImpl::instance()->uniqueIDManager();
+
+ QFile file(m_filename);
+ if (!file.open(QIODevice::WriteOnly))
+ return false;
+
+ QDomDocument doc("KeyboardMappingScheme");
+ QDomElement root = doc.createElement("mapping");
+ doc.appendChild(root);
+
+ for (int i=0; i<items.count(); ++i) {
+ ShortcutItem *item = items.at(i);
+ QDomElement ctag = doc.createElement("shortcut");
+ ctag.setAttribute(QLatin1String("id"), idmanager->stringForUniqueIdentifier(item->m_cmd->id()));
+ root.appendChild(ctag);
+
+ QDomElement ktag = doc.createElement("key");
+ ktag.setAttribute(QLatin1String("value"), item->m_key.toString());
+ ctag.appendChild(ktag);
+ }
+
+ file.write(doc.toByteArray());
+ file.close();
+ return true;
+}
diff --git a/src/plugins/coreplugin/actionmanager/commandsfile.h b/src/plugins/coreplugin/actionmanager/commandsfile.h
new file mode 100644
index 0000000000..890c2384f5
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/commandsfile.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMMANDSFILE_H
+#define COMMANDSFILE_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QMap>
+#include <QtCore/QList>
+#include <QtGui/QKeySequence>
+
+namespace Core {
+namespace Internal {
+
+struct ShortcutItem;
+
+class CommandsFile : public QObject {
+ Q_OBJECT
+
+public:
+ CommandsFile(const QString &filename);
+
+ QMap<QString, QKeySequence> importCommands() const;
+ bool exportCommands(const QList<ShortcutItem *> &items);
+
+private:
+ QString m_filename;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //COMMANDSFILE_H
diff --git a/src/plugins/coreplugin/actionmanager/iactioncontainer.h b/src/plugins/coreplugin/actionmanager/iactioncontainer.h
new file mode 100644
index 0000000000..a9adb471b1
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/iactioncontainer.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IACTIONCONTAINER_H
+#define IACTIONCONTAINER_H
+
+#include <QtCore/QObject>
+#include <QtGui/QMenu>
+#include <QtGui/QToolBar>
+#include <QtGui/QMenuBar>
+#include <QtGui/QAction>
+
+namespace Core {
+
+class ICommand;
+class IActionContainer : public QObject
+{
+public:
+ enum ContainerType {
+ CT_Mask = 0xFF,
+ CT_Menu = 0x01,
+ CT_ToolBar = 0x02
+ };
+
+ enum EmptyAction {
+ EA_Mask = 0xFF00,
+ EA_None = 0x0100,
+ EA_Hide = 0x0200,
+ EA_Disable = 0x0300
+ };
+
+ virtual void setEmptyAction(EmptyAction ea) = 0;
+
+ virtual int id() const = 0;
+ virtual ContainerType type() const = 0;
+
+ virtual QMenu *menu() const = 0;
+ virtual QToolBar *toolBar() const = 0;
+ virtual QMenuBar *menuBar() const = 0;
+
+ virtual QAction *insertLocation(const QString &group) const = 0;
+ virtual void appendGroup(const QString &group, bool global = false) = 0;
+ virtual void addAction(Core::ICommand *action, const QString &group = QString()) = 0;
+ virtual void addMenu(Core::IActionContainer *menu, const QString &group = QString()) = 0;
+
+ virtual bool update() = 0;
+ virtual ~IActionContainer() {}
+};
+
+} // namespace Core
+
+#endif // IACTIONCONTAINER_H
diff --git a/src/plugins/coreplugin/actionmanager/icommand.h b/src/plugins/coreplugin/actionmanager/icommand.h
new file mode 100644
index 0000000000..c1a03a2f14
--- /dev/null
+++ b/src/plugins/coreplugin/actionmanager/icommand.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ICOMMAND_H
+#define ICOMMAND_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QShortcut>
+#include <QtGui/QKeySequence>
+
+namespace Core {
+
+class CORE_EXPORT ICommand : public QObject
+{
+ Q_OBJECT
+public:
+ enum CommandType {
+ CT_Shortcut = 0x0001,
+ CT_OverridableAction = 0x0002,
+ CT_Mask = 0x00FF
+ };
+
+ enum CommandAttribute {
+ CA_Hide = 0x0100,
+ CA_UpdateText = 0x0200,
+ CA_UpdateIcon = 0x0400,
+ CA_NonConfigureable = 0x8000,
+ CA_Mask = 0xFF00
+ };
+
+ virtual void setDefaultKeySequence(const QKeySequence &key) = 0;
+ virtual void setKeySequence(const QKeySequence &key) = 0;
+ virtual QKeySequence defaultKeySequence() const = 0;
+ virtual QKeySequence keySequence() const = 0;
+ virtual void setDefaultText(const QString &text) = 0;
+ virtual QString defaultText() const = 0;
+
+ virtual void setCategory(const QString &name) = 0;
+
+ virtual int id() const = 0;
+ virtual CommandType type() const = 0;
+
+ virtual QAction *action() const = 0;
+ virtual QShortcut *shortcut() const = 0;
+
+ virtual void setAttribute(CommandAttribute attr) = 0;
+ virtual void removeAttribute(CommandAttribute attr) = 0;
+ virtual bool hasAttribute(CommandAttribute attr) const = 0;
+
+ virtual bool isActive() const = 0;
+
+ virtual ~ICommand() {}
+
+ virtual QString stringWithAppendedShortcut(const QString &str) const = 0;
+
+signals:
+ void keySequenceChanged();
+};
+
+} // namespace Core
+
+#endif // ICOMMAND_H
diff --git a/src/plugins/coreplugin/basefilewizard.cpp b/src/plugins/coreplugin/basefilewizard.cpp
new file mode 100644
index 0000000000..b54b43af8d
--- /dev/null
+++ b/src/plugins/coreplugin/basefilewizard.cpp
@@ -0,0 +1,671 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basefilewizard.h"
+#include "mimedatabase.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/ifilewizardextension.h>
+#include <utils/filewizarddialog.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QVector>
+#include <QtCore/QDebug>
+#include <QtCore/QSharedData>
+#include <QtCore/QEventLoop>
+#include <QtCore/QSharedPointer>
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QWizard>
+#include <QtGui/QMainWindow>
+
+enum { debugWizard = 0 };
+
+namespace Core {
+
+class GeneratedFilePrivate : public QSharedData {
+public:
+ GeneratedFilePrivate() {}
+ explicit GeneratedFilePrivate(const QString &p);
+ QString path;
+ QString contents;
+ QString editorKind;
+};
+
+GeneratedFilePrivate::GeneratedFilePrivate(const QString &p) :
+ path(p)
+{
+}
+
+GeneratedFile::GeneratedFile() :
+ m_d(new GeneratedFilePrivate)
+{
+}
+
+GeneratedFile::GeneratedFile(const QString &p) :
+ m_d(new GeneratedFilePrivate(p))
+{
+}
+
+GeneratedFile::GeneratedFile(const GeneratedFile &rhs) :
+ m_d(rhs.m_d)
+{
+}
+
+GeneratedFile &GeneratedFile::operator=(const GeneratedFile &rhs)
+{
+ if (this != &rhs)
+ m_d.operator=(rhs.m_d);
+ return *this;
+}
+
+GeneratedFile::~GeneratedFile()
+{
+}
+
+QString GeneratedFile::path() const
+{
+ return m_d->path;
+}
+
+void GeneratedFile::setPath(const QString &p)
+{
+ m_d->path = p;
+}
+
+QString GeneratedFile::contents() const
+{
+ return m_d->contents;
+}
+
+void GeneratedFile::setContents(const QString &c)
+{
+ m_d->contents = c;
+}
+
+QString GeneratedFile::editorKind() const
+{
+ return m_d->editorKind;
+}
+
+void GeneratedFile::setEditorKind(const QString &k)
+{
+ m_d->editorKind = k;
+}
+
+bool GeneratedFile::write(QString *errorMessage) const
+{
+ // Ensure the directory
+ const QFileInfo info(m_d->path);
+ const QDir dir = info.absoluteDir();
+ if (!dir.exists()) {
+ if (!dir.mkpath(dir.absolutePath())) {
+ *errorMessage = BaseFileWizard::tr("Unable to create the directory %1.").arg(dir.absolutePath());
+ return false;
+ }
+ }
+ // Write out
+ QFile file(m_d->path);
+ if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) {
+ *errorMessage = BaseFileWizard::tr("Unable to open %1 for writing: %2").arg(m_d->path, file.errorString());
+ return false;
+ }
+ if (file.write(m_d->contents.toUtf8()) == -1) {
+ *errorMessage = BaseFileWizard::tr("Error while writing to %1: %2").arg(m_d->path, file.errorString());
+ return false;
+ }
+ file.close();
+ return true;
+}
+// ------------ BaseFileWizardParameterData
+class BaseFileWizardParameterData : public QSharedData {
+public:
+ explicit BaseFileWizardParameterData(IWizard::Kind kind = IWizard::FileWizard);
+
+ IWizard::Kind kind;
+ QIcon icon;
+ QString description;
+ QString name;
+ QString category;
+ QString trCategory;
+};
+
+BaseFileWizardParameterData::BaseFileWizardParameterData(IWizard::Kind k) :
+ kind(k)
+{
+}
+
+BaseFileWizardParameters::BaseFileWizardParameters(IWizard::Kind kind) :
+ m_d(new BaseFileWizardParameterData(kind))
+{
+}
+
+BaseFileWizardParameters::BaseFileWizardParameters(const BaseFileWizardParameters &rhs) :
+ m_d(rhs.m_d)
+{
+}
+
+BaseFileWizardParameters &BaseFileWizardParameters::operator=(const BaseFileWizardParameters &rhs)
+{
+ if (this != &rhs)
+ m_d.operator=(rhs.m_d);
+ return *this;
+}
+
+BaseFileWizardParameters::~BaseFileWizardParameters()
+{
+}
+
+IWizard::Kind BaseFileWizardParameters::kind() const
+{
+ return m_d->kind;
+}
+
+void BaseFileWizardParameters::setKind(IWizard::Kind k)
+{
+ m_d->kind = k;
+}
+
+QIcon BaseFileWizardParameters::icon() const
+{
+ return m_d->icon;
+}
+
+void BaseFileWizardParameters::setIcon(const QIcon &icon)
+{
+ m_d->icon = icon;
+}
+
+QString BaseFileWizardParameters::description() const
+{
+ return m_d->description;
+}
+
+void BaseFileWizardParameters::setDescription(const QString &v)
+{
+ m_d->description = v;
+}
+
+
+QString BaseFileWizardParameters::name() const
+{
+ return m_d->name;
+}
+
+void BaseFileWizardParameters::setName(const QString &v)
+{
+ m_d->name = v;
+}
+
+
+QString BaseFileWizardParameters::category() const
+{
+ return m_d->category;
+}
+
+void BaseFileWizardParameters::setCategory(const QString &v)
+{
+ m_d->category = v;
+}
+
+QString BaseFileWizardParameters::trCategory() const
+{
+ return m_d->trCategory;
+}
+
+void BaseFileWizardParameters::setTrCategory(const QString &v)
+{
+ m_d->trCategory = v;
+}
+
+/* WizardEventLoop: Special event loop that runs a QWizard and terminates if the page changes.
+ * Synopsis:
+ * \code
+ Wizard wizard(parent);
+ WizardEventLoop::WizardResult wr;
+ do {
+ wr = WizardEventLoop::execWizardPage(wizard);
+ } while (wr == WizardEventLoop::PageChanged);
+ * \endcode */
+
+class WizardEventLoop : public QEventLoop
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(WizardEventLoop)
+ WizardEventLoop(QObject *parent);
+
+public:
+ enum WizardResult { Accepted, Rejected , PageChanged };
+
+ static WizardResult execWizardPage(QWizard &w);
+
+private slots:
+ void pageChanged(int);
+ void accepted();
+ void rejected();
+
+private:
+ WizardResult execWizardPageI();
+
+ WizardResult m_result;
+};
+
+WizardEventLoop::WizardEventLoop(QObject *parent) :
+ QEventLoop(parent),
+ m_result(Rejected)
+{
+}
+
+WizardEventLoop::WizardResult WizardEventLoop::execWizardPage(QWizard &wizard)
+{
+ /* Install ourselves on the wizard. Main trick is here to connect
+ * to the page changed signal and quit() on it. */
+ WizardEventLoop *eventLoop = wizard.findChild<WizardEventLoop *>();
+ if (!eventLoop) {
+ eventLoop = new WizardEventLoop(&wizard);
+ connect(&wizard, SIGNAL(currentIdChanged(int)), eventLoop, SLOT(pageChanged(int)));
+ connect(&wizard, SIGNAL(accepted()), eventLoop, SLOT(accepted()));
+ connect(&wizard, SIGNAL(rejected()), eventLoop, SLOT(rejected()));
+ wizard.setAttribute(Qt::WA_ShowModal, true);
+ wizard.show();
+ }
+ const WizardResult result = eventLoop->execWizardPageI();
+ // Quitting?
+ if (result != PageChanged)
+ delete eventLoop;
+ if (debugWizard)
+ qDebug() << "WizardEventLoop::runWizard" << wizard.pageIds() << " returns " << result;
+
+ return result;
+}
+
+WizardEventLoop::WizardResult WizardEventLoop::execWizardPageI()
+{
+ m_result = Rejected;
+ exec(QEventLoop::DialogExec);
+ return m_result;
+}
+
+void WizardEventLoop::pageChanged(int /*page*/)
+{
+ m_result = PageChanged;
+ quit(); // !
+}
+
+void WizardEventLoop::accepted()
+{
+ m_result = Accepted;
+ quit();
+}
+
+void WizardEventLoop::rejected()
+{
+ m_result = Rejected;
+ quit();
+}
+
+// ---------------- BaseFileWizardPrivate
+struct BaseFileWizardPrivate {
+ explicit BaseFileWizardPrivate(const Core::BaseFileWizardParameters &parameters,
+ Core::ICore *core);
+
+ const Core::BaseFileWizardParameters m_parameters;
+ QWizard *m_wizardDialog;
+ Core::ICore *m_core;
+};
+
+Core::BaseFileWizardPrivate::BaseFileWizardPrivate(const BaseFileWizardParameters &parameters,
+ Core::ICore *core) :
+ m_parameters(parameters),
+ m_wizardDialog(0),
+ m_core(core)
+{
+}
+
+// ---------------- Wizard
+BaseFileWizard::BaseFileWizard(const BaseFileWizardParameters &parameters,
+ Core::ICore *core,
+ QObject *parent) :
+ IWizard(parent),
+ m_d(new BaseFileWizardPrivate(parameters, core))
+{
+}
+
+BaseFileWizard::~BaseFileWizard()
+{
+ delete m_d;
+}
+
+IWizard::Kind BaseFileWizard::kind() const
+{
+ return m_d->m_parameters.kind();
+}
+
+QIcon BaseFileWizard::icon() const
+{
+ return m_d->m_parameters.icon();
+}
+
+QString BaseFileWizard::description() const
+{
+ return m_d->m_parameters.description();
+}
+
+QString BaseFileWizard::name() const
+{
+ return m_d->m_parameters.name();
+}
+
+QString BaseFileWizard::category() const
+{
+ return m_d->m_parameters.category();
+}
+
+QString BaseFileWizard::trCategory() const
+{
+ return m_d->m_parameters.trCategory();
+}
+
+QStringList BaseFileWizard::runWizard(const QString &path, QWidget *parent)
+{
+ typedef QList<IFileWizardExtension*> ExtensionList;
+
+ QString errorMessage;
+ // Compile extension pages, purge out unused ones
+ ExtensionList extensions = ExtensionSystem::PluginManager::instance()->getObjects<IFileWizardExtension>();
+ WizardPageList allExtensionPages;
+ for (ExtensionList::iterator it = extensions.begin(); it != extensions.end(); ) {
+ const WizardPageList extensionPages = (*it)->extensionPages(this);
+ if (extensionPages.empty()) {
+ it = extensions.erase(it);
+ } else {
+ allExtensionPages += extensionPages;
+ ++it;
+ }
+ }
+
+ if (debugWizard)
+ qDebug() << Q_FUNC_INFO << path << parent << "exs" << extensions.size() << allExtensionPages.size();
+
+ QWizardPage *firstExtensionPage = 0;
+ if (!allExtensionPages.empty())
+ firstExtensionPage = allExtensionPages.front();
+
+ // Create dialog and run it. Ensure that the dialog is deleted when
+ // leaving the func, but not before the IFileWizardExtension::process
+ // has been called
+ const QSharedPointer<QWizard> wizard(createWizardDialog(parent, path, allExtensionPages));
+ GeneratedFiles files;
+ // Run the wizard: Call generate files on switching to the first extension
+ // page is OR after 'Accepted' if there are no extension pages
+ while (true) {
+ const WizardEventLoop::WizardResult wr = WizardEventLoop::execWizardPage(*wizard);
+ if (wr == WizardEventLoop::Rejected) {
+ files.clear();
+ break;
+ }
+ const bool accepted = wr == WizardEventLoop::Accepted;
+ const bool firstExtensionPageHit = wr == WizardEventLoop::PageChanged
+ && wizard->page(wizard->currentId()) == firstExtensionPage;
+ const bool needGenerateFiles = firstExtensionPageHit || (accepted && allExtensionPages.empty());
+ if (needGenerateFiles) {
+ QString errorMessage;
+ files = generateFiles(wizard.data(), &errorMessage);
+ if (files.empty()) {
+ QMessageBox::critical(0, tr("File Generation Failure"), errorMessage);
+ break;
+ }
+ }
+ if (firstExtensionPageHit)
+ foreach(IFileWizardExtension *ex, extensions)
+ ex->firstExtensionPageShown(files);
+ if (accepted)
+ break;
+ }
+ if (files.empty())
+ return QStringList();
+ // Compile result list and prompt for overwrite
+ QStringList result;
+ foreach (const GeneratedFile &generatedFile, files)
+ result.push_back(generatedFile.path());
+
+ switch (promptOverwrite(path, result, &errorMessage)) {
+ case OverwriteCanceled:
+ return QStringList();
+ case OverwriteError:
+ QMessageBox::critical(0, tr("Existing files"), errorMessage);
+ return QStringList();
+ case OverwriteOk:
+ break;
+ }
+
+ // Write
+ foreach (const GeneratedFile &generatedFile, files) {
+ if (!generatedFile.write(&errorMessage)) {
+ QMessageBox::critical(parent, tr("File Generation Failure"), errorMessage);
+ return QStringList();
+ }
+ }
+ // Run the extensions
+ foreach(IFileWizardExtension *ex, extensions)
+ if (!ex->process(files, &errorMessage)) {
+ QMessageBox::critical(parent, tr("File Generation Failure"), errorMessage);
+ return QStringList();
+ }
+
+ // Post generation handler
+ if (!postGenerateFiles(files, &errorMessage)) {
+ QMessageBox::critical(0, tr("File Generation Failure"), errorMessage);
+ return QStringList();
+ }
+
+ return result;
+}
+
+QPixmap BaseFileWizard::watermark()
+{
+ return QPixmap(QLatin1String(":/qworkbench/images/qtwatermark.png"));
+}
+
+void BaseFileWizard::setupWizard(QWizard *w)
+{
+ w->setPixmap(QWizard::WatermarkPixmap, watermark());
+}
+
+bool BaseFileWizard::postGenerateFiles(const GeneratedFiles &l, QString *errorMessage)
+{
+ // File mode: open the editors in file mode and ensure editor pane
+ const Core::GeneratedFiles::const_iterator cend = l.constEnd();
+ for (Core::GeneratedFiles::const_iterator it = l.constBegin(); it != cend; ++it) {
+ if (!m_d->m_core->editorManager()->openEditor(it->path(), it->editorKind())) {
+ *errorMessage = tr("Failed to open an editor for %1").arg(it->path());
+ return false;
+ }
+ }
+ m_d->m_core->editorManager()->ensureEditorManagerVisible();
+ return true;
+}
+
+BaseFileWizard::OverwriteResult BaseFileWizard::promptOverwrite(const QString &location,
+ const QStringList &files,
+ QString *errorMessage) const
+{
+ if (debugWizard)
+ qDebug() << Q_FUNC_INFO << location << files;
+
+
+ bool existingFilesFound = false;
+ bool oddStuffFound = false;
+
+ static const QString readOnlyMsg = tr(" [read only]");
+ static const QString directoryMsg = tr(" [directory]");
+ static const QString symLinkMsg = tr(" [symbolic link]");
+
+ // Format a file list message as ( "<file1> [readonly], <file2> [directory]").
+ QString fileNamesMsgPart;
+ foreach (const QString &fileName, files) {
+ const QFileInfo fi(fileName);
+ if (fi.exists()) {
+ existingFilesFound = true;
+ if (!fileNamesMsgPart.isEmpty())
+ fileNamesMsgPart += QLatin1String(", ");
+ fileNamesMsgPart += fi.fileName();
+ do {
+ if (fi.isDir()) {
+ oddStuffFound = true;
+ fileNamesMsgPart += directoryMsg;
+ break;
+ }
+ if (fi.isSymLink()) {
+ oddStuffFound = true;
+ fileNamesMsgPart += symLinkMsg;
+ break;
+ }
+ if (!fi.isWritable()) {
+ oddStuffFound = true;
+ fileNamesMsgPart += readOnlyMsg;
+ }
+ } while (false);
+ }
+ }
+
+ if (!existingFilesFound)
+ return OverwriteOk;
+
+ if (oddStuffFound) {
+ *errorMessage = tr("The project directory %1 contains files which cannot be overwritten:\n%2.").arg(location).arg(fileNamesMsgPart);
+ return OverwriteError;
+ }
+
+ const QString messageFormat = tr("The following files already exist in the directory %1:\n"
+ "%2.\nWould you like to overwrite them?");
+ const QString message = messageFormat.arg(location).arg(fileNamesMsgPart);
+ const bool yes = (QMessageBox::question(core()->mainWindow(),
+ tr("Existing files"), message,
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No)
+ == QMessageBox::Yes);
+ return yes ? OverwriteOk : OverwriteCanceled;
+}
+
+Core::ICore *BaseFileWizard::core() const
+{
+ return m_d->m_core;
+}
+
+QList<IWizard*> BaseFileWizard::allWizards()
+{
+ return ExtensionSystem::PluginManager::instance()->getObjects<IWizard>();
+}
+
+// Utility to find all registered wizards of a certain kind
+
+class WizardKindPredicate {
+public:
+ WizardKindPredicate(IWizard::Kind kind) : m_kind(kind) {}
+ bool operator()(const IWizard &w) const { return w.kind() == m_kind; }
+private:
+ const IWizard::Kind m_kind;
+};
+
+QList<IWizard*> BaseFileWizard::findWizardsOfKind(Kind kind)
+{
+ return findWizards(WizardKindPredicate(kind));
+}
+
+QString BaseFileWizard::buildFileName(const QString &path,
+ const QString &baseName,
+ const QString &extension)
+{
+ QString rc = path;
+ if (!rc.isEmpty() && !rc.endsWith(QDir::separator()))
+ rc += QDir::separator();
+ rc += baseName;
+ // Add extension unless user specified something else
+ const QChar dot = QLatin1Char('.');
+ if (!extension.isEmpty() && !baseName.contains(dot)) {
+ if (!extension.startsWith(dot))
+ rc += dot;
+ rc += extension;
+ }
+ if (debugWizard)
+ qDebug() << Q_FUNC_INFO << rc;
+ return rc;
+}
+
+QString BaseFileWizard::preferredSuffix(const QString &mimeType) const
+{
+ const QString rc = m_d->m_core->mimeDatabase()->preferredSuffixByType(mimeType);
+ if (rc.isEmpty())
+ qWarning("%s: WARNING: Unable to find a preferred suffix for %s.",
+ Q_FUNC_INFO, mimeType.toUtf8().constData());
+ return rc;
+}
+
+// ------------- StandardFileWizard(
+
+StandardFileWizard::StandardFileWizard(const BaseFileWizardParameters &parameters,
+ Core::ICore *core,
+ QObject *parent) :
+ BaseFileWizard(parameters, core, parent)
+{
+}
+
+QWizard *StandardFileWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ Core::Utils::FileWizardDialog *standardWizardDialog = new Core::Utils::FileWizardDialog(parent);
+ standardWizardDialog->setWindowTitle(tr("New %1").arg(name()));
+ setupWizard(standardWizardDialog);
+ standardWizardDialog->setPath(defaultPath);
+ foreach (QWizardPage *p, extensionPages)
+ standardWizardDialog->addPage(p);
+ return standardWizardDialog;
+}
+
+GeneratedFiles StandardFileWizard::generateFiles(const QWizard *w,
+ QString *errorMessage) const
+{
+ const Core::Utils::FileWizardDialog *standardWizardDialog = qobject_cast<const Core::Utils::FileWizardDialog *>(w);
+ return generateFilesFromPath(standardWizardDialog->path(),
+ standardWizardDialog->name(),
+ errorMessage);
+}
+
+
+} // namespace Core
+#include "basefilewizard.moc"
diff --git a/src/plugins/coreplugin/basefilewizard.h b/src/plugins/coreplugin/basefilewizard.h
new file mode 100644
index 0000000000..dcf965ecce
--- /dev/null
+++ b/src/plugins/coreplugin/basefilewizard.h
@@ -0,0 +1,244 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEFILEWIZARD_H
+#define BASEFILEWIZARD_H
+
+#include "core_global.h"
+
+#include <coreplugin/dialogs/iwizard.h>
+
+#include <QtGui/QIcon>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QMap>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QWizard;
+class QWizardPage;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class ICore;
+class IEditor;
+class IFileWizardExtension;
+
+class BaseFileWizardParameterData;
+struct BaseFileWizardPrivate;
+class GeneratedFilePrivate;
+
+/*!
+ * Represents a file generated by a wizard. The Wizard class will check for
+ * each file whether it already exists and will report any errors that may
+ * occur during creation of the files.
+ */
+class CORE_EXPORT GeneratedFile {
+public:
+ GeneratedFile();
+ explicit GeneratedFile(const QString &path);
+ GeneratedFile(const GeneratedFile &);
+ GeneratedFile &operator=(const GeneratedFile&);
+ ~GeneratedFile();
+
+ // Full path of the file should be created, or the suggested file name
+ QString path() const;
+ void setPath(const QString &p);
+
+ // Contents of the file
+ QString contents() const;
+ void setContents(const QString &c);
+
+ // Kind of editor to open the file with
+ QString editorKind() const;
+ void setEditorKind(const QString &k);
+
+ bool write(QString *errorMessage) const;
+
+private:
+ QSharedDataPointer<GeneratedFilePrivate> m_d;
+};
+
+typedef QList<GeneratedFile> GeneratedFiles;
+
+/* Parameter class for passing parameters to instances of class Wizard
+ * containing name, icon and such. */
+
+class CORE_EXPORT BaseFileWizardParameters {
+public:
+ explicit BaseFileWizardParameters(IWizard::Kind kind = IWizard::FileWizard);
+ BaseFileWizardParameters(const BaseFileWizardParameters &);
+ BaseFileWizardParameters &operator=(const BaseFileWizardParameters&);
+ ~BaseFileWizardParameters();
+
+ IWizard::Kind kind() const;
+ void setKind(IWizard::Kind k);
+
+ QIcon icon() const;
+ void setIcon(const QIcon&);
+
+ QString description() const;
+ void setDescription(const QString &);
+
+ QString name() const;
+ void setName(const QString &);
+
+ QString category() const;
+ void setCategory(const QString &);
+
+ QString trCategory() const;
+ void setTrCategory(const QString &);
+
+private:
+ QSharedDataPointer<BaseFileWizardParameterData> m_d;
+};
+
+/* A generic wizard for creating files.
+ *
+ * The abstract methods:
+ *
+ * createWizardDialog() : Called to create the QWizard dialog to be shown
+ * generateFiles() : Generate file content
+ *
+ * must be implemented. The behaviour can be further customized by overwriting
+ * the virtual method:
+ * postGenerateFiles() : Called after generating the files.
+ */
+
+class CORE_EXPORT BaseFileWizard : public IWizard
+{
+ Q_DISABLE_COPY(BaseFileWizard)
+ Q_OBJECT
+
+public:
+ virtual ~BaseFileWizard();
+
+ // IWizard
+ virtual Kind kind() const;
+ virtual QIcon icon() const;
+ virtual QString description() const;
+ virtual QString name() const;
+
+ virtual QString category() const;
+ virtual QString trCategory() const;
+
+ virtual QStringList runWizard(const QString &path, QWidget *parent);
+
+ // Utility to find all registered wizards
+ static QList<IWizard*> allWizards();
+ // Utility to find all registered wizards of a certain kind
+ static QList<IWizard*> findWizardsOfKind(Kind kind);
+
+ // Build a file name, adding the extension unless baseName already has one
+ static QString buildFileName(const QString &path, const QString &baseName, const QString &extension);
+
+ // Return standard pixmap to be used as watermark
+ static QPixmap watermark();
+ // Set the standard watermark on a QWizard
+ static void setupWizard(QWizard *);
+
+protected:
+ typedef QList<QWizardPage *> WizardPageList;
+
+ explicit BaseFileWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent = 0);
+
+ // Overwrite to create the wizard dialog on the parent, adding
+ // the extension pages.
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const = 0;
+
+ // Overwrite to query the parameters from the dialog and generate the files.
+ virtual GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const = 0;
+
+ /* Overwrite to perform steps to be done after files are actually created.
+ * The default implementation opens editors with the newly generated files. */
+ virtual bool postGenerateFiles(const GeneratedFiles &l, QString *errorMessage);
+
+ // Utility that returns the preferred suffix for a mime type
+ QString preferredSuffix(const QString &mimeType) const;
+
+ // Utility that performs an overwrite check on a set of files. It checks if
+ // the file exists, can be overwritten at all and prompts the user.
+ enum OverwriteResult { OverwriteOk, OverwriteError, OverwriteCanceled };
+ OverwriteResult promptOverwrite(const QString &location,
+ const QStringList &files,
+ QString *errorMessage) const;
+ Core::ICore *core() const;
+
+private:
+ BaseFileWizardPrivate *m_d;
+};
+
+// StandardFileWizard convenience class for creating one file. It uses
+// Core::Utils::FileWizardDialog and introduces a new virtual to generate the
+// files from path and name.
+
+class CORE_EXPORT StandardFileWizard : public BaseFileWizard {
+ Q_DISABLE_COPY(StandardFileWizard)
+ Q_OBJECT
+
+protected:
+ explicit StandardFileWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent = 0);
+
+ // Implemented to create a Core::Utils::FileWizardDialog
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+ // Implemented to retrieve path and name and call generateFilesFromPath()
+ virtual GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+
+ // Newly introduced virtual that creates a file from a path
+ virtual GeneratedFiles generateFilesFromPath(const QString &path,
+ const QString &name,
+ QString *errorMessage) const = 0;
+};
+
+/* A utility to find all wizards supporting a view mode and matching a predicate */
+template <class Predicate>
+ QList<IWizard*> findWizards(Predicate predicate)
+{
+ // Filter all wizards
+ const QList<IWizard*> allWizards = BaseFileWizard::allWizards();
+ QList<IWizard*> rc;
+ const QList<IWizard*>::const_iterator cend = allWizards.constEnd();
+ for (QList<IWizard*>::const_iterator it = allWizards.constBegin(); it != cend; ++it)
+ if (predicate(*(*it)))
+ rc.push_back(*it);
+ return rc;
+}
+
+} // namespace Core
+
+#endif // BASEFILEWIZARD_H
diff --git a/src/plugins/coreplugin/basemode.cpp b/src/plugins/coreplugin/basemode.cpp
new file mode 100644
index 0000000000..5573f733f8
--- /dev/null
+++ b/src/plugins/coreplugin/basemode.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basemode.h"
+
+#include <QtGui/QWidget>
+
+#include <extensionsystem/pluginmanager.h>
+
+using namespace Core;
+
+/*!
+ \class BaseMode
+ \mainclass
+ \ingroup qwb
+ \inheaderfile basemode.h
+ \brief A base implementation of the mode interface IMode.
+
+ The BaseMode class can be used directly for most IMode implementations. It has setter functions
+ for the mode properties and a convenience constructor.
+
+ The ownership of the widget is given to the BaseMode, so when the BaseMode is destroyed it
+ deletes its widget.
+
+ A typical use case is to do the following in the init method of a plugin:
+ \code
+ bool MyPlugin::init(QString *error_message)
+ {
+ [...]
+ addObject(new Core::BaseMode("mymode",
+ "MyPlugin.UniqueModeName",
+ icon,
+ 50, // priority
+ new MyWidget));
+ [...]
+ }
+ \endcode
+*/
+
+/*!
+ \fn BaseMode::BaseMode(QObject *parent)
+
+ Creates a mode with empty name, no icon, lowest priority and no widget. You should use the
+ setter functions to give the mode a meaning.
+
+ \a parent
+*/
+BaseMode::BaseMode(QObject *parent):
+ IMode(parent),
+ m_priority(0),
+ m_widget(0)
+{
+}
+
+/*!
+ \fn BaseMode::BaseMode(const QString &name,
+ const char * uniqueModeName,
+ const QIcon &icon,
+ int priority,
+ QWidget *widget,
+ QObject *parent)
+
+ Creates a mode with the given properties.
+
+ \a name
+ \a uniqueModeName
+ \a icon
+ \a priority
+ \a widget
+ \a parent
+*/
+BaseMode::BaseMode(const QString &name,
+ const char * uniqueModeName,
+ const QIcon &icon,
+ int priority,
+ QWidget *widget,
+ QObject *parent):
+ IMode(parent),
+ m_name(name),
+ m_icon(icon),
+ m_priority(priority),
+ m_widget(widget),
+ m_uniqueModeName(uniqueModeName)
+{
+}
+
+/*!
+ \fn BaseMode::~BaseMode()
+*/
+BaseMode::~BaseMode()
+{
+ delete m_widget;
+}
diff --git a/src/plugins/coreplugin/basemode.h b/src/plugins/coreplugin/basemode.h
new file mode 100644
index 0000000000..65bd5bb378
--- /dev/null
+++ b/src/plugins/coreplugin/basemode.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEMODE_H
+#define BASEMODE_H
+
+#include "core_global.h"
+
+#include "imode.h"
+
+#include <QtCore/QObject>
+#include <QtGui/QWidget>
+
+namespace Core {
+
+class CORE_EXPORT BaseMode
+ : public IMode
+{
+ Q_OBJECT
+
+public:
+ BaseMode(QObject *parent = 0);
+ BaseMode(const QString &name,
+ const char * uniqueModeName,
+ const QIcon &icon,
+ int priority,
+ QWidget *widget,
+ QObject *parent = 0);
+ ~BaseMode();
+
+ // IMode
+ QString name() const { return m_name; }
+ QIcon icon() const { return m_icon; }
+ int priority() const { return m_priority; }
+ QWidget *widget() { return m_widget; }
+ const char *uniqueModeName() const { return m_uniqueModeName; }
+ QList<int> context() const { return m_context; }
+
+ void setName(const QString &name) { m_name = name; }
+ void setIcon(const QIcon &icon) { m_icon = icon; }
+ void setPriority(int priority) { m_priority = priority; }
+ void setWidget(QWidget *widget) { m_widget = widget; }
+ void setUniqueModeName(const char *uniqueModeName) { m_uniqueModeName = uniqueModeName; }
+ void setContext(const QList<int> &context) { m_context = context; }
+
+private:
+ QString m_name;
+ QIcon m_icon;
+ int m_priority;
+ QWidget *m_widget;
+ const char * m_uniqueModeName;
+ QList<int> m_context;
+};
+
+} // namespace Core
+
+#endif // BASEMODE_H
diff --git a/src/plugins/coreplugin/baseview.cpp b/src/plugins/coreplugin/baseview.cpp
new file mode 100644
index 0000000000..ef0ab5754c
--- /dev/null
+++ b/src/plugins/coreplugin/baseview.cpp
@@ -0,0 +1,189 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "baseview.h"
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+
+using namespace Core;
+
+/*!
+ \class BaseView
+ \mainclass
+ \ingroup qwb
+ \inheaderfile baseview.h
+ \brief A base implementation of IView.
+
+ The BaseView class can be used directly for most IView implementations.
+ It has setter functions for the views properties, and a convenience constructor
+ for the most important ones.
+
+ The ownership of the widget is given to the BaseView, so when the BaseView is destroyed it
+ deletes its widget.
+
+ A typical use case is to do the following in the init method of a plugin:
+ \code
+ bool MyPlugin::init(QString *error_message)
+ {
+ [...]
+ addObject(new Core::BaseView("myplugin.myview",
+ new MyWidget,
+ QList<int>() << myContextId,
+ Qt::LeftDockWidgetArea,
+ this));
+ [...]
+ }
+ \endcode
+*/
+
+/*!
+ \fn BaseView::BaseView()
+
+ Creates a View with empty view name, no widget, empty context, NoDockWidgetArea,
+ no menu group and empty default shortcut. You should use the setter functions
+ to give the view a meaning.
+*/
+BaseView::BaseView(QObject *parent)
+ : IView(parent),
+ m_viewName(""),
+ m_widget(0),
+ m_context(QList<int>()),
+ m_defaultPosition(IView::First)
+{
+}
+
+/*!
+ \fn BaseView::BaseView(const char *name, QWidget *widget, const QList<int> &context, Qt::DockWidgetArea position, QObject *parent)
+
+ Creates a view with the given properties.
+
+ \a name
+ \a widget
+ \a context
+ \a position
+ \a parent
+*/
+
+BaseView::BaseView(const char *name, QWidget *widget, const QList<int> &context, IView::ViewPosition position, QObject *parent)
+ : IView(parent),
+ m_viewName(name),
+ m_widget(widget),
+ m_context(context),
+ m_defaultPosition(position)
+{
+}
+
+/*!
+ \fn BaseView::~BaseView()
+*/
+BaseView::~BaseView()
+{
+ delete m_widget;
+}
+
+/*!
+ \fn const QList<int> &BaseView::context() const
+*/
+QList<int> BaseView::context() const
+{
+ return m_context;
+}
+
+/*!
+ \fn QWidget *BaseView::widget()
+*/
+QWidget *BaseView::widget()
+{
+ return m_widget;
+}
+
+/*!
+ \fn const char *BaseView::uniqueViewName() const
+*/
+const char *BaseView::uniqueViewName() const
+{
+ return m_viewName;
+}
+
+
+/*!
+ \fn IView::ViewPosition BaseView::defaultPosition() const
+*/
+IView::ViewPosition BaseView::defaultPosition() const
+{
+ return m_defaultPosition;
+}
+
+/*!
+ \fn void BaseView::setUniqueViewName(const char *name)
+
+ \a name
+*/
+void BaseView::setUniqueViewName(const char *name)
+{
+ m_viewName = name;
+}
+
+/*!
+ \fn QWidget *BaseView::setWidget(QWidget *widget)
+
+ The BaseView takes the ownership of the \a widget. The previously
+ set widget (if existent) is not deleted but returned, and responsibility
+ for deleting it moves to the caller of this method.
+*/
+QWidget *BaseView::setWidget(QWidget *widget)
+{
+ QWidget *oldWidget = m_widget;
+ m_widget = widget;
+ return oldWidget;
+}
+
+/*!
+ \fn void BaseView::setContext(const QList<int> &context)
+
+ \a context
+*/
+void BaseView::setContext(const QList<int> &context)
+{
+ m_context = context;
+}
+
+/*!
+ \fn void BaseView::setDefaultPosition(IView::ViewPosition position)
+
+ \a position
+*/
+void BaseView::setDefaultPosition(IView::ViewPosition position)
+{
+ m_defaultPosition = position;
+}
+
diff --git a/src/plugins/coreplugin/baseview.h b/src/plugins/coreplugin/baseview.h
new file mode 100644
index 0000000000..dd3bb0503a
--- /dev/null
+++ b/src/plugins/coreplugin/baseview.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEVIEW_H
+#define BASEVIEW_H
+
+#include "core_global.h"
+#include "iview.h"
+#include <QtCore/QPointer>
+
+namespace Core {
+
+class CORE_EXPORT BaseView
+ : public IView
+{
+ Q_OBJECT
+
+public:
+ BaseView(QObject *parent = 0);
+ BaseView(const char *name, QWidget *widget, const QList<int> &context, IView::ViewPosition position, QObject *parent = 0);
+ ~BaseView();
+
+ QList<int> context() const;
+ QWidget *widget();
+ const char *uniqueViewName() const;
+ IView::ViewPosition defaultPosition() const;
+
+ void setUniqueViewName(const char *name);
+ QWidget *setWidget(QWidget *widget);
+ void setContext(const QList<int> &context);
+ void setDefaultPosition(IView::ViewPosition position);
+
+private:
+ const char *m_viewName;
+ QPointer<QWidget> m_widget;
+ QList<int> m_context;
+ IView::ViewPosition m_defaultPosition;
+};
+
+} // namespace Core
+
+#endif // BASEVIEW_H
diff --git a/src/plugins/coreplugin/core.qrc b/src/plugins/coreplugin/core.qrc
new file mode 100644
index 0000000000..00cd47c92b
--- /dev/null
+++ b/src/plugins/coreplugin/core.qrc
@@ -0,0 +1,71 @@
+<RCC>
+ <qresource prefix="/qworkbench" >
+ <file>html/images/bg_site_header_dark_grey.png</file>
+ <file>html/images/body_bg_circles_bottom_right.png</file>
+ <file>html/images/body_bg_gradient.png</file>
+ <file>html/images/btn_getting_started.png</file>
+ <file>html/images/btn_getting_started_hover.png</file>
+ <file>html/images/btn_restore_session.png</file>
+ <file>html/images/btn_restore_session_hover.png</file>
+ <file>html/images/list_bullet_arrow.png</file>
+ <file>html/images/mode_Project.png</file>
+ <file>html/images/nokia_logo.png</file>
+ <file>html/images/product_logo.png</file>
+ <file>html/images/qt_logo.png</file>
+ <file>html/images/rc_bottom_left.png</file>
+ <file>html/images/rc_bottom_mid.png</file>
+ <file>html/images/rc_bottom_right.png</file>
+ <file>html/images/rc_mid_left.png</file>
+ <file>html/images/rc_mid_mid.png</file>
+ <file>html/images/rc_mid_right.png</file>
+ <file>html/images/rc_top_left.png</file>
+ <file>html/images/rc_top_mid.png</file>
+ <file>html/images/rc_top_right.png</file>
+ <file>html/qt.css</file>
+ <file>html/recent_projects.html</file>
+ <file>html/recent_sessions.html</file>
+ <file>html/welcome.html</file>
+ <file>images/clean_pane_small.png</file>
+ <file>images/clear.png</file>
+ <file>images/closebutton.png</file>
+ <file>images/dir.png</file>
+ <file>images/editcopy.png</file>
+ <file>images/editcut.png</file>
+ <file>images/editpaste.png</file>
+ <file>images/empty14.png</file>
+ <file>images/filenew.png</file>
+ <file>images/fileopen.png</file>
+ <file>images/filesave.png</file>
+ <file>images/find.png</file>
+ <file>images/findnext.png</file>
+ <file>images/qtcreator_logo_128.png</file>
+ <file>images/qtcreator_logo_32.png</file>
+ <file>images/inputfield.png</file>
+ <file>images/inputfield_disabled.png</file>
+ <file>images/linkicon.png</file>
+ <file>images/locked.png</file>
+ <file>images/magnifier.png</file>
+ <file>images/minus.png</file>
+ <file>images/next.png</file>
+ <file>images/panel_button.png</file>
+ <file>images/panel_button_checked.png</file>
+ <file>images/panel_button_checked_hover.png</file>
+ <file>images/panel_button_hover.png</file>
+ <file>images/panel_button_pressed.png</file>
+ <file>images/plus.png</file>
+ <file>images/prev.png</file>
+ <file>images/pushbutton.png</file>
+ <file>images/pushbutton_hover.png</file>
+ <file>images/pushbutton_pressed.png</file>
+ <file>images/qtwatermark.png</file>
+ <file>images/redo.png</file>
+ <file>images/replace.png</file>
+ <file>images/reset.png</file>
+ <file>images/sidebaricon.png</file>
+ <file>images/splitbutton_horizontal.png</file>
+ <file>images/statusbar.png</file>
+ <file>images/undo.png</file>
+ <file>images/unknownfile.png</file>
+ <file>images/unlocked.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/coreplugin/core_global.h b/src/plugins/coreplugin/core_global.h
new file mode 100644
index 0000000000..71737b31b7
--- /dev/null
+++ b/src/plugins/coreplugin/core_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef CORE_GLOBAL_H
+#define CORE_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(CORE_LIBRARY)
+# define CORE_EXPORT Q_DECL_EXPORT
+#else
+# define CORE_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // CORE_GLOBAL_H
diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h
new file mode 100644
index 0000000000..6f0292041e
--- /dev/null
+++ b/src/plugins/coreplugin/coreconstants.h
@@ -0,0 +1,224 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CORECONSTANTS_H
+#define CORECONSTANTS_H
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+
+namespace Core {
+namespace Constants {
+
+#define IDE_VERSION_MAJOR 0
+#define IDE_VERSION_MINOR 9
+#define IDE_VERSION_RELEASE 1
+
+#define STRINGIFY_INTERNAL(x) #x
+#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
+
+#define IDE_VERSION STRINGIFY(IDE_VERSION_MAJOR) \
+ "." STRINGIFY(IDE_VERSION_MINOR) \
+ "." STRINGIFY(IDE_VERSION_RELEASE)
+
+const char * const IDE_VERSION_LONG = IDE_VERSION;
+const char * const IDE_AUTHOR = "Nokia Corporation";
+const char * const IDE_YEAR = "2008";
+
+#ifdef IDE_REVISION
+const char * const IDE_REVISION_STR = STRINGIFY(IDE_REVISION);
+#else
+const char * const IDE_REVISION_STR = "";
+#endif
+
+#undef IDE_VERSION
+#undef STRINGIFY
+#undef STRINGIFY_INTERNAL
+
+//modes
+const char * const MODE_WELCOME = "QtCreator.Mode.Welcome";
+const char * const MODE_EDIT = "QtCreator.Mode.Edit";
+const char * const MODE_OUTPUT = "QtCreator.Mode.Output";
+const int P_MODE_WELCOME = 100;
+const int P_MODE_EDIT = 90;
+const int P_MODE_OUTPUT = 10;
+
+//menubar
+const char * const MENU_BAR = "QtCreator.MenuBar";
+
+//menus
+const char * const M_FILE = "QtCreator.Menu.File";
+const char * const M_FILE_OPEN = "QtCreator.Menu.File.Open";
+const char * const M_FILE_NEW = "QtCreator.Menu.File.New";
+const char * const M_FILE_RECENTFILES = "QtCreator.Menu.File.RecentFiles";
+const char * const M_EDIT = "QtCreator.Menu.Edit";
+const char * const M_EDIT_ADVANCED = "QtCreator.Menu.Edit.Advanced";
+const char * const M_TOOLS = "QtCreator.Menu.Tools";
+const char * const M_WINDOW = "QtCreator.Menu.Window";
+const char * const M_WINDOW_PANES = "QtCreator.Menu.Window.Panes";
+const char * const M_HELP = "QtCreator.Menu.Help";
+
+//contexts
+const char * const C_GLOBAL = "Global Context";
+const int C_GLOBAL_ID = 0;
+const char * const C_WELCOME_MODE = "Core.WelcomeMode";
+const char * const C_EDIT_MODE = "Core.EditMode";
+const char * const C_EDITORMANAGER = "Core.EditorManager";
+const char * const C_NAVIGATION_PANE = "Core.NavigationPane";
+
+//default editor kind
+const char * const K_DEFAULT_TEXT_EDITOR = "Plain Text Editor";
+const char * const K_DEFAULT_BINARY_EDITOR = "Binary Editor";
+
+//actions
+const char * const UNDO = "QtCreator.Undo";
+const char * const REDO = "QtCreator.Redo";
+const char * const COPY = "QtCreator.Copy";
+const char * const PASTE = "QtCreator.Paste";
+const char * const CUT = "QtCreator.Cut";
+const char * const SELECTALL = "QtCreator.SelectAll";
+
+const char * const GOTO = "QtCreator.Goto";
+
+const char * const NEW = "QtCreator.New";
+const char * const OPEN = "QtCreator.Open";
+const char * const OPEN_WITH = "QtCreator.OpenWith";
+const char * const REVERTTOSAVED = "QtCreator.RevertToSaved";
+const char * const SAVE = "QtCreator.Save";
+const char * const SAVEAS = "QtCreator.SaveAs";
+const char * const SAVEALL = "QtCreator.SaveAll";
+const char * const PRINT = "QtCreator.Print";
+const char * const EXIT = "QtCreator.Exit";
+
+const char * const OPTIONS = "QtCreator.Options";
+const char * const TOGGLE_SIDEBAR = "QtCreator.ToggleSidebar";
+
+const char * const MINIMIZE_WINDOW = "QtCreator.MinimizeWindow";
+const char * const ZOOM_WINDOW = "QtCreator.ZoomWindow";
+
+const char * const HORIZONTAL = "QtCreator.Horizontal";
+const char * const VERTICAL = "QtCreator.Vertical";
+const char * const REMOVE = "QtCreator.Remove";
+const char * const SAVEASDEFAULT = "QtCreator.SaveAsDefaultLayout";
+const char * const RESTOREDEFAULT = "QtCreator.RestoreDefaultLayout";
+const char * const CLOSE = "QtCreator.Close";
+const char * const DUPLICATEDOCUMENT = "QtCreator.DuplicateDocument";
+const char * const CLOSEALL = "QtCreator.CloseAll";
+const char * const GOTONEXT = "QtCreator.GotoNext";
+const char * const GOTOPREV = "QtCreator.GotoPrevious";
+const char * const GOTONEXTINHISTORY = "QtCreator.GotoNextInHistory";
+const char * const GOTOPREVINHISTORY = "QtCreator.GotoPreviousInHistory";
+const char * const GO_BACK = "QtCreator.GoBack";
+const char * const GO_FORWARD = "QtCreator.GoForward";
+const char * const GOTOPREVIOUSGROUP = "QtCreator.GotoPreviousTabGroup";
+const char * const GOTONEXTGROUP = "QtCreator.GotoNextTabGroup";
+const char * const WINDOWSLIST = "QtCreator.WindowsList";
+const char * const ABOUT_WORKBENCH = "QtCreator.AboutWorkbench";
+const char * const ABOUT_PLUGINS = "QtCreator.AboutPlugins";
+const char * const ABOUT_QT = "QtCreator.AboutQt";
+const char * const S_RETURNTOEDITOR = "QtCreator.ReturnToEditor";
+const char * const OPEN_IN_EXTERNAL_EDITOR = "QtCreattor.OpenInExternalEditor";
+
+// default groups
+const char * const G_DEFAULT_ONE = "QtCreator.Group.Default.One";
+const char * const G_DEFAULT_TWO = "QtCreator.Group.Default.Two";
+const char * const G_DEFAULT_THREE = "QtCreator.Group.Default.Three";
+
+// main menu bar groups
+const char * const G_FILE = "QtCreator.Group.File";
+const char * const G_EDIT = "QtCreator.Group.Edit";
+const char * const G_VIEW = "QtCreator.Group.View";
+const char * const G_TOOLS = "QtCreator.Group.Tools";
+const char * const G_WINDOW = "QtCreator.Group.Window";
+const char * const G_HELP = "QtCreator.Group.Help";
+
+// file menu groups
+const char * const G_FILE_NEW = "QtCreator.Group.File.New";
+const char * const G_FILE_OPEN = "QtCreator.Group.File.Open";
+const char * const G_FILE_PROJECT = "QtCreator.Group.File.Project";
+const char * const G_FILE_SAVE = "QtCreator.Group.File.Save";
+const char * const G_FILE_CLOSE = "QtCreator.Group.File.Close";
+const char * const G_FILE_PRINT = "QtCreator.Group.File.Print";
+const char * const G_FILE_OTHER = "QtCreator.Group.File.Other";
+
+// edit menu groups
+const char * const G_EDIT_UNDOREDO = "QtCreator.Group.Edit.UndoRedo";
+const char * const G_EDIT_COPYPASTE = "QtCreator.Group.Edit.CopyPaste";
+const char * const G_EDIT_SELECTALL = "QtCreator.Group.Edit.SelectAll";
+const char * const G_EDIT_FORMAT = "QtCreator.Group.Edit.Format";
+
+const char * const G_EDIT_FIND = "QtCreator.Group.Edit.Find";
+const char * const G_EDIT_OTHER = "QtCreator.Group.Edit.Other";
+
+// window menu groups
+const char * const G_WINDOW_SIZE = "QtCreator.Group.Window.Size";
+const char * const G_WINDOW_PANES = "QtCreator.Group.Window.Panes";
+const char * const G_WINDOW_SPLIT = "QtCreator.Group.Window.Split";
+const char * const G_WINDOW_CLOSE = "QtCreator.Group.Window.Close";
+const char * const G_WINDOW_NAVIGATE = "QtCreator.Group.Window.Navigate";
+const char * const G_WINDOW_NAVIGATE_GROUPS = "QtCreator.Group.Window.Navigate.Groups";
+const char * const G_WINDOW_OTHER = "QtCreator.Group.Window.Other";
+const char * const G_WINDOW_LIST = "QtCreator.Group.Window.List";
+
+// help groups (global)
+const char * const G_HELP_HELP = "QtCreator.Group.Help.Help";
+const char * const G_HELP_ABOUT = "QtCreator.Group.Help.About";
+
+const char * const ICON_MINUS = ":/qworkbench/images/minus.png";
+const char * const ICON_PLUS = ":/qworkbench/images/plus.png";
+const char * const ICON_NEWFILE = ":/qworkbench/images/filenew.png";
+const char * const ICON_OPENFILE = ":/qworkbench/images/fileopen.png";
+const char * const ICON_SAVEFILE = ":/qworkbench/images/filesave.png";
+const char * const ICON_UNDO = ":/qworkbench/images/undo.png";
+const char * const ICON_REDO = ":/qworkbench/images/redo.png";
+const char * const ICON_COPY = ":/qworkbench/images/editcopy.png";
+const char * const ICON_PASTE = ":/qworkbench/images/editpaste.png";
+const char * const ICON_CUT = ":/qworkbench/images/editcut.png";
+const char * const ICON_NEXT = ":/qworkbench/images/next.png";
+const char * const ICON_PREV = ":/qworkbench/images/prev.png";
+const char * const ICON_DIR = ":/qworkbench/images/dir.png";
+const char * const ICON_CLEAN_PANE = ":/qworkbench/images/clean_pane_small.png";
+const char * const ICON_CLEAR = ":/qworkbench/images/clear.png";
+const char * const ICON_FIND = ":/qworkbench/images/find.png";
+const char * const ICON_FINDNEXT = ":/qworkbench/images/findnext.png";
+const char * const ICON_REPLACE = ":/qworkbench/images/replace.png";
+const char * const ICON_RESET = ":/qworkbench/images/reset.png";
+const char * const ICON_MAGNIFIER = ":/qworkbench/images/magnifier.png";
+const char * const ICON_TOGGLE_SIDEBAR = ":/qworkbench/images/sidebaricon.png";
+
+// wizard kind
+const char * const WIZARD_TYPE_FILE = "QtCreator::WizardType::File";
+const char * const WIZARD_TYPE_CLASS = "QtCreator::WizardType::Class";
+
+} // namespace Constants
+} // namespace Core
+
+#endif // CORECONSTANTS_H
diff --git a/src/plugins/coreplugin/coreimpl.cpp b/src/plugins/coreplugin/coreimpl.cpp
new file mode 100644
index 0000000000..258aa0331b
--- /dev/null
+++ b/src/plugins/coreplugin/coreimpl.cpp
@@ -0,0 +1,211 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "coreimpl.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+
+using namespace Core;
+using namespace Core::Internal;
+
+CoreImpl *CoreImpl::m_instance = 0;
+
+CoreImpl *CoreImpl::instance()
+{
+ return m_instance;
+}
+
+CoreImpl::CoreImpl(MainWindow *mainwindow)
+{
+ m_instance = this;
+ m_mainwindow = mainwindow;
+}
+
+QStringList CoreImpl::showNewItemDialog(const QString &title,
+ const QList<IWizard *> &wizards,
+ const QString &defaultLocation)
+{
+ return m_mainwindow->showNewItemDialog(title, wizards, defaultLocation);
+}
+
+void CoreImpl::showOptionsDialog(const QString &group, const QString &page)
+{
+ m_mainwindow->showOptionsDialog(group, page);
+}
+
+ActionManagerInterface *CoreImpl::actionManager() const
+{
+ return m_mainwindow->actionManager();
+}
+
+FileManager *CoreImpl::fileManager() const
+{
+ return m_mainwindow->fileManager();
+}
+
+UniqueIDManager *CoreImpl::uniqueIDManager() const
+{
+ return m_mainwindow->uniqueIDManager();
+}
+
+MessageManager *CoreImpl::messageManager() const
+{
+ return m_mainwindow->messageManager();
+}
+
+ViewManagerInterface *CoreImpl::viewManager() const
+{
+ return m_mainwindow->viewManager();
+}
+
+ExtensionSystem::PluginManager *CoreImpl::pluginManager() const
+{
+ return m_mainwindow->pluginManager();
+}
+
+EditorManager *CoreImpl::editorManager() const
+{
+ return m_mainwindow->editorManager();
+}
+
+ProgressManagerInterface *CoreImpl::progressManager() const
+{
+ return m_mainwindow->progressManager();
+}
+
+ScriptManagerInterface *CoreImpl::scriptManager() const
+{
+ return m_mainwindow->scriptManager();
+}
+
+VariableManager *CoreImpl::variableManager() const
+{
+ return m_mainwindow->variableManager();
+}
+
+VCSManager *CoreImpl::vcsManager() const
+{
+ return m_mainwindow->vcsManager();
+}
+
+ModeManager *CoreImpl::modeManager() const
+{
+ return m_mainwindow->modeManager();
+}
+
+MimeDatabase *CoreImpl::mimeDatabase() const
+{
+ return m_mainwindow->mimeDatabase();
+}
+
+QSettings *CoreImpl::settings() const
+{
+ return m_mainwindow->settings();
+}
+
+QPrinter *CoreImpl::printer() const
+{
+ return m_mainwindow->printer();
+}
+
+QString CoreImpl::resourcePath() const
+{
+#if defined(Q_OS_MAC)
+ return QDir::cleanPath(QCoreApplication::applicationDirPath()+QLatin1String("/../Resources"));
+#else
+ return QDir::cleanPath(QCoreApplication::applicationDirPath());
+#endif
+}
+
+QString CoreImpl::libraryPath() const
+{
+#if defined(Q_OS_MAC)
+ return QDir::cleanPath(QCoreApplication::applicationDirPath()+QLatin1String("/../PlugIns"));
+#else
+ return QDir::cleanPath(QCoreApplication::applicationDirPath()+QLatin1String("/../lib"));
+#endif
+}
+
+IContext *CoreImpl::currentContextObject() const
+{
+ return m_mainwindow->currentContextObject();
+}
+
+
+QMainWindow *CoreImpl::mainWindow() const
+{
+ return m_mainwindow;
+}
+
+QStatusBar *CoreImpl::statusBar() const
+{
+ return m_mainwindow->statusBar();
+}
+
+
+// adds and removes additional active contexts, this context is appended to the
+// currently active contexts. call updateContext after changing
+void CoreImpl::addAdditionalContext(int context)
+{
+ m_mainwindow->addAdditionalContext(context);
+}
+
+void CoreImpl::removeAdditionalContext(int context)
+{
+ m_mainwindow->removeAdditionalContext(context);
+}
+
+bool CoreImpl::hasContext(int context) const
+{
+ return m_mainwindow->hasContext(context);
+}
+
+void CoreImpl::addContextObject(IContext *context)
+{
+ m_mainwindow->addContextObject(context);
+}
+
+void CoreImpl::removeContextObject(IContext *context)
+{
+ m_mainwindow->removeContextObject(context);
+}
+
+void CoreImpl::updateContext()
+{
+ return m_mainwindow->updateContext();
+}
+
+void CoreImpl::openFiles(const QStringList &arguments)
+{
+ m_mainwindow->openFiles(arguments);
+}
diff --git a/src/plugins/coreplugin/coreimpl.h b/src/plugins/coreplugin/coreimpl.h
new file mode 100644
index 0000000000..b7eaf185a4
--- /dev/null
+++ b/src/plugins/coreplugin/coreimpl.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COREIMPL_H
+#define COREIMPL_H
+
+#include "icore.h"
+#include "mainwindow.h"
+
+namespace Core {
+namespace Internal {
+
+class CoreImpl : public ICore
+{
+ Q_OBJECT
+
+public:
+ static CoreImpl *instance();
+
+ CoreImpl(MainWindow *mainwindow);
+ ~CoreImpl() {}
+
+ QStringList showNewItemDialog(const QString &title,
+ const QList<IWizard *> &wizards,
+ const QString &defaultLocation = QString());
+ void showOptionsDialog(const QString &group = QString(),
+ const QString &page = QString());
+
+ ActionManagerInterface *actionManager() const;
+ FileManager *fileManager() const ;
+ UniqueIDManager *uniqueIDManager() const;
+ MessageManager *messageManager() const;
+ ViewManagerInterface *viewManager() const;
+ ExtensionSystem::PluginManager *pluginManager() const;
+ EditorManager *editorManager() const;
+ ProgressManagerInterface *progressManager() const;
+ ScriptManagerInterface *scriptManager() const;
+ VariableManager *variableManager() const;
+ VCSManager *vcsManager() const;
+ ModeManager *modeManager() const;
+ MimeDatabase *mimeDatabase() const;
+
+ QSettings *settings() const;
+ QPrinter *printer() const;
+
+ QString resourcePath() const;
+ QString libraryPath() const;
+
+ IContext *currentContextObject() const;
+
+ QMainWindow *mainWindow() const;
+ QStatusBar *statusBar() const;
+
+ // adds and removes additional active contexts, this context is appended to the
+ // currently active contexts. call updateContext after changing
+ void addAdditionalContext(int context);
+ void removeAdditionalContext(int context);
+ bool hasContext(int context) const;
+ void addContextObject(IContext *contex);
+ void removeContextObject(IContext *contex);
+
+ void updateContext();
+
+ void openFiles(const QStringList &fileNames);
+
+private:
+ MainWindow *m_mainwindow;
+ friend class MainWindow;
+
+ static CoreImpl *m_instance;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // COREIMPL_H
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
new file mode 100644
index 0000000000..070edd9a6a
--- /dev/null
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "coreplugin.h"
+#include "welcomemode.h"
+#include "editmode.h"
+#include "editormanager.h"
+#include "mainwindow.h"
+#include "modemanager.h"
+#include "viewmanager.h"
+#include "fileiconprovider.h"
+
+#include <QtCore/qplugin.h>
+#ifdef QT_WEBKIT
+#include <QtGui/QApplication>
+#include <QtWebKit/QWebSettings>
+#endif
+
+using namespace Core::Internal;
+
+CorePlugin::CorePlugin() :
+ m_mainWindow(new MainWindow), m_welcomeMode(0), m_editMode(0), m_pm(0)
+{
+}
+
+CorePlugin::~CorePlugin()
+{
+ if (m_welcomeMode) {
+ removeObject(m_welcomeMode);
+ delete m_welcomeMode;
+ }
+ if (m_editMode) {
+ removeObject(m_editMode);
+ delete m_editMode;
+ }
+
+ // delete FileIconProvider singleton
+ delete FileIconProvider::instance();
+
+ delete m_mainWindow;
+}
+
+bool CorePlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+ m_pm = ExtensionSystem::PluginManager::instance();
+ const bool success = m_mainWindow->init(m_pm, error_message);
+ if (success) {
+#ifdef QT_WEBKIT
+ QWebSettings *webSettings = QWebSettings::globalSettings();
+ const QFont applicationFont = QApplication::font();
+ webSettings->setFontFamily(QWebSettings::StandardFont, applicationFont.family());
+ //webSettings->setFontSize(QWebSettings::DefaultFontSize, applicationFont.pointSize());
+#endif
+ m_welcomeMode = new WelcomeMode;
+ addObject(m_welcomeMode);
+
+ EditorManager *editorManager = qobject_cast<EditorManager*>(m_mainWindow->editorManager());
+ m_editMode = new EditMode(editorManager);
+ addObject(m_editMode);
+ }
+ return success;
+}
+
+void CorePlugin::extensionsInitialized()
+{
+ m_mainWindow->modeManager()->activateMode(m_welcomeMode->uniqueModeName());
+ m_mainWindow->extensionsInitialized();
+}
+
+void CorePlugin::remoteArgument(const QString& arg)
+{
+ // An empty argument is sent to trigger activation
+ // of the window via QtSingleApplication. It should be
+ // the last of a sequence.
+ if (arg.isEmpty()) {
+ m_mainWindow->activateWindow();
+ } else {
+ m_mainWindow->openFiles(QStringList(arg));
+ }
+}
+
+Q_EXPORT_PLUGIN(CorePlugin)
diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h
new file mode 100644
index 0000000000..6afd9c7f24
--- /dev/null
+++ b/src/plugins/coreplugin/coreplugin.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QWORKBENCHPLUGIN_H
+#define QWORKBENCHPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+namespace Core {
+namespace Internal {
+
+class WelcomeMode;
+class EditMode;
+class MainWindow;
+
+class CorePlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ CorePlugin();
+ ~CorePlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message = 0);
+ void extensionsInitialized();
+
+public slots:
+ void remoteArgument(const QString&);
+
+private:
+ MainWindow *m_mainWindow;
+ WelcomeMode *m_welcomeMode;
+ EditMode *m_editMode;
+
+ ExtensionSystem::PluginManager *m_pm;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // QWORKBENCHPLUGIN_H
diff --git a/src/plugins/coreplugin/coreplugin.pri b/src/plugins/coreplugin/coreplugin.pri
new file mode 100644
index 0000000000..c2b2a3fa2c
--- /dev/null
+++ b/src/plugins/coreplugin/coreplugin.pri
@@ -0,0 +1,3 @@
+include(coreplugin_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(Core)
diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro
new file mode 100644
index 0000000000..f0c474d4f8
--- /dev/null
+++ b/src/plugins/coreplugin/coreplugin.pro
@@ -0,0 +1,169 @@
+TEMPLATE = lib
+TARGET = Core
+DEFINES += CORE_LIBRARY
+QT += xml \
+ script \
+ svg
+
+include(../../qworkbenchplugin.pri)
+include(../../libs/utils/utils.pri)
+include(../../../shared/scriptwrapper/scriptwrapper.pri)
+include(coreplugin_dependencies.pri)
+INCLUDEPATH += dialogs \
+ actionmanager \
+ editormanager \
+ progressmanager \
+ scriptmanager
+DEPENDPATH += dialogs \
+ actionmanager \
+ editormanager \
+ scriptmanager
+SOURCES += mainwindow.cpp \
+ welcomemode.cpp \
+ editmode.cpp \
+ tabpositionindicator.cpp \
+ fancyactionbar.cpp \
+ fancytabwidget.cpp \
+ flowlayout.cpp \
+ generalsettings.cpp \
+ filemanager.cpp \
+ uniqueidmanager.cpp \
+ messagemanager.cpp \
+ messageoutputwindow.cpp \
+ outputpane.cpp \
+ vcsmanager.cpp \
+ viewmanager.cpp \
+ versiondialog.cpp \
+ editormanager/editorgroup.cpp \
+ editormanager/editormanager.cpp \
+ editormanager/stackededitorgroup.cpp \
+ editormanager/editorsplitter.cpp \
+ editormanager/openeditorsview.cpp \
+ editormanager/openeditorswindow.cpp \
+ actionmanager/actionmanager.cpp \
+ actionmanager/command.cpp \
+ actionmanager/actioncontainer.cpp \
+ actionmanager/commandsfile.cpp \
+ dialogs/saveitemsdialog.cpp \
+ dialogs/newdialog.cpp \
+ dialogs/settingsdialog.cpp \
+ dialogs/shortcutsettings.cpp \
+ dialogs/openwithdialog.cpp \
+ progressmanager/progressmanager.cpp \
+ progressmanager/progressview.cpp \
+ progressmanager/progresspie.cpp \
+ progressmanager/futureprogress.cpp \
+ scriptmanager/scriptmanager.cpp \
+ scriptmanager/qworkbench_wrapper.cpp \
+ basemode.cpp \
+ baseview.cpp \
+ coreplugin.cpp \
+ variablemanager.cpp \
+ modemanager.cpp \
+ coreimpl.cpp \
+ basefilewizard.cpp \
+ plugindialog.cpp \
+ stylehelper.cpp \
+ inavigationwidgetfactory.cpp \
+ navigationwidget.cpp \
+ manhattanstyle.cpp \
+ minisplitter.cpp \
+ styleanimator.cpp \
+ findplaceholder.cpp \
+ rightpane.cpp \
+ sidebar.cpp \
+ fileiconprovider.cpp \
+ mimedatabase.cpp
+HEADERS += mainwindow.h \
+ welcomemode.h \
+ editmode.h \
+ tabpositionindicator.h \
+ fancyactionbar.h \
+ fancytabwidget.h \
+ flowlayout.h \
+ generalsettings.h \
+ filemanager.h \
+ uniqueidmanager.h \
+ messagemanager.h \
+ messageoutputwindow.h \
+ outputpane.h \
+ vcsmanager.h \
+ viewmanager.h \
+ editormanager/editorgroup.h \
+ editormanager/editormanager.h \
+ editormanager/stackededitorgroup.h \
+ editormanager/editorsplitter.h \
+ editormanager/openeditorsview.h \
+ editormanager/openeditorswindow.h \
+ editormanager/ieditor.h \
+ editormanager/ieditorfactory.h \
+ actionmanager/iactioncontainer.h \
+ actionmanager/actionmanagerinterface.h \
+ actionmanager/icommand.h \
+ actionmanager/actionmanager.h \
+ actionmanager/command.h \
+ actionmanager/actioncontainer.h \
+ actionmanager/commandsfile.h \
+ dialogs/saveitemsdialog.h \
+ dialogs/newdialog.h \
+ dialogs/settingsdialog.h \
+ dialogs/shortcutsettings.h \
+ dialogs/openwithdialog.h \
+ dialogs/iwizard.h \
+ dialogs/ioptionspage.h \
+ progressmanager/progressmanager.h \
+ progressmanager/progressview.h \
+ progressmanager/progresspie.h \
+ progressmanager/futureprogress.h \
+ progressmanager/progressmanagerinterface.h \
+ icontext.h \
+ icore.h \
+ ifile.h \
+ ifilefactory.h \
+ imode.h \
+ ioutputpane.h \
+ coreconstants.h \
+ iversioncontrol.h \
+ iview.h \
+ ifilewizardextension.h \
+ viewmanagerinterface.h \
+ icorelistener.h \
+ versiondialog.h \
+ scriptmanager/metatypedeclarations.h \
+ scriptmanager/qworkbench_wrapper.h \
+ scriptmanager/scriptmanagerinterface.h \
+ scriptmanager/scriptmanager.h \
+ core_global.h \
+ basemode.h \
+ baseview.h \
+ coreplugin.h \
+ variablemanager.h \
+ modemanager.h \
+ coreimpl.h \
+ basefilewizard.h \
+ plugindialog.h \
+ stylehelper.h \
+ inavigationwidgetfactory.h \
+ navigationwidget.h \
+ manhattanstyle.h \
+ minisplitter.h \
+ styleanimator.h \
+ findplaceholder.h \
+ rightpane.h \
+ sidebar.h \
+ fileiconprovider.h \
+ mimedatabase.h
+FORMS += dialogs/newdialog.ui \
+ dialogs/settingsdialog.ui \
+ dialogs/shortcutsettings.ui \
+ dialogs/saveitemsdialog.ui \
+ dialogs/openwithdialog.ui \
+ editormanager/openeditorsview.ui \
+ generalsettings.ui
+RESOURCES += core.qrc \
+ fancyactionbar.qrc
+
+contains(QT_CONFIG, webkit): {
+ QT += webkit
+ DEFINES += QT_WEBKIT
+}
diff --git a/src/plugins/coreplugin/coreplugin_dependencies.pri b/src/plugins/coreplugin/coreplugin_dependencies.pri
new file mode 100644
index 0000000000..8b548e7179
--- /dev/null
+++ b/src/plugins/coreplugin/coreplugin_dependencies.pri
@@ -0,0 +1,2 @@
+include(../../libs/extensionsystem/extensionsystem.pri)
+include(../../libs/utils/utils.pri)
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h
new file mode 100644
index 0000000000..4aa3854385
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IOPTIONSPAGE_H
+#define IOPTIONSPAGE_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtGui/QWidget>
+
+namespace Core {
+
+class CORE_EXPORT IOptionsPage : public QObject
+{
+ Q_OBJECT
+public:
+ IOptionsPage(QObject *parent = 0) : QObject(parent) {}
+ virtual ~IOptionsPage() {}
+
+ virtual QString name() const = 0;
+ virtual QString category() const = 0;
+ virtual QString trCategory() const = 0;
+
+ virtual QWidget *createPage(QWidget *parent) = 0;
+ virtual void finished(bool accepted) = 0;
+};
+
+} // namespace Core
+
+#endif // IOPTIONSPAGE_H
diff --git a/src/plugins/coreplugin/dialogs/iwizard.h b/src/plugins/coreplugin/dialogs/iwizard.h
new file mode 100644
index 0000000000..37457ba39b
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/iwizard.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IWIZARD_H
+#define IWIZARD_H
+
+#include <coreplugin/core_global.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QIcon;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class CORE_EXPORT IWizard
+ : public QObject
+{
+ Q_OBJECT
+public:
+ enum Kind {
+ FileWizard,
+ ClassWizard,
+ ProjectWizard
+ };
+
+ IWizard(QObject *parent = 0) : QObject(parent) {}
+
+ virtual Kind kind() const = 0;
+ virtual QIcon icon() const = 0;
+ virtual QString description() const = 0;
+ virtual QString name() const = 0;
+
+ virtual QString category() const = 0;
+ virtual QString trCategory() const = 0;
+
+ virtual QStringList runWizard(const QString &path, QWidget *parent) = 0;
+};
+} // namespace Core
+
+#endif // IWIZARD_H
diff --git a/src/plugins/coreplugin/dialogs/newdialog.cpp b/src/plugins/coreplugin/dialogs/newdialog.cpp
new file mode 100644
index 0000000000..e344dc34a0
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/newdialog.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "newdialog.h"
+#include "ui_newdialog.h"
+#include "basefilewizard.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/dialogs/iwizard.h>
+
+
+#include <QtGui/QHeaderView>
+#include <QtGui/QPushButton>
+
+Q_DECLARE_METATYPE(Core::IWizard*)
+
+static inline Core::IWizard *wizardOfItem(const QTreeWidgetItem *item = 0)
+{
+ if (!item)
+ return 0;
+ return qVariantValue<Core::IWizard*>(item->data(0, Qt::UserRole));
+}
+
+using namespace Core;
+using namespace Core::Internal;
+
+NewDialog::NewDialog(QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Core::Internal::Ui::NewDialog),
+ m_okButton(0)
+{
+ typedef QMap<QString, QTreeWidgetItem *> CategoryItemMap;
+ m_ui->setupUi(this);
+ m_okButton = m_ui->buttonBox->button(QDialogButtonBox::Ok);
+ m_okButton->setDefault(true);
+
+ m_ui->watermark->setPixmap(BaseFileWizard::watermark());
+
+ m_ui->templatesTree->header()->hide();
+ connect(m_ui->templatesTree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(currentItemChanged(QTreeWidgetItem*)));
+ connect(m_ui->templatesTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), m_okButton, SLOT(animateClick()));
+
+ connect(m_okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked()));
+ connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+void NewDialog::setWizards(const QList<IWizard*> wizards)
+{
+ typedef QMap<QString, QTreeWidgetItem *> CategoryItemMap;
+
+ CategoryItemMap categories;
+ QVariant wizardPtr;
+
+ m_ui->templatesTree->clear();
+ foreach (IWizard *wizard, wizards) {
+ // ensure category root
+ const QString categoryName = wizard->category();
+ CategoryItemMap::iterator cit = categories.find(categoryName);
+ if (cit == categories.end()) {
+ QTreeWidgetItem *categoryItem = new QTreeWidgetItem(m_ui->templatesTree);
+ categoryItem->setFlags(Qt::ItemIsEnabled);
+ categoryItem->setText(0, wizard->trCategory());
+ qVariantSetValue<IWizard*>(wizardPtr, 0);
+ categoryItem->setData(0, Qt::UserRole, wizardPtr);
+ cit = categories.insert(categoryName, categoryItem);
+ }
+ // add item
+ QTreeWidgetItem *wizardItem = new QTreeWidgetItem(cit.value(), QStringList(wizard->name()));
+ wizardItem->setIcon(0, wizard->icon());
+ qVariantSetValue<IWizard*>(wizardPtr, wizard);
+ wizardItem->setData(0, Qt::UserRole, wizardPtr);
+ wizardItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
+ }
+}
+
+Core::IWizard *NewDialog::showDialog()
+{
+ m_ui->templatesTree->expandAll();
+ if (QTreeWidgetItem *rootItem = m_ui->templatesTree->topLevelItem(0)) {
+ m_ui->templatesTree->scrollToItem(rootItem);
+ if (rootItem->childCount())
+ m_ui->templatesTree->setCurrentItem(rootItem->child(0));
+ }
+ updateOkButton();
+ if (exec() != Accepted)
+ return 0;
+ return currentWizard();
+}
+
+NewDialog::~NewDialog()
+{
+ delete m_ui;
+}
+
+IWizard *NewDialog::currentWizard() const
+{
+ return wizardOfItem(m_ui->templatesTree->currentItem());
+}
+
+void NewDialog::currentItemChanged(QTreeWidgetItem *cat)
+{
+
+ if (const IWizard *wizard = wizardOfItem(cat))
+ m_ui->descLabel->setText(wizard->description());
+ else
+ m_ui->descLabel->setText(QString());
+ updateOkButton();
+}
+
+void NewDialog::okButtonClicked()
+{
+ if (m_ui->templatesTree->currentItem())
+ accept();
+}
+
+
+void NewDialog::updateOkButton()
+{
+ m_okButton->setEnabled(currentWizard() != 0);
+}
diff --git a/src/plugins/coreplugin/dialogs/newdialog.h b/src/plugins/coreplugin/dialogs/newdialog.h
new file mode 100644
index 0000000000..84059b71a1
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/newdialog.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef NEWDIALOG_H
+#define NEWDIALOG_H
+
+#include <QtGui/QDialog>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+class QTreeWidgetItem;
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class IWizard;
+
+namespace Internal {
+
+namespace Ui {
+ class NewDialog;
+}
+
+class NewDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit NewDialog(QWidget *parent);
+ virtual ~NewDialog();
+
+ void setWizards(const QList<IWizard*> wizards);
+
+ Core::IWizard *showDialog();
+
+private slots:
+ void currentItemChanged(QTreeWidgetItem *cat);
+ void okButtonClicked();
+ void updateOkButton();
+
+private:
+ Core::IWizard *currentWizard() const;
+
+ Ui::NewDialog *m_ui;
+ QPushButton *m_okButton;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //NEWDIALOG_H
diff --git a/src/plugins/coreplugin/dialogs/newdialog.ui b/src/plugins/coreplugin/dialogs/newdialog.ui
new file mode 100644
index 0000000000..3941240768
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/newdialog.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Internal::NewDialog</class>
+ <widget class="QDialog" name="Core::Internal::NewDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>490</width>
+ <height>390</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>New Project</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QTreeWidget" name="templatesTree">
+ <property name="minimumSize">
+ <size>
+ <width>400</width>
+ <height>301</height>
+ </size>
+ </property>
+ <column>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="descLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="watermark">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </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>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/coreplugin/dialogs/openwithdialog.cpp b/src/plugins/coreplugin/dialogs/openwithdialog.cpp
new file mode 100644
index 0000000000..b388218474
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/openwithdialog.cpp
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "openwithdialog.h"
+
+#include <QtGui/QListWidget>
+#include <QtGui/QPushButton>
+#include <QtCore/QFileInfo>
+
+using namespace Core;
+using namespace Core::Internal;
+
+OpenWithDialog::OpenWithDialog(const QString &fileName, QWidget *parent) :
+ QDialog(parent)
+{
+ setupUi(this);
+ label->setText(tr("Open file '%1' with:").arg(QFileInfo(fileName).fileName()));
+ buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+ connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
+ this, SLOT(accept()));
+ connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
+ this, SLOT(reject()));
+ connect(editorListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
+ this, SLOT(accept()));
+ connect(editorListWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
+ this, SLOT(currentItemChanged(QListWidgetItem*,QListWidgetItem*)));
+
+ setOkButtonEnabled(false);
+}
+
+void OpenWithDialog::setOkButtonEnabled(bool v)
+{
+ buttonBox->button(QDialogButtonBox::Ok)->setEnabled(v);
+}
+
+void OpenWithDialog::setEditors(const QStringList &editors)
+{
+ foreach (const QString &e, editors)
+ editorListWidget->addItem(e);
+}
+
+QString OpenWithDialog::editor() const
+{
+ if (const QListWidgetItem *item = editorListWidget->currentItem())
+ return item->text();
+ return QString();
+}
+
+void OpenWithDialog::setCurrentEditor(int index)
+{
+ editorListWidget->setCurrentRow(index);
+}
+
+void OpenWithDialog::currentItemChanged(QListWidgetItem *current, QListWidgetItem *)
+{
+ setOkButtonEnabled(current);
+}
diff --git a/src/plugins/coreplugin/dialogs/openwithdialog.h b/src/plugins/coreplugin/dialogs/openwithdialog.h
new file mode 100644
index 0000000000..569f5eac7d
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/openwithdialog.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OPENWITHDIALOG_H
+#define OPENWITHDIALOG_H
+
+#include <QtGui/QDialog>
+#include "ui_openwithdialog.h"
+
+namespace Core {
+
+class ICore;
+
+namespace Internal {
+
+// Present the user with a file name and a list of available
+// editor kinds to choose from.
+class OpenWithDialog : public QDialog, public Ui::OpenWithDialog
+{
+ Q_OBJECT
+
+public:
+ OpenWithDialog(const QString &fileName, QWidget *parent);
+
+ void setEditors(const QStringList &);
+ QString editor() const;
+
+ void setCurrentEditor(int index);
+
+private slots:
+ void currentItemChanged(QListWidgetItem *, QListWidgetItem *);
+
+private:
+ void setOkButtonEnabled(bool);
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif
diff --git a/src/plugins/coreplugin/dialogs/openwithdialog.ui b/src/plugins/coreplugin/dialogs/openwithdialog.ui
new file mode 100644
index 0000000000..1ec069d598
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/openwithdialog.ui
@@ -0,0 +1,46 @@
+<ui version="4.0" >
+ <class>OpenWithDialog</class>
+ <widget class="QWidget" name="OpenWithDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>358</width>
+ <height>199</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Open File With...</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Open file extension with:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="editorListWidget" />
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp
new file mode 100644
index 0000000000..7c06c786fd
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp
@@ -0,0 +1,207 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "saveitemsdialog.h"
+#include "mainwindow.h"
+#include "vcsmanager.h"
+
+#include <coreplugin/ifile.h>
+
+#include <QtCore/QFileInfo>
+#include <QtGui/QPushButton>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QHeaderView>
+#include <QtGui/QCheckBox>
+#include <QtGui/QPushButton>
+
+using namespace Core;
+using namespace Core::Internal;
+
+FileItem::FileItem(QTreeWidget *tree, bool supportOpen, bool open, const QString &text)
+ : QTreeWidgetItem(tree)
+{
+ m_saveCheckBox = createCheckBox(tree, 0);
+ m_saveCheckBox->setChecked(true);
+
+ QFileInfo fi(text);
+ QString name = fi.fileName();
+ if (open)
+ name.append(tr(" [ReadOnly]"));
+
+ if (supportOpen) {
+ m_sccCheckBox = createCheckBox(tree, 1);
+ m_sccCheckBox->setEnabled(open);
+ m_sccCheckBox->setChecked(open);
+ connect(m_saveCheckBox, SIGNAL(stateChanged(int)),
+ this, SLOT(updateSCCCheckBox()));
+ setText(2, name);
+ setToolTip(2, text);
+ } else {
+ m_sccCheckBox = 0;
+ setText(2, name);
+ setToolTip(2, text);
+ }
+}
+
+QCheckBox *FileItem::createCheckBox(QTreeWidget *tree, int column)
+{
+ QWidget *w = new QWidget();
+ QHBoxLayout *l = new QHBoxLayout(w);
+ l->setMargin(0);
+ l->setSpacing(0);
+ QCheckBox *box = new QCheckBox(w);
+ l->addWidget(box);
+ l->setAlignment(box, Qt::AlignCenter);
+ w->setLayout(l);
+ tree->setItemWidget(this, column, w);
+ return box;
+}
+
+void FileItem::updateSCCCheckBox()
+{
+ if (!m_saveCheckBox->isChecked()) {
+ m_sccCheckBox->setEnabled(false);
+ m_sccCheckBox->setChecked(false);
+ } else {
+ m_sccCheckBox->setEnabled(true);
+ }
+}
+
+bool FileItem::shouldBeSaved() const
+{
+ return m_saveCheckBox->isChecked();
+}
+
+void FileItem::setShouldBeSaved(bool s)
+{
+ m_saveCheckBox->setChecked(s);
+}
+
+bool FileItem::shouldBeOpened() const
+{
+ if (m_sccCheckBox)
+ return m_sccCheckBox->isChecked();
+ return false;
+}
+
+
+
+SaveItemsDialog::SaveItemsDialog(MainWindow *mainWindow,
+ QMap<IFile*, QString> items)
+ : QDialog(mainWindow)
+{
+ m_ui.setupUi(this);
+ QPushButton *uncheckButton = m_ui.buttonBox->addButton(tr("Uncheck All"),
+ QDialogButtonBox::ActionRole);
+ QPushButton *discardButton = m_ui.buttonBox->addButton(tr("Discard All"),
+ QDialogButtonBox::DestructiveRole);
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setFocus(Qt::TabFocusReason);
+
+ m_ui.treeWidget->header()->setMovable(false);
+ m_ui.treeWidget->setRootIsDecorated(false);
+ m_ui.treeWidget->setColumnCount(2);
+
+ QStringList headers;
+ headers << tr("Save") << tr("File Name");
+
+ const bool hasVersionControl = true;
+ if (hasVersionControl) {
+ m_ui.treeWidget->setColumnCount(3);
+ headers.insert(1, tr("Open with SCC"));
+ }
+ m_ui.treeWidget->setHeaderLabels(headers);
+
+ FileItem *itm;
+ QMap<IFile*, QString>::const_iterator it = items.constBegin();
+ while (it != items.constEnd()) {
+ QString directory = QFileInfo(it.key()->fileName()).absolutePath();
+ bool fileHasVersionControl = mainWindow->vcsManager()->findVersionControlForDirectory(directory) != 0;
+ itm = new FileItem(m_ui.treeWidget, fileHasVersionControl,
+ it.key()->isReadOnly(), it.value());
+ m_itemMap.insert(itm, it.key());
+ ++it;
+ }
+
+ m_ui.treeWidget->resizeColumnToContents(0);
+ if (hasVersionControl)
+ m_ui.treeWidget->resizeColumnToContents(1);
+
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
+ this, SLOT(collectItemsToSave()));
+ connect(uncheckButton, SIGNAL(clicked()), this, SLOT(uncheckAll()));
+ connect(discardButton, SIGNAL(clicked()), this, SLOT(discardAll()));
+}
+
+void SaveItemsDialog::setMessage(const QString &msg)
+{
+ m_ui.msgLabel->setText(msg);
+}
+
+void SaveItemsDialog::collectItemsToSave()
+{
+ m_itemsToSave.clear();
+ m_itemsToOpen.clear();
+ QMap<FileItem*, IFile*>::const_iterator it = m_itemMap.constBegin();
+ while (it != m_itemMap.constEnd()) {
+ if (it.key()->shouldBeSaved())
+ m_itemsToSave << it.value();
+ if (it.key()->shouldBeOpened())
+ m_itemsToOpen.insert(it.value());
+ ++it;
+ }
+ accept();
+}
+
+void SaveItemsDialog::discardAll()
+{
+ uncheckAll();
+ collectItemsToSave();
+}
+
+QList<IFile*> SaveItemsDialog::itemsToSave() const
+{
+ return m_itemsToSave;
+}
+
+QSet<IFile*> SaveItemsDialog::itemsToOpen() const
+{
+ return m_itemsToOpen;
+}
+
+void SaveItemsDialog::uncheckAll()
+{
+ for (int i=0; i<m_ui.treeWidget->topLevelItemCount(); ++i) {
+ FileItem *item = static_cast<FileItem*>(m_ui.treeWidget->topLevelItem(i));
+ item->setShouldBeSaved(false);
+ }
+}
diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.h b/src/plugins/coreplugin/dialogs/saveitemsdialog.h
new file mode 100644
index 0000000000..52e43aab0a
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SAVEITEMSDIALOG_H
+#define SAVEITEMSDIALOG_H
+
+#include <QtCore/QMap>
+#include <QtGui/QDialog>
+
+#include "ui_saveitemsdialog.h"
+
+QT_BEGIN_NAMESPACE
+class QCheckBox;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class IFile;
+class EditorManager;
+
+namespace Internal {
+
+class MainWindow;
+
+class FileItem : public QObject, public QTreeWidgetItem
+{
+ Q_OBJECT
+
+public:
+ FileItem(QTreeWidget *tree, bool supportOpen,
+ bool open, const QString &text);
+ bool shouldBeSaved() const;
+ void setShouldBeSaved(bool s);
+ bool shouldBeOpened() const;
+
+private slots:
+ void updateSCCCheckBox();
+
+private:
+ QCheckBox *createCheckBox(QTreeWidget *tree, int column);
+ QCheckBox *m_saveCheckBox;
+ QCheckBox *m_sccCheckBox;
+};
+
+class SaveItemsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ SaveItemsDialog(MainWindow *mainWindow,
+ QMap<Core::IFile*, QString> items);
+
+ void setMessage(const QString &msg);
+
+ QList<Core::IFile*> itemsToSave() const;
+ QSet<Core::IFile*> itemsToOpen() const;
+
+private slots:
+ void collectItemsToSave();
+ void uncheckAll();
+ void discardAll();
+
+private:
+ Ui::SaveItemsDialog m_ui;
+ QMap<FileItem*, Core::IFile*> m_itemMap;
+ QList<Core::IFile*> m_itemsToSave;
+ QSet<Core::IFile*> m_itemsToOpen;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // SAVEITEMSDIALOG_H
diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.ui b/src/plugins/coreplugin/dialogs/saveitemsdialog.ui
new file mode 100644
index 0000000000..85931a1dab
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.ui
@@ -0,0 +1,66 @@
+<ui version="4.0" >
+ <class>SaveItemsDialog</class>
+ <widget class="QDialog" name="SaveItemsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>200</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Save Changes</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="msgLabel" >
+ <property name="text" >
+ <string>Save the changes of the following items:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="treeWidget" />
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>treeWidget</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SaveItemsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>199</x>
+ <y>174</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>199</x>
+ <y>99</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp
new file mode 100644
index 0000000000..78d839bf1a
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingsdialog.h"
+#include "coreimpl.h"
+
+#include <QtGui/QHeaderView>
+#include <QtGui/QPushButton>
+
+using namespace Core;
+using namespace Core::Internal;
+
+SettingsDialog::SettingsDialog(QWidget *parent, const QString &initialCategory,
+ const QString &initialPage)
+ : QDialog(parent)
+{
+ setupUi(this);
+ buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+ pageTree->header()->setVisible(false);
+
+ connect(pageTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(pageSelected(QTreeWidgetItem *)));
+
+ QMap<QString, QTreeWidgetItem *> categories;
+
+ QList<IOptionsPage*> pages =
+ CoreImpl::instance()->pluginManager()->getObjects<IOptionsPage>();
+
+ int index = 0;
+ foreach(IOptionsPage *page, pages) {
+ QTreeWidgetItem *item = new QTreeWidgetItem();
+ item->setText(0, page->name());
+ item->setData(0, Qt::UserRole, index);
+
+ QStringList categoriesId = page->category().split(QLatin1Char('|'));
+ QStringList trCategories = page->trCategory().split(QLatin1Char('|'));
+ QString currentCategory = categoriesId.at(0);
+
+ QTreeWidgetItem *treeitem;
+ if (!categories.contains(currentCategory)) {
+ treeitem = new QTreeWidgetItem(pageTree);
+ treeitem->setText(0, trCategories.at(0));
+ treeitem->setData(0, Qt::UserRole, index);
+ categories.insert(currentCategory, treeitem);
+ }
+
+ int catCount = 1;
+ while (catCount < categoriesId.count()) {
+ if(!categories.contains(currentCategory + QLatin1Char('|') + categoriesId.at(catCount))) {
+ treeitem = new QTreeWidgetItem(categories.value(currentCategory));
+ currentCategory += QLatin1Char('|') + categoriesId.at(catCount);
+ treeitem->setText(0, trCategories.at(catCount));
+ treeitem->setData(0, Qt::UserRole, index);
+ categories.insert(currentCategory, treeitem);
+ } else {
+ currentCategory += QLatin1Char('|') + categoriesId.at(catCount);
+ }
+ ++catCount;
+ }
+
+ categories.value(currentCategory)->addChild(item);
+
+ m_pages.append(page);
+ stackedPages->addWidget(page->createPage(stackedPages));
+
+ if (page->name() == initialPage && currentCategory == initialCategory) {
+ stackedPages->setCurrentIndex(stackedPages->count());
+ pageTree->setCurrentItem(item);
+ }
+
+ index++;
+ }
+
+ QList<int> sizes;
+ sizes << 150 << 300;
+ splitter->setSizes(sizes);
+
+ splitter->setStretchFactor(splitter->indexOf(pageTree), 0);
+ splitter->setStretchFactor(splitter->indexOf(layoutWidget), 1);
+}
+
+SettingsDialog::~SettingsDialog()
+{
+
+}
+
+void SettingsDialog::pageSelected(QTreeWidgetItem *)
+{
+ QTreeWidgetItem *item = pageTree->currentItem();
+ int index = item->data(0, Qt::UserRole).toInt();
+ stackedPages->setCurrentIndex(index);
+}
+
+void SettingsDialog::accept()
+{
+ foreach(IOptionsPage *page, m_pages) {
+ page->finished(true);
+ }
+ done(QDialog::Accepted);
+}
+
+void SettingsDialog::reject()
+{
+ foreach(IOptionsPage *page, m_pages) {
+ page->finished(false);
+ }
+ done(QDialog::Rejected);
+}
diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.h b/src/plugins/coreplugin/dialogs/settingsdialog.h
new file mode 100644
index 0000000000..2d80aa643c
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/settingsdialog.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include "ui_settingsdialog.h"
+
+#include <QtCore/QList>
+
+#include "coreplugin/dialogs/ioptionspage.h"
+
+namespace Core {
+namespace Internal {
+
+class SettingsDialog : public QDialog, public ::Ui::SettingsDialog
+{
+ Q_OBJECT
+
+public:
+ SettingsDialog(QWidget *parent,
+ const QString &initialCategory = QString(),
+ const QString &initialPage = QString());
+ ~SettingsDialog();
+
+private slots:
+ void pageSelected(QTreeWidgetItem *cat);
+ void accept();
+ void reject();
+
+private:
+ QList<Core::IOptionsPage*> m_pages;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // SETTINGSDIALOG_H
diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.ui b/src/plugins/coreplugin/dialogs/settingsdialog.ui
new file mode 100644
index 0000000000..9d2475536c
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/settingsdialog.ui
@@ -0,0 +1,121 @@
+<ui version="4.0" >
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>697</width>
+ <height>476</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Options</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QTreeWidget" name="pageTree" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="columnCount" >
+ <number>1</number>
+ </property>
+ <column>
+ <property name="text" >
+ <string>0</string>
+ </property>
+ </column>
+ </widget>
+ <widget class="QWidget" name="layoutWidget" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedPages" >
+ <property name="minimumSize" >
+ <size>
+ <width>350</width>
+ <height>250</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>297</x>
+ <y>361</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>297</x>
+ <y>193</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>297</x>
+ <y>361</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>297</x>
+ <y>193</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
new file mode 100644
index 0000000000..aeefebdf24
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
@@ -0,0 +1,379 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "shortcutsettings.h"
+#include "ui_shortcutsettings.h"
+#include "actionmanager.h"
+#include "command.h"
+#include "coreconstants.h"
+#include "coreimpl.h"
+#include "commandsfile.h"
+#include "filemanager.h"
+
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/icommand.h>
+
+#include <QtGui/QKeyEvent>
+#include <QtGui/QShortcut>
+#include <QtGui/QHeaderView>
+#include <QtGui/QFileDialog>
+#include <QtDebug>
+
+Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*);
+
+using namespace Core;
+using namespace Core::Internal;
+
+ShortcutSettings::ShortcutSettings(QObject *parent)
+ : IOptionsPage(parent)
+{
+}
+
+ShortcutSettings::~ShortcutSettings()
+{
+}
+
+// IOptionsPage
+QString ShortcutSettings::name() const
+{
+ return tr("Keyboard");
+}
+
+QString ShortcutSettings::category() const
+{
+ return QLatin1String("Environment");
+}
+
+QString ShortcutSettings::trCategory() const
+{
+ return tr("Environment");
+}
+
+QWidget *ShortcutSettings::createPage(QWidget *parent)
+{
+ m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0;
+
+ m_page = new Ui_ShortcutSettings();
+ QWidget *w = new QWidget(parent);
+ m_page->setupUi(w);
+
+ m_page->resetButton->setIcon(QIcon(Constants::ICON_RESET));
+ m_page->shortcutEdit->installEventFilter(this);
+
+ connect(m_page->resetButton, SIGNAL(clicked()),
+ this, SLOT(resetKeySequence()));
+ connect(m_page->removeButton, SIGNAL(clicked()),
+ this, SLOT(removeKeySequence()));
+ connect(m_page->exportButton, SIGNAL(clicked()),
+ this, SLOT(exportAction()));
+ connect(m_page->importButton, SIGNAL(clicked()),
+ this, SLOT(importAction()));
+ connect(m_page->defaultButton, SIGNAL(clicked()),
+ this, SLOT(defaultAction()));
+
+ initialize();
+
+ m_page->commandList->sortByColumn(0, Qt::AscendingOrder);
+
+ connect(m_page->filterEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
+ connect(m_page->commandList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(commandChanged(QTreeWidgetItem *)));
+ connect(m_page->shortcutEdit, SIGNAL(textChanged(QString)), this, SLOT(keyChanged()));
+
+ QHeaderView *hv = m_page->commandList->header();
+ hv->resizeSection(0, 210);
+ hv->resizeSection(1, 110);
+ hv->setStretchLastSection(true);
+
+ commandChanged(0);
+
+ return w;
+}
+
+void ShortcutSettings::finished(bool accepted)
+{
+ if (accepted) {
+ foreach(ShortcutItem *item, m_scitems) {
+ item->m_cmd->setKeySequence(item->m_key);
+ }
+ }
+
+ qDeleteAll(m_scitems);
+ m_scitems.clear();
+}
+
+bool ShortcutSettings::eventFilter(QObject *o, QEvent *e)
+{
+ Q_UNUSED(o);
+
+ if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent *k = static_cast<QKeyEvent*>(e);
+ handleKeyEvent(k);
+ return true;
+ }
+
+ if ( e->type() == QEvent::Shortcut ||
+ e->type() == QEvent::ShortcutOverride ||
+ e->type() == QEvent::KeyRelease )
+ return true;
+
+ return false;
+}
+
+void ShortcutSettings::commandChanged(QTreeWidgetItem *current)
+{
+ if (!current || !current->data(0, Qt::UserRole).isValid()) {
+ m_page->shortcutEdit->setText("");
+ m_page->seqGrp->setEnabled(false);
+ return;
+ }
+ m_page->seqGrp->setEnabled(true);
+ ShortcutItem *scitem = qVariantValue<ShortcutItem *>(current->data(0, Qt::UserRole));
+ setKeySequence(scitem->m_key);
+}
+
+void ShortcutSettings::filterChanged(const QString &f)
+{
+ for (int i=0; i<m_page->commandList->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = m_page->commandList->topLevelItem(i);
+ item->setHidden(filter(f, item));
+ }
+}
+
+void ShortcutSettings::keyChanged()
+{
+ QTreeWidgetItem *current = m_page->commandList->currentItem();
+ if (current && current->data(0, Qt::UserRole).isValid()) {
+ ShortcutItem *scitem = qVariantValue<ShortcutItem *>(current->data(0, Qt::UserRole));
+ scitem->m_key = QKeySequence(m_key[0], m_key[1], m_key[2], m_key[3]);
+ current->setText(2, scitem->m_key);
+ }
+}
+
+void ShortcutSettings::setKeySequence(const QKeySequence &key)
+{
+ m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0;
+ m_keyNum = key.count();
+ for (int i = 0; i < m_keyNum; ++i) {
+ m_key[i] = key[i];
+ }
+ m_page->shortcutEdit->setText(key);
+}
+
+bool ShortcutSettings::filter(const QString &f, const QTreeWidgetItem *item)
+{
+ if (item->childCount() == 0) {
+ if (f.isEmpty())
+ return false;
+ for (int i = 0; i < item->columnCount(); ++i) {
+ if(item->text(i).contains(f, Qt::CaseInsensitive))
+ return false;
+ }
+ return true;
+ }
+
+ bool found = false;
+ for (int i = 0; i < item->childCount(); ++i) {
+ QTreeWidgetItem *citem = item->child(i);
+ if (filter(f, citem)) {
+ citem->setHidden(true);
+ } else {
+ citem->setHidden(false);
+ found = true;
+ }
+ }
+ return !found;
+}
+
+void ShortcutSettings::resetKeySequence()
+{
+ QTreeWidgetItem *current = m_page->commandList->currentItem();
+ if (current && current->data(0, Qt::UserRole).isValid()) {
+ ShortcutItem *scitem = qVariantValue<ShortcutItem *>(current->data(0, Qt::UserRole));
+ setKeySequence(scitem->m_cmd->defaultKeySequence());
+ }
+}
+
+void ShortcutSettings::removeKeySequence()
+{
+ m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0;
+ m_page->shortcutEdit->clear();
+}
+
+void ShortcutSettings::importAction()
+{
+ UniqueIDManager *uidm =
+ CoreImpl::instance()->uniqueIDManager();
+
+ QString fileName = QFileDialog::getOpenFileName(0, tr("Import Keyboard Mapping Scheme"),
+ CoreImpl::instance()->resourcePath() + "/schemes/",
+ tr("Keyboard Mapping Scheme (*.kms)"));
+ if (!fileName.isEmpty()) {
+ CommandsFile cf(fileName);
+ QMap<QString, QKeySequence> mapping = cf.importCommands();
+
+ foreach(ShortcutItem *item, m_scitems) {
+ QString sid = uidm->stringForUniqueIdentifier(item->m_cmd->id());
+ if (mapping.contains(sid)) {
+ item->m_key = mapping.value(sid);
+ item->m_item->setText(2, item->m_key);
+ if (item->m_item == m_page->commandList->currentItem())
+ commandChanged(item->m_item);
+ }
+ }
+ }
+}
+
+void ShortcutSettings::defaultAction()
+{
+ foreach(ShortcutItem *item, m_scitems) {
+ item->m_key = item->m_cmd->defaultKeySequence();
+ item->m_item->setText(2, item->m_key);
+ if (item->m_item == m_page->commandList->currentItem())
+ commandChanged(item->m_item);
+ }
+}
+
+void ShortcutSettings::exportAction()
+{
+ QString fileName = CoreImpl::instance()->fileManager()->getSaveFileNameWithExtension(
+ tr("Export Keyboard Mapping Scheme"),
+ CoreImpl::instance()->resourcePath() + "/schemes/",
+ tr("Keyboard Mapping Scheme (*.kms)"),
+ ".kms");
+ if (!fileName.isEmpty()) {
+ CommandsFile cf(fileName);
+ cf.exportCommands(m_scitems);
+ }
+}
+
+void ShortcutSettings::initialize()
+{
+ QMap<QString, QTreeWidgetItem *> categories;
+
+ m_am = ActionManager::instance();
+ UniqueIDManager *uidm =
+ CoreImpl::instance()->uniqueIDManager();
+
+ QList<Command *> cmds = m_am->commands();
+ for (int i = 0; i < cmds.size(); ++i) {
+ Command *c = cmds.at(i);
+ if (c->hasAttribute(Command::CA_NonConfigureable))
+ continue;
+ if (c->action() && c->action()->isSeparator())
+ continue;
+
+ QTreeWidgetItem *item = 0;
+ ShortcutItem *s = new ShortcutItem;
+ m_scitems << s;
+ if (c->category().isEmpty()) {
+ item = new QTreeWidgetItem(m_page->commandList);
+ } else {
+ if (!categories.contains(c->category())) {
+ QTreeWidgetItem *cat = new QTreeWidgetItem(m_page->commandList);
+ cat->setText(0, c->category());
+ categories.insert(c->category(), cat);
+ cat->setExpanded(true);
+ }
+ item = new QTreeWidgetItem(categories.value(c->category()));
+ }
+ s->m_cmd = c;
+ s->m_item = item;
+
+ item->setText(0, uidm->stringForUniqueIdentifier(c->id()));
+
+ if (c->action()) {
+ QString text = c->hasAttribute(Command::CA_UpdateText) && !c->defaultText().isNull() ? c->defaultText() : c->action()->text();
+ s->m_key = c->action()->shortcut();
+ item->setText(1, text);
+ } else {
+ s->m_key = c->shortcut()->key();
+ item->setText(1, c->shortcut()->whatsThis());
+ }
+
+ item->setText(2, s->m_key);
+ item->setData(0, Qt::UserRole, qVariantFromValue(s));
+ }
+}
+
+void ShortcutSettings::handleKeyEvent(QKeyEvent *e)
+{
+ int nextKey = e->key();
+ if ( m_keyNum > 3 ||
+ nextKey == Qt::Key_Control ||
+ nextKey == Qt::Key_Shift ||
+ nextKey == Qt::Key_Meta ||
+ nextKey == Qt::Key_Alt )
+ return;
+
+ nextKey |= translateModifiers(e->modifiers(), e->text());
+ switch (m_keyNum) {
+ case 0:
+ m_key[0] = nextKey;
+ break;
+ case 1:
+ m_key[1] = nextKey;
+ break;
+ case 2:
+ m_key[2] = nextKey;
+ break;
+ case 3:
+ m_key[3] = nextKey;
+ break;
+ default:
+ break;
+ }
+ m_keyNum++;
+ QKeySequence ks(m_key[0], m_key[1], m_key[2], m_key[3]);
+ m_page->shortcutEdit->setText(ks);
+ e->accept();
+}
+
+int ShortcutSettings::translateModifiers(Qt::KeyboardModifiers state,
+ const QString &text)
+{
+ int result = 0;
+ // The shift modifier only counts when it is not used to type a symbol
+ // that is only reachable using the shift key anyway
+ if ((state & Qt::ShiftModifier) && (text.size() == 0
+ || !text.at(0).isPrint()
+ || text.at(0).isLetter()
+ || text.at(0).isSpace()))
+ result |= Qt::SHIFT;
+ if (state & Qt::ControlModifier)
+ result |= Qt::CTRL;
+ if (state & Qt::MetaModifier)
+ result |= Qt::META;
+ if (state & Qt::AltModifier)
+ result |= Qt::ALT;
+ return result;
+}
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.h b/src/plugins/coreplugin/dialogs/shortcutsettings.h
new file mode 100644
index 0000000000..38dfb88894
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SHORTCUTSETTINGS_H
+#define SHORTCUTSETTINGS_H
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtCore/QObject>
+#include <QtGui/QKeySequence>
+#include <QtGui/QTreeWidgetItem>
+#include <QtGui/QKeyEvent>
+
+QT_BEGIN_NAMESPACE
+class Ui_ShortcutSettings;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class ICommand;
+
+namespace Internal {
+
+class ActionManager;
+class Command;
+class MainWindow;
+
+struct ShortcutItem {
+ ICommand *m_cmd;
+ QKeySequence m_key;
+ QTreeWidgetItem *m_item;
+};
+
+
+class ShortcutSettings : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ ShortcutSettings(QObject *parent = 0);
+ ~ShortcutSettings();
+
+ // IOptionsPage
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+protected:
+ bool eventFilter(QObject *o, QEvent *e);
+
+private slots:
+ void commandChanged(QTreeWidgetItem *current);
+ void filterChanged(const QString &f);
+ void keyChanged();
+ void resetKeySequence();
+ void removeKeySequence();
+ void importAction();
+ void exportAction();
+ void defaultAction();
+
+private:
+ void setKeySequence(const QKeySequence &key);
+ bool filter(const QString &f, const QTreeWidgetItem *item);
+ void initialize();
+
+ void handleKeyEvent(QKeyEvent *e);
+ int translateModifiers(Qt::KeyboardModifiers state, const QString &text);
+
+ QList<ShortcutItem *> m_scitems;
+ ActionManager *m_am;
+ int m_key[4], m_keyNum;
+ Ui_ShortcutSettings *m_page;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // SHORTCUTSETTINGS_H
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.ui b/src/plugins/coreplugin/dialogs/shortcutsettings.ui
new file mode 100644
index 0000000000..4faaec4b32
--- /dev/null
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.ui
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ShortcutSettings</class>
+ <widget class="QWidget" name="ShortcutSettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>568</width>
+ <height>451</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Keyboard Shortcuts</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="filterLabel">
+ <property name="text">
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="filterEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="commandList">
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="columnCount">
+ <number>3</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>Command</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Label</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Shortcut</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QPushButton" name="defaultButton">
+ <property name="text">
+ <string>Defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="importButton">
+ <property name="text">
+ <string>Import...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="exportButton">
+ <property name="text">
+ <string>Export...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="seqGrp">
+ <property name="title">
+ <string>Key Sequence</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Shortcut:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="shortcutEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="resetButton">
+ <property name="toolTip">
+ <string>Reset</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../core.qrc">
+ <normaloff>:/qworkbench/images/reset.png</normaloff>:/qworkbench/images/reset.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="removeButton">
+ <property name="toolTip">
+ <string>Remove</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../core.qrc">
+ <normaloff>:/qworkbench/images/clear.png</normaloff>:/qworkbench/images/clear.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="infoLabel">
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../core.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plugins/coreplugin/editmode.cpp b/src/plugins/coreplugin/editmode.cpp
new file mode 100644
index 0000000000..088cd69f37
--- /dev/null
+++ b/src/plugins/coreplugin/editmode.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "editmode.h"
+#include "editormanager.h"
+#include "coreconstants.h"
+#include "coreimpl.h"
+#include "modemanager.h"
+#include "uniqueidmanager.h"
+#include "minisplitter.h"
+#include "findplaceholder.h"
+#include "outputpane.h"
+#include "navigationwidget.h"
+#include "rightpane.h"
+
+#include <QtCore/QLatin1String>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QWidget>
+#include <QtGui/QSplitter>
+
+using namespace Core;
+using namespace Core::Internal;
+
+EditMode::EditMode(EditorManager *editorManager):
+ m_editorManager(editorManager),
+ m_splitter(new MiniSplitter),
+ m_rightSplitWidgetLayout(new QVBoxLayout)
+{
+ m_rightSplitWidgetLayout->setSpacing(0);
+ m_rightSplitWidgetLayout->setMargin(0);
+ QWidget *rightSplitWidget = new QWidget;
+ rightSplitWidget->setLayout(m_rightSplitWidgetLayout);
+ m_rightSplitWidgetLayout->insertWidget(0, new Core::EditorManagerPlaceHolder(this));
+ m_rightSplitWidgetLayout->addWidget(new Core::FindToolBarPlaceHolder(this));
+
+ MiniSplitter *rightPaneSplitter = new MiniSplitter;
+ rightPaneSplitter->insertWidget(0, rightSplitWidget);
+ rightPaneSplitter->insertWidget(1, new RightPanePlaceHolder(this));
+ rightPaneSplitter->setStretchFactor(0, 1);
+ rightPaneSplitter->setStretchFactor(1, 0);
+
+ MiniSplitter *splitter = new MiniSplitter;
+ splitter->setOrientation(Qt::Vertical);
+ splitter->insertWidget(0, rightPaneSplitter);
+ splitter->insertWidget(1, new Core::OutputPanePlaceHolder(this));
+ splitter->setStretchFactor(0, 3);
+ splitter->setStretchFactor(1, 0);
+
+ m_splitter->insertWidget(0, new NavigationWidgetPlaceHolder(this));
+ m_splitter->insertWidget(1, splitter);
+ m_splitter->setStretchFactor(0, 0);
+ m_splitter->setStretchFactor(1, 1);
+
+ ModeManager *modeManager = ModeManager::instance();
+ connect(modeManager, SIGNAL(currentModeChanged(Core::IMode*)),
+ this, SLOT(grabEditorManager(Core::IMode*)));
+ m_splitter->setFocusProxy(m_editorManager);
+}
+
+EditMode::~EditMode()
+{
+ // Make sure the editor manager does not get deleted
+ m_editorManager->setParent(0);
+ delete m_splitter;
+}
+
+QString EditMode::name() const
+{
+ return QLatin1String("Edit");
+}
+
+QIcon EditMode::icon() const
+{
+ return QIcon(QLatin1String(":/fancyactionbar/images/mode_Edit.png"));
+}
+
+int EditMode::priority() const
+{
+ return Constants::P_MODE_EDIT;
+}
+
+QWidget* EditMode::widget()
+{
+ return m_splitter;
+}
+
+const char* EditMode::uniqueModeName() const
+{
+ return Constants::MODE_EDIT;
+}
+
+QList<int> EditMode::context() const
+{
+ static QList<int> contexts = QList<int>() <<
+ CoreImpl::instance()->uniqueIDManager()->uniqueIdentifier(Constants::C_EDIT_MODE) <<
+ CoreImpl::instance()->uniqueIDManager()->uniqueIdentifier(Constants::C_EDITORMANAGER) <<
+ CoreImpl::instance()->uniqueIDManager()->uniqueIdentifier(Constants::C_NAVIGATION_PANE);
+ return contexts;
+}
+
+void EditMode::grabEditorManager(Core::IMode *mode)
+{
+ if (mode != this)
+ return;
+
+ if (m_editorManager->currentEditor())
+ m_editorManager->currentEditor()->widget()->setFocus();
+}
diff --git a/src/plugins/coreplugin/editmode.h b/src/plugins/coreplugin/editmode.h
new file mode 100644
index 0000000000..234c4aab9e
--- /dev/null
+++ b/src/plugins/coreplugin/editmode.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EDITMODE_H
+#define EDITMODE_H
+
+#include <coreplugin/imode.h>
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QSplitter;
+class QWidget;
+class QVBoxLayout;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class EditorManager;
+
+namespace Internal {
+
+class EditMode : public Core::IMode
+{
+ Q_OBJECT
+
+public:
+ EditMode(EditorManager *editorManager);
+ ~EditMode();
+
+ // IMode
+ QString name() const;
+ QIcon icon() const;
+ int priority() const;
+ QWidget* widget();
+ const char* uniqueModeName() const;
+ QList<int> context() const;
+
+private slots:
+ void grabEditorManager(Core::IMode *mode);
+
+private:
+ EditorManager *m_editorManager;
+ QSplitter *m_splitter;
+ QVBoxLayout *m_rightSplitWidgetLayout;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // EDITMODE_H
diff --git a/src/plugins/coreplugin/editormanager/editorgroup.cpp b/src/plugins/coreplugin/editormanager/editorgroup.cpp
new file mode 100644
index 0000000000..53b61c74fd
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/editorgroup.cpp
@@ -0,0 +1,337 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "editorgroup.h"
+#include "editormanager.h"
+
+#include <coreplugin/coreconstants.h>
+
+#include <QtCore/QDir>
+#include <QtGui/QPainter>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleOption>
+#include <QtCore/QtDebug>
+#ifdef Q_WS_MAC
+#include <QtGui/QMacStyle>
+#endif
+
+Q_DECLARE_METATYPE(Core::IEditor*)
+
+using namespace Core;
+using namespace Core::Internal;
+
+namespace Core {
+namespace Internal {
+class EditorList;
+}
+}
+
+QDataStream &operator<<(QDataStream &out, const Core::Internal::EditorList &list);
+QDataStream &operator>>(QDataStream &in, Core::Internal::EditorList &list);
+
+namespace Core {
+namespace Internal {
+
+class EditorList
+{
+public:
+ quint32 currentEditorIndex;
+ void append(Core::IEditor *editor);
+ QString fileNameAt(int index);
+ QString editorKindAt(int index);
+ int count();
+
+private:
+ QList<QPair<QString,QString> > editorinfo;
+
+ friend QDataStream &::operator<<(QDataStream &out, const EditorList &list);
+ friend QDataStream &::operator>>(QDataStream &in, EditorList &list);
+};
+
+} // namespace Internal
+} // namespace Core
+
+//================EditorModel====================
+int EditorModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 1;
+}
+
+int EditorModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_editors.count();
+}
+
+QModelIndex EditorModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ if (column != 0 || row < 0 || row >= m_editors.count())
+ return QModelIndex();
+ return createIndex(row, column);
+}
+
+QVariant EditorModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ IEditor *editor = m_editors.at(index.row());
+ Q_ASSERT(editor);
+ switch (role) {
+ case Qt::DisplayRole:
+ return editor->file()->isModified()
+ ?editor->displayName()+QLatin1String("*")
+ :editor->displayName();
+ case Qt::DecorationRole:
+ return editor->file()->isReadOnly()
+ ?QIcon(QLatin1String(":/qworkbench/images/locked.png"))
+ :QIcon();
+ case Qt::ToolTipRole:
+ return editor->file()->fileName().isEmpty()
+ ?editor->displayName()
+ :QDir::toNativeSeparators(editor->file()->fileName());
+ case Qt::UserRole:
+ return qVariantFromValue(editor);
+ default:
+ return QVariant();
+ }
+ return QVariant();
+}
+
+QModelIndex EditorModel::indexOf(IEditor *editor) const
+{
+ int idx = m_editors.indexOf(editor);
+ if (idx < 0)
+ return QModelIndex();
+ return createIndex(idx, 0);
+}
+
+//================EditorGroupContext===============
+
+EditorGroupContext::EditorGroupContext(EditorGroup *editorGroup)
+ : IContext(editorGroup),
+ m_context(QList<int>() << Constants::C_GLOBAL_ID),
+ m_editorGroup(editorGroup)
+{
+}
+QList<int> EditorGroupContext::context() const
+{
+ return m_context;
+}
+
+QWidget *EditorGroupContext::widget()
+{
+ return m_editorGroup;
+}
+
+EditorGroup *EditorGroupContext::editorGroup()
+{
+ return m_editorGroup;
+}
+
+//================EditorGroup=================
+
+EditorGroup::EditorGroup(QWidget *parent)
+ : QFrame(parent),
+ m_contextObject(new EditorGroupContext(this))
+{
+ setFocusPolicy(Qt::StrongFocus);
+
+ m_model = new EditorModel(this);
+}
+
+QSize EditorGroup::minimumSizeHint() const
+{
+ return QSize(10, 10);
+}
+
+void EditorGroup::focusInEvent(QFocusEvent *)
+{
+ update();
+}
+
+void EditorGroup::focusOutEvent(QFocusEvent *)
+{
+ update();
+}
+
+void EditorGroup::paintEvent(QPaintEvent *e)
+{
+ QFrame::paintEvent(e);
+ if (editorCount() == 0) {
+ QPainter painter(this);
+
+ // Discreet indication where an editor would be
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setPen(Qt::NoPen);
+ QColor shadeBrush(Qt::black);
+ shadeBrush.setAlpha(10);
+ painter.setBrush(shadeBrush);
+ const int r = 3;
+ painter.drawRoundedRect(rect().adjusted(r, r, -r, -r), r * 2, r * 2);
+
+ if (hasFocus()) {
+#ifdef Q_WS_MAC
+ // With QMacStyle, we have to draw our own focus rect, since I didn't find
+ // a way to draw the nice mac focus rect _inside_ this widget
+ if (qobject_cast<QMacStyle *>(style())) {
+ painter.setPen(Qt::DotLine);
+ painter.setBrush(Qt::NoBrush);
+ painter.setOpacity(0.75);
+ painter.drawRect(rect());
+ } else {
+#endif
+ QStyleOptionFocusRect option;
+ option.initFrom(this);
+ option.backgroundColor = palette().color(QPalette::Background);
+
+ // Some styles require a certain state flag in order to draw the focus rect
+ option.state |= QStyle::State_KeyboardFocusChange;
+
+ style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter);
+#ifdef Q_WS_MAC
+ }
+#endif
+ }
+ }
+}
+
+void EditorGroup::moveEditorsFromGroup(EditorGroup *group)
+{
+ foreach (IEditor *editor, group->editors()) {
+ group->removeEditor(editor);
+ addEditor(editor);
+ }
+}
+
+void EditorGroup::moveEditorFromGroup(EditorGroup *group, IEditor *editor)
+{
+ group->removeEditor(editor);
+ addEditor(editor);
+}
+
+QByteArray EditorGroup::saveState() const
+{
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::WriteOnly);
+ EditorList editorinfo;
+ IEditor *curr = currentEditor();
+ QList<IEditor *> editors = editorsInNaturalOrder();
+ for (int j = 0; j < editors.count(); ++j) {
+ IEditor *editor = editors.at(j);
+ if (editor == curr)
+ editorinfo.currentEditorIndex = j;
+ editorinfo.append(editor);
+ }
+ stream << editorinfo;
+ return bytes;
+}
+
+bool EditorGroup::restoreState(const QByteArray &state)
+{
+ QDataStream in(state);
+ EditorManager *em = EditorManager::instance();
+ EditorList editors;
+ in >> editors;
+ IEditor *currentEditor = 0;
+ IEditor *editor;
+ int savedIndex = editors.currentEditorIndex;
+ for (int j = 0; j < editors.count(); ++j) {
+ editor = em->restoreEditor(editors.fileNameAt(j), editors.editorKindAt(j), this);
+ if (j == savedIndex)
+ currentEditor = editor;
+ }
+ if (currentEditor)
+ setCurrentEditor(currentEditor);
+ return true;
+}
+
+void EditorGroup::addEditor(IEditor *editor)
+{
+ m_model->addEditor(editor);
+}
+
+void EditorGroup::insertEditor(int i, IEditor *editor)
+{
+ m_model->insertEditor(i, editor);
+}
+
+void EditorGroup::removeEditor(IEditor *editor)
+{
+ m_model->removeEditor(editor);
+}
+
+void EditorGroup::showEditorInfoBar(const QString &, const QString &, const QString &, QObject *, const char *)
+{
+}
+
+void EditorGroup::hideEditorInfoBar(const QString &)
+{
+}
+
+void EditorList::append(IEditor *editor)
+{
+ if (editor->file()->fileName().isEmpty())
+ return;
+ editorinfo << qMakePair(editor->file()->fileName(), QString(editor->kind()));
+}
+
+QDataStream &operator<<(QDataStream &out, const EditorList &list)
+{
+ //todo: versioning
+ out << list.currentEditorIndex << list.editorinfo;
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, EditorList &list)
+{
+ //todo: versioning
+ in >> list.currentEditorIndex;
+ in >> list.editorinfo;
+ return in;
+}
+
+QString EditorList::fileNameAt(int index)
+{
+ return editorinfo.at(index).first;
+}
+
+QString EditorList::editorKindAt(int index)
+{
+ return editorinfo.at(index).second;
+}
+
+int EditorList::count()
+{
+ return editorinfo.count();
+}
diff --git a/src/plugins/coreplugin/editormanager/editorgroup.h b/src/plugins/coreplugin/editormanager/editorgroup.h
new file mode 100644
index 0000000000..eca333c4df
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/editorgroup.h
@@ -0,0 +1,165 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EDITORGROUP_H
+#define EDITORGROUP_H
+
+#include <coreplugin/icontext.h>
+
+#include <QtCore/QEvent>
+#include <QtCore/QAbstractListModel>
+
+#include <QtGui/QFrame>
+#include <QtGui/QAbstractButton>
+#include <QtGui/QPen>
+
+namespace Core {
+
+class IEditor;
+class EditorGroup;
+
+namespace Internal {
+
+class EditorModel;
+
+// Also used by the EditorManager
+class EditorGroupContext : public IContext
+{
+ Q_OBJECT
+
+public:
+ EditorGroupContext(EditorGroup *editorGroup);
+ EditorGroup *editorGroup();
+ // IContext
+ QList<int> context() const;
+ QWidget *widget();
+private:
+ QList<int> m_context;
+ EditorGroup *m_editorGroup;
+};
+
+} // namespace Internal
+
+class CORE_EXPORT EditorGroup : public QFrame
+{
+ Q_OBJECT
+
+public:
+ EditorGroup(QWidget *parent);
+ virtual ~EditorGroup() {};
+
+ virtual IContext *contextObject() { return m_contextObject; }
+ virtual QWidget *widget() { return this; }
+
+ virtual int editorCount() const = 0;
+ virtual void addEditor(IEditor *editor);
+ virtual void insertEditor(int i, IEditor *editor);
+ virtual void removeEditor(IEditor *editor);
+ virtual QList<IEditor*> editors() const = 0;
+
+ virtual IEditor *currentEditor() const = 0;
+ virtual void setCurrentEditor(IEditor *editor) = 0;
+
+ virtual void moveEditorsFromGroup(EditorGroup *group);
+ virtual void moveEditorFromGroup(EditorGroup *group, IEditor *editor);
+
+ virtual QByteArray saveState() const;
+ virtual bool restoreState(const QByteArray &state);
+
+ virtual void showEditorInfoBar(const QString &kind,
+ const QString &infoText,
+ const QString &buttonText,
+ QObject *object, const char *member);
+
+ virtual void hideEditorInfoBar(const QString &kind);
+
+ QSize minimumSizeHint() const;
+ void focusInEvent(QFocusEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+ void paintEvent(QPaintEvent *e);
+
+signals:
+ void closeRequested(Core::IEditor *editor);
+ void editorRemoved(Core::IEditor *editor);
+ void editorAdded(Core::IEditor *editor);
+
+protected:
+ virtual QList<IEditor *> editorsInNaturalOrder() const { return editors(); }
+ Internal::EditorModel *model() const { return m_model; }
+
+private:
+ Internal::EditorGroupContext *m_contextObject;
+ Internal::EditorModel *m_model;
+};
+
+namespace Internal {
+
+// Also used by StackedEditorGroup
+class EditorModel : public QAbstractItemModel
+{
+public:
+ EditorModel(QObject *parent) : QAbstractItemModel(parent) {}
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QModelIndex parent(const QModelIndex &/*index*/) const { return QModelIndex(); }
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
+
+ void addEditor(IEditor *editor) { insertEditor(rowCount(), editor); }
+ void insertEditor(int index, IEditor *editor) {
+ beginInsertRows(QModelIndex(), index, index);
+ m_editors.insert(index, editor);
+ endInsertRows();
+ }
+ void removeEditor(IEditor *editor) {
+ int index = m_editors.indexOf(editor);
+ beginRemoveRows(QModelIndex(), index, index);
+ m_editors.removeAt(index);
+ endRemoveRows();
+ }
+
+ void emitDataChanged(IEditor *editor) {
+ int idx = m_editors.indexOf(editor);
+ QModelIndex mindex = index(idx, 0);
+ emit dataChanged(mindex, mindex);
+ }
+
+ QList<IEditor *> editors() const { return m_editors; }
+ QModelIndex indexOf(IEditor *editor) const;
+private:
+ QList<IEditor *> m_editors;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // EDITORGROUP_H
diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp
new file mode 100644
index 0000000000..7b2e0b2362
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/editormanager.cpp
@@ -0,0 +1,1576 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "editormanager.h"
+#include "editorsplitter.h"
+#include "openeditorswindow.h"
+#include "openwithdialog.h"
+#include "filemanager.h"
+#include "tabpositionindicator.h"
+#include "saveitemsdialog.h"
+#include "vcsmanager.h"
+#include "iversioncontrol.h"
+#include "openeditorsview.h"
+#include "editorgroup.h"
+#include "mimedatabase.h"
+
+#include <coreplugin/coreimpl.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/baseview.h>
+#include <coreplugin/imode.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+#include <QtCore/QProcess>
+#include <QtCore/QDebug>
+
+#include <QtGui/QAction>
+#include <QtGui/QLayout>
+#include <QtGui/QApplication>
+#include <QtGui/QSplitter>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+
+using namespace Core;
+using namespace Core::Internal;
+
+enum { debugEditorManager=0 };
+
+//===================EditorManager=====================
+
+EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0;
+
+EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent)
+ : QWidget(parent), m_mode(mode)
+{
+ setLayout(new QVBoxLayout);
+ layout()->setMargin(0);
+ connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
+ this, SLOT(currentModeChanged(Core::IMode *)));
+}
+
+EditorManagerPlaceHolder::~EditorManagerPlaceHolder()
+{
+ if (m_current == this) {
+ EditorManager::instance()->setParent(0);
+ EditorManager::instance()->hide();
+ }
+}
+
+void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
+{
+ if (m_current == this) {
+ m_current = 0;
+ EditorManager::instance()->setParent(0);
+ EditorManager::instance()->hide();
+ }
+ if (m_mode == mode) {
+ m_current = this;
+ layout()->addWidget(EditorManager::instance());
+ EditorManager::instance()->show();
+ }
+}
+
+EditorManagerPlaceHolder* EditorManagerPlaceHolder::current()
+{
+ return m_current;
+}
+
+// ---------------- EditorManager
+
+struct Core::EditorManagerPrivate {
+ struct EditLocation {
+ QPointer<IEditor> editor;
+ QString fileName;
+ QString kind;
+ QVariant state;
+ };
+ explicit EditorManagerPrivate(ICore *core, QWidget *parent);
+ ~EditorManagerPrivate();
+ Internal::EditorSplitter *m_splitter;
+ ICore *m_core;
+
+ bool m_suppressEditorChanges;
+
+ // actions
+ QAction *m_revertToSavedAction;
+ QAction *m_saveAction;
+ QAction *m_saveAsAction;
+ QAction *m_closeCurrentEditorAction;
+ QAction *m_closeAllEditorsAction;
+ QAction *m_gotoNextDocHistoryAction;
+ QAction *m_gotoPreviousDocHistoryAction;
+ QAction *m_duplicateAction;
+ QAction *m_goBackAction;
+ QAction *m_goForwardAction;
+ QAction *m_openInExternalEditorAction;
+
+ QList<IEditor *> m_editorHistory;
+ QList<EditLocation *> m_navigationHistory;
+ int currentNavigationHistoryPosition;
+ Internal::OpenEditorsWindow *m_windowPopup;
+ Core::BaseView *m_openEditorsView;
+ Internal::EditorClosingCoreListener *m_coreListener;
+
+ typedef QMap<IEditor *, QList<IEditor *> *> DuplicateMap;
+ DuplicateMap m_duplicates;
+
+ QMap<QString, QVariant> m_editorStates;
+ Internal::OpenEditorsViewFactory *m_openEditorsFactory;
+
+ QString fileFilters;
+ QString selectedFilter;
+
+ QString m_externalEditor;
+};
+
+EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) :
+ m_splitter(0),
+ m_core(core),
+ m_suppressEditorChanges(false),
+ m_revertToSavedAction(new QAction(EditorManager::tr("Revert to Saved"), parent)),
+ m_saveAction(new QAction(parent)),
+ m_saveAsAction(new QAction(parent)),
+ m_closeCurrentEditorAction(new QAction(EditorManager::tr("Close"), parent)),
+ m_closeAllEditorsAction(new QAction(EditorManager::tr("Close All"), parent)),
+ m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Document in History"), parent)),
+ m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Document in History"), parent)),
+ m_duplicateAction(new QAction(EditorManager::tr("Duplicate Document"), parent)),
+ m_goBackAction(new QAction(EditorManager::tr("Go back"), parent)),
+ m_goForwardAction(new QAction(EditorManager::tr("Go forward"), parent)),
+ m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)),
+ currentNavigationHistoryPosition(-1),
+ m_windowPopup(0),
+ m_coreListener(0)
+{
+
+}
+
+EditorManagerPrivate::~EditorManagerPrivate()
+{
+ qDeleteAll(m_navigationHistory);
+ m_navigationHistory.clear();
+}
+
+EditorManager *EditorManager::m_instance = 0;
+
+EditorManager::EditorManager(ICore *core, QWidget *parent) :
+ QWidget(parent),
+ m_d(new EditorManagerPrivate(core, parent))
+{
+ m_instance = this;
+
+ connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
+ this, SLOT(updateCurrentEditorAndGroup(Core::IContext *)));
+
+ const QList<int> gc = QList<int>() << Constants::C_GLOBAL_ID;
+ const QList<int> editManagerContext =
+ QList<int>() << m_d->m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_EDITORMANAGER);
+
+ ActionManagerInterface *am = m_d->m_core->actionManager();
+ IActionContainer *mfile = am->actionContainer(Constants::M_FILE);
+
+ //Revert to saved
+ ICommand *cmd = am->registerAction(m_d->m_revertToSavedAction,
+ Constants::REVERTTOSAVED, editManagerContext);
+ cmd->setAttribute(ICommand::CA_UpdateText);
+ cmd->setDefaultText(tr("Revert File to Saved"));
+ mfile->addAction(cmd, Constants::G_FILE_SAVE);
+ connect(m_d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved()));
+
+ //Save Action
+ am->registerAction(m_d->m_saveAction, Constants::SAVE, editManagerContext);
+ connect(m_d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));
+
+ //Save As Action
+ am->registerAction(m_d->m_saveAsAction, Constants::SAVEAS, editManagerContext);
+ connect(m_d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs()));
+
+ //Window Menu
+ IActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
+
+ //Window menu separators
+ QAction *tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Split"), editManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Close"), editManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_CLOSE);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Navigate"), editManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Navigate.Groups"), editManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE_GROUPS);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Bottom"), editManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_LIST);
+
+ //Close Action
+ cmd = am->registerAction(m_d->m_closeCurrentEditorAction, Constants::CLOSE, editManagerContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+W")));
+ cmd->setAttribute(Core::ICommand::CA_UpdateText);
+ cmd->setDefaultText(m_d->m_closeCurrentEditorAction->text());
+ mfile->addAction(cmd, Constants::G_FILE_CLOSE);
+ connect(m_d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor()));
+
+ //Close All Action
+ cmd = am->registerAction(m_d->m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W")));
+ mfile->addAction(cmd, Constants::G_FILE_CLOSE);
+ connect(m_d->m_closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));
+
+ //Duplicate Action
+ cmd = am->registerAction(m_d->m_duplicateAction, Constants::DUPLICATEDOCUMENT, editManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_CLOSE);
+ connect(m_d->m_duplicateAction, SIGNAL(triggered()), this, SLOT(duplicateEditor()));
+
+ // Goto Previous In History Action
+ cmd = am->registerAction(m_d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editManagerContext);
+#ifdef Q_WS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Tab")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab")));
+#endif
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+ connect(m_d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory()));
+
+ // Goto Next In History Action
+ cmd = am->registerAction(m_d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editManagerContext);
+#ifdef Q_WS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab")));
+#endif
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+ connect(m_d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory()));
+
+ // Go back in navigation history
+ cmd = am->registerAction(m_d->m_goBackAction, Constants::GO_BACK, editManagerContext);
+#ifdef Q_WS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Left")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left")));
+#endif
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+ connect(m_d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory()));
+
+ // Go forward in navigation history
+ cmd = am->registerAction(m_d->m_goForwardAction, Constants::GO_FORWARD, editManagerContext);
+#ifdef Q_WS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Right")));
+#else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right")));
+#endif
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+ connect(m_d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory()));
+
+
+ IActionContainer *medit = am->actionContainer(Constants::M_EDIT);
+ IActionContainer *advancedMenu = am->createMenu(Constants::M_EDIT_ADVANCED);
+ medit->addMenu(advancedMenu, Constants::G_EDIT_FORMAT);
+ advancedMenu->menu()->setTitle(tr("&Advanced"));
+ cmd = am->registerAction(m_d->m_openInExternalEditorAction, Constants::OPEN_IN_EXTERNAL_EDITOR, editManagerContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+V,Alt+I")));
+ advancedMenu->addAction(cmd);
+ connect(m_d->m_openInExternalEditorAction, SIGNAL(triggered()), this, SLOT(openInExternalEditor()));
+
+
+ // other setup
+ connect(this, SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(updateActions()));
+ connect(this, SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(updateEditorHistory()));
+ m_d->m_splitter = new EditorSplitter(m_d->m_core);
+ connect(m_d->m_splitter, SIGNAL(closeRequested(Core::IEditor *)),
+ this, SLOT(closeEditor(Core::IEditor *)));
+ connect(m_d->m_splitter, SIGNAL(editorGroupsChanged()),
+ this, SIGNAL(editorGroupsChanged()));
+
+ QHBoxLayout *l = new QHBoxLayout(this);
+ l->setSpacing(0);
+ l->setMargin(0);
+ l->addWidget(m_d->m_splitter);
+
+ updateActions();
+
+ m_d->m_windowPopup = new OpenEditorsWindow(this);
+
+#ifdef Q_OS_MAC
+ m_d->m_externalEditor = m_d->m_core->resourcePath()
+ +QLatin1String("/runInTerminal.command vi %f +%l");
+#elif defined(Q_OS_UNIX)
+ m_d->m_externalEditor = QLatin1String("xterm -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\"");
+#endif
+}
+
+EditorManager::~EditorManager()
+{
+ if (m_d->m_core) {
+ if (m_d->m_coreListener) {
+ m_d->m_core->pluginManager()->removeObject(m_d->m_coreListener);
+ delete m_d->m_coreListener;
+ }
+ m_d->m_core->pluginManager()->removeObject(m_d->m_openEditorsFactory);
+ delete m_d->m_openEditorsFactory;
+ }
+ delete m_d;
+}
+
+void EditorManager::init()
+{
+ QList<int> context;
+ context << m_d->m_core->uniqueIDManager()->uniqueIdentifier("QtCreator.OpenDocumentsView");
+
+ m_d->m_coreListener = new EditorClosingCoreListener(this);
+ m_d->m_core->pluginManager()->addObject(m_d->m_coreListener);
+
+ m_d->m_openEditorsFactory = new OpenEditorsViewFactory();
+ m_d->m_core->pluginManager()->addObject(m_d->m_openEditorsFactory);
+}
+
+QSize EditorManager::minimumSizeHint() const
+{
+ return QSize(400, 300);
+}
+
+EditorSplitter *EditorManager::editorSplitter() const
+{
+ return m_d->m_splitter;
+}
+
+void EditorManager::updateEditorHistory()
+{
+ IEditor *editor = currentEditor();
+ if (!editor)
+ return;
+ m_d->m_editorHistory.removeAll(editor);
+ m_d->m_editorHistory.prepend(editor);
+}
+
+bool EditorManager::registerEditor(IEditor *editor)
+{
+ if (editor) {
+ if (!hasDuplicate(editor)) {
+ m_d->m_core->fileManager()->addFile(editor->file());
+ m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName());
+ }
+ m_d->m_editorHistory.removeAll(editor);
+ m_d->m_editorHistory.prepend(editor);
+ return true;
+ }
+ return false;
+}
+
+bool EditorManager::unregisterEditor(IEditor *editor)
+{
+ if (editor) {
+ if (!hasDuplicate(editor))
+ m_d->m_core->fileManager()->removeFile(editor->file());
+ m_d->m_editorHistory.removeAll(editor);
+ return true;
+ }
+ return false;
+}
+
+void EditorManager::updateCurrentEditorAndGroup(IContext *context)
+{
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO;
+ EditorGroupContext *groupContext = context ? qobject_cast<EditorGroupContext*>(context) : 0;
+ IEditor *editor = context ? qobject_cast<IEditor*>(context) : 0;
+ if (groupContext) {
+ m_d->m_splitter->setCurrentGroup(groupContext->editorGroup());
+ setCurrentEditor(0);
+ updateActions();
+ } else if (editor) {
+ setCurrentEditor(editor);
+ } else {
+ updateActions();
+ }
+ if (debugEditorManager)
+ qDebug() << "leaving method" << Q_FUNC_INFO;
+}
+
+void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory)
+{
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO << currentEditor() << "-->" << editor
+ << (m_d->m_suppressEditorChanges?"suppressed":"")
+ << "ignore history?" << ignoreNavigationHistory;
+ if (m_d->m_suppressEditorChanges)
+ return;
+ if (editor) {
+ bool addToHistory = (!ignoreNavigationHistory && editor != currentEditor());
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO << (addToHistory ? "adding to history" : "not adding to history");
+ if (addToHistory)
+ addCurrentPositionToNavigationHistory(true);
+ EditorGroup *group = groupOfEditor(editor);
+ if (!group)
+ return;
+ m_d->m_suppressEditorChanges = true;
+ m_d->m_splitter->setCurrentGroup(group);
+ group->setCurrentEditor(editor);
+ m_d->m_suppressEditorChanges = false;
+ if (addToHistory)
+ addCurrentPositionToNavigationHistory();
+ }
+ editorChanged(editor);
+}
+
+void EditorManager::editorChanged(IEditor *toEditor)
+{
+ emit currentEditorChanged(toEditor);
+}
+
+EditorGroup *EditorManager::groupOfEditor(IEditor *editor) const
+{
+ foreach (EditorGroup *group, m_d->m_splitter->groups()) {
+ if (group->editors().contains(editor))
+ return group;
+ }
+ return 0;
+}
+
+QList<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
+{
+ QList<IEditor *> found;
+ QString fixedname = FileManager::fixFileName(filename);
+ foreach (IEditor *editor, openedEditors()) {
+ if (fixedname == FileManager::fixFileName(editor->file()->fileName()))
+ found << editor;
+ }
+ return found;
+}
+
+IEditor *EditorManager::currentEditor() const
+{
+ return m_d->m_splitter->currentGroup()->currentEditor();
+}
+
+EditorGroup *EditorManager::currentEditorGroup() const
+{
+ return m_d->m_splitter->currentGroup();
+}
+
+void EditorManager::duplicateEditor()
+{
+ IEditor *curEditor = currentEditor();
+ if (!curEditor || !curEditor->duplicateSupported())
+ return;
+ IEditor *editor = curEditor->duplicate(this);
+ registerDuplicate(curEditor, editor);
+ insertEditor(editor);
+}
+
+// SLOT connected to action
+// since this is potentially called in the event handler of the editor
+// we simply postpone it with a single shot timer
+void EditorManager::closeEditor()
+{
+ static bool postpone = true;
+ if (postpone) {
+ QTimer::singleShot(0, this, SLOT(closeEditor()));
+ postpone = false;
+ } else {
+ closeEditor(currentEditor());
+ postpone = true;
+ }
+
+}
+
+void EditorManager::closeEditor(IEditor *editor)
+{
+ if (!editor)
+ editor = currentEditor();
+ if (!editor)
+ return;
+ closeEditors(QList<IEditor *>() << editor);
+}
+
+QList<IEditor*>
+ EditorManager::editorsForFiles(QList<IFile*> files) const
+{
+ const QList<IEditor *> editors = openedEditors();
+ QSet<IEditor *> found;
+ foreach (IFile *file, files) {
+ foreach (IEditor *editor, editors) {
+ if (editor->file() == file && !found.contains(editor)) {
+ if (hasDuplicate(editor)) {
+ foreach (IEditor *duplicate, duplicates(editor)) {
+ found << duplicate;
+ }
+ } else {
+ found << editor;
+ }
+ }
+ }
+ }
+ return found.toList();
+}
+
+QList<IFile *>
+ EditorManager::filesForEditors(QList<IEditor *> editors) const
+{
+ QSet<IEditor *> handledEditors;
+ QList<IFile *> files;
+ foreach (IEditor *editor, editors) {
+ if (!handledEditors.contains(editor)) {
+ files << editor->file();
+ if (hasDuplicate(editor)) {
+ foreach (IEditor *duplicate, duplicates(editor)) {
+ handledEditors << duplicate;
+ }
+ } else {
+ handledEditors.insert(editor);
+ }
+ }
+ }
+ return files;
+}
+
+bool EditorManager::closeAllEditors(bool askAboutModifiedEditors)
+{
+ return closeEditors(openedEditors(), askAboutModifiedEditors);
+}
+
+bool EditorManager::closeEditors(const QList<IEditor*> editorsToClose, bool askAboutModifiedEditors)
+{
+ if (editorsToClose.isEmpty())
+ return true;
+ bool closingFailed = false;
+ QList<IEditor*> acceptedEditors;
+ //ask all core listeners to check whether the editor can be closed
+ const QList<ICoreListener *> listeners =
+ m_d->m_core->pluginManager()->getObjects<ICoreListener>();
+ foreach (IEditor *editor, editorsToClose) {
+ bool editorAccepted = true;
+ foreach (ICoreListener *listener, listeners) {
+ if (!listener->editorAboutToClose(editor)) {
+ editorAccepted = false;
+ closingFailed = false;
+ break;
+ }
+ }
+ if (editorAccepted)
+ acceptedEditors.append(editor);
+ }
+ if (acceptedEditors.isEmpty())
+ return false;
+ //ask whether to save modified files
+ if (askAboutModifiedEditors) {
+ bool cancelled = false;
+ QList<IFile*> list = CoreImpl::instance()->fileManager()->
+ saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled);
+ if (cancelled)
+ return false;
+ if (!list.isEmpty()) {
+ QSet<IEditor*> skipSet = editorsForFiles(list).toSet();
+ acceptedEditors = acceptedEditors.toSet().subtract(skipSet).toList();
+ closingFailed = false;
+ }
+ }
+ if (acceptedEditors.isEmpty())
+ return false;
+ bool currentEditorRemoved = false;
+ IEditor *current = currentEditor();
+ if (current)
+ addCurrentPositionToNavigationHistory(true);
+ // remove current editor last, for optimization
+ if (acceptedEditors.contains(current)) {
+ currentEditorRemoved = true;
+ acceptedEditors.removeAll(current);
+ acceptedEditors.append(current);
+ }
+ // remove the editors
+ foreach (IEditor *editor, acceptedEditors) {
+ emit editorAboutToClose(editor);
+ if (!editor->file()->fileName().isEmpty()) {
+ QByteArray state = editor->saveState();
+ if (!state.isEmpty())
+ m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state));
+ }
+ unregisterEditor(editor);
+ if (hasDuplicate(editor))
+ unregisterDuplicate(editor);
+ m_d->m_core->removeContextObject(editor);
+ EditorGroup *group = groupOfEditor(editor);
+ const bool suppress = m_d->m_suppressEditorChanges;
+ m_d->m_suppressEditorChanges = true;
+ if (group)
+ group->removeEditor(editor);
+ m_d->m_suppressEditorChanges = suppress;
+ }
+ emit editorsClosed(acceptedEditors);
+ foreach (IEditor *editor, acceptedEditors) {
+ delete editor;
+ }
+ if (currentEditorRemoved) {
+ if (m_d->m_editorHistory.count() > 0) {
+ setCurrentEditor(m_d->m_editorHistory.first(), true);
+ } else {
+ editorChanged(currentEditor());
+ }
+ }
+ if (currentEditor())
+ addCurrentPositionToNavigationHistory();
+ updateActions();
+
+ return !closingFailed;
+}
+
+
+/* Find editors for a mimetype, best matching at the front
+ * of the list. Recurse over the parent classes of the mimetype to
+ * find them. */
+static void mimeTypeFactoryRecursion(const MimeDatabase *db,
+ const MimeType &mimeType,
+ const QList<IEditorFactory*> &allFactories,
+ bool firstMatchOnly,
+ QList<IEditorFactory*> *list)
+{
+ typedef QList<IEditorFactory*> EditorFactoryList;
+ // Loop factories to find type
+ const QString type = mimeType.type();
+ const EditorFactoryList::const_iterator fcend = allFactories.constEnd();
+ for (EditorFactoryList::const_iterator fit = allFactories.constBegin(); fit != fcend; ++fit) {
+ // Exclude duplicates when recursing over xml or C++ -> C -> text.
+ IEditorFactory *factory = *fit;
+ if (!list->contains(factory) && factory->mimeTypes().contains(type)) {
+ list->push_back(*fit);
+ if (firstMatchOnly)
+ return;
+ break;
+ }
+ }
+ // Any parent classes? -> recurse
+ QStringList parentTypes = mimeType.subClassesOf();
+ if (parentTypes.empty())
+ return;
+ const QStringList::const_iterator pcend = parentTypes .constEnd();
+ for (QStringList::const_iterator pit = parentTypes .constBegin(); pit != pcend; ++pit) {
+ if (const MimeType parent = db->findByType(*pit))
+ mimeTypeFactoryRecursion(db, parent, allFactories, firstMatchOnly, list);
+ }
+}
+
+EditorManager::EditorFactoryList
+ EditorManager::editorFactories(const MimeType &mimeType, bool bestMatchOnly) const
+{
+ EditorFactoryList rc;
+ const EditorFactoryList allFactories = m_d->m_core->pluginManager()->getObjects<IEditorFactory>();
+ mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allFactories, bestMatchOnly, &rc);
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc;
+ return rc;
+}
+
+IEditor *EditorManager::createEditor(const QString &editorKind,
+ const QString &fileName)
+{
+ typedef QList<IEditorFactory*> FactoryList;
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO << editorKind << fileName;
+
+
+ EditorFactoryList factories;
+ if (editorKind.isEmpty()) {
+ // Find by mime type
+ const MimeType mimeType = m_d->m_core->mimeDatabase()->findByFile(QFileInfo(fileName));
+ if (!mimeType) {
+ qWarning("%s unable to determine mime type of %s/%s.",
+ Q_FUNC_INFO, fileName.toUtf8().constData(), editorKind.toUtf8().constData());
+ return 0;
+ }
+ factories = editorFactories(mimeType, true);
+ } else {
+ // Find by editor kind
+ const EditorFactoryList allFactories = m_d->m_core->pluginManager()->getObjects<IEditorFactory>();
+ const EditorFactoryList::const_iterator acend = allFactories.constEnd();
+ for (EditorFactoryList::const_iterator ait = allFactories.constBegin(); ait != acend; ++ait) {
+ if (editorKind == (*ait)->kind()) {
+ factories.push_back(*ait);
+ break;
+ }
+ }
+ }
+ if (factories.empty()) {
+ qWarning("%s: unable to find an editor factory for the file '%s', editor kind '%s'.",
+ Q_FUNC_INFO, fileName.toUtf8().constData(), editorKind.toUtf8().constData());
+ return 0;
+ }
+
+ IEditor *editor = factories.front()->createEditor(this);
+ if (editor)
+ connect(editor, SIGNAL(changed()), this, SLOT(updateActions()));
+ if (editor)
+ emit editorCreated(editor, fileName);
+ return editor;
+}
+
+void EditorManager::insertEditor(IEditor *editor,
+ bool ignoreNavigationHistory,
+ EditorGroup *group)
+{
+ if (!editor)
+ return;
+ m_d->m_core->addContextObject(editor);
+ registerEditor(editor);
+ if (group)
+ group->addEditor(editor);
+ else
+ m_d->m_splitter->currentGroup()->addEditor(editor);
+
+ setCurrentEditor(editor, ignoreNavigationHistory);
+ emit editorOpened(editor);
+}
+
+// Run the OpenWithDialog and return the editor kind
+// selected by the user.
+QString EditorManager::getOpenWithEditorKind(const QString &fileName) const
+{
+ QStringList editorKinds;
+ // Collect editors that can open the file
+ if (const MimeType mt = m_d->m_core->mimeDatabase()->findByFile(fileName)) {
+ const EditorFactoryList editors = editorFactories(mt, false);
+ const int size = editors.size();
+ for (int i = 0; i < size; i++) {
+ editorKinds.push_back(editors.at(i)->kind());
+ }
+ }
+ if (editorKinds.empty())
+ return QString();
+
+ // Run dialog.
+ OpenWithDialog dialog(fileName, m_d->m_core->mainWindow());
+ dialog.setEditors(editorKinds);
+ dialog.setCurrentEditor(0);
+ if (dialog.exec() != QDialog::Accepted)
+ return QString();
+ return dialog.editor();
+}
+
+static QString formatFileFilters(const Core::ICore *core, QString *selectedFilter)
+{
+ QString rc;
+ // Compile list of filter strings. If we find a glob matching all files,
+ // put it last and set it as default selectedFilter.
+ QStringList filters = core->mimeDatabase()->filterStrings();
+ filters.sort();
+ selectedFilter->clear();
+ if (filters.empty())
+ return rc;
+ const QString filterSeparator = QLatin1String(";;");
+ bool hasAllFilter = false;
+ const int size = filters.size();
+ for (int i = 0; i < size; i++) {
+ const QString &filterString = filters.at(i);
+ if (filterString.isEmpty()) { // binary editor
+ hasAllFilter = true;
+ } else {
+ if (!rc.isEmpty())
+ rc += filterSeparator;
+ rc += filterString;
+ }
+ }
+ if (hasAllFilter) {
+ // prepend all files filter
+ // prepending instead of appending to work around a but in Qt/Mac
+ QString allFilesFilter = QLatin1String("All Files (*)");
+ if (!rc.isEmpty())
+ allFilesFilter += filterSeparator;
+ rc.prepend(allFilesFilter);
+ *selectedFilter = allFilesFilter;
+ } else {
+ *selectedFilter = filters.front();
+ }
+ return rc;
+}
+
+IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorKind,
+ bool ignoreNavigationHistory)
+{
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO << fileName << editorKind;
+
+ if (fileName.isEmpty())
+ return 0;
+
+ const QList<IEditor *> editors = editorsForFileName(fileName);
+ if (!editors.isEmpty()) {
+ setCurrentEditor(editors.first(), ignoreNavigationHistory);
+ return editors.first();
+ }
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ IEditor *editor = createEditor(editorKind, fileName);
+ if (!editor || !editor->open(fileName)) {
+ QApplication::restoreOverrideCursor();
+ QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), tr("Cannot open file %1!").arg(fileName));
+ delete editor;
+ editor = 0;
+ return 0;
+ }
+ insertEditor(editor, ignoreNavigationHistory);
+ restoreEditorState(editor);
+ QApplication::restoreOverrideCursor();
+ ensureEditorManagerVisible();
+ return editor;
+}
+
+QStringList EditorManager::getOpenFileNames() const
+{
+ QString dir;
+ if (m_d->fileFilters.isEmpty())
+ m_d->fileFilters = formatFileFilters(m_d->m_core, &m_d->selectedFilter);
+
+ if (IEditor *curEditor = currentEditor()) {
+ const QFileInfo fi(curEditor->file()->fileName());
+ dir = fi.absolutePath();
+ }
+
+ return QFileDialog::getOpenFileNames(m_d->m_core->mainWindow(), tr("Open File"),
+ dir, m_d->fileFilters, &m_d->selectedFilter);
+}
+
+void EditorManager::ensureEditorManagerVisible()
+{
+ if (!isVisible()) {
+ m_d->m_core->modeManager()->activateMode(Constants::MODE_EDIT);
+ }
+}
+
+IEditor *EditorManager::newFile(const QString &editorKind,
+ QString *titlePattern,
+ const QString &contents)
+{
+ if (debugEditorManager)
+ qDebug() << Q_FUNC_INFO << editorKind << titlePattern << contents;
+
+ if (editorKind.isEmpty())
+ return 0;
+
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ IEditor *edt = createEditor(editorKind);
+ if (!edt)
+ return 0;
+
+ if (!edt || !edt->createNew(contents)) {
+ QApplication::restoreOverrideCursor();
+ delete edt;
+ edt = 0;
+ return 0;
+ }
+
+ QString title = edt->displayName();
+
+ if (title.isEmpty() && titlePattern) {
+ const QChar dollar = QLatin1Char('$');
+ const QChar dot = QLatin1Char('.');
+
+ QString base = *titlePattern;
+ if (base.isEmpty())
+ base = QLatin1String("unnamed$");
+ if (base.contains(dollar)) {
+ int i = 1;
+ QSet<QString> docnames;
+ foreach (IEditor *editor, openedEditors()) {
+ QString name = editor->file()->fileName();
+ if (name.isEmpty()) {
+ name = editor->displayName();
+ name.remove(QLatin1Char('*'));
+ } else {
+ name = QFileInfo(name).completeBaseName();
+ }
+ docnames << name;
+ }
+
+ do {
+ title = base;
+ title.replace(QString(dollar), QString::number(i++));
+ } while (docnames.contains(title));
+ } else {
+ title = *titlePattern;
+ }
+ }
+ *titlePattern = title;
+ edt->setDisplayName(title);
+ insertEditor(edt);
+ QApplication::restoreOverrideCursor();
+ return edt;
+}
+
+bool EditorManager::hasEditor(const QString &fileName) const
+{
+ return !editorsForFileName(fileName).isEmpty();
+}
+
+void EditorManager::restoreEditorState(IEditor *editor)
+{
+ Q_ASSERT(editor);
+ QString fileName = editor->file()->fileName();
+ if (m_d->m_editorStates.contains(fileName)) {
+ editor->restoreState(m_d->m_editorStates.value(fileName).toByteArray());
+ }
+}
+
+bool EditorManager::saveEditor(IEditor *editor)
+{
+ return saveFile(editor);
+}
+
+bool EditorManager::saveFile(IEditor *editor)
+{
+ if (!editor)
+ editor = currentEditor();
+ if (!editor)
+ return false;
+
+ IFile *file = editor->file();
+ const QString &fileName = file->fileName();
+ if (!fileName.isEmpty() && file->isReadOnly()) {
+ MakeWritableResult answer =
+ makeEditorWritable(editor);
+ if (answer == Failed)
+ return false;
+ if (answer == SavedAs)
+ return true;
+ }
+
+ if (file->isReadOnly() || fileName.isEmpty()) {
+ return saveFileAs(editor);
+ }
+
+ m_d->m_core->fileManager()->blockFileChange(file);
+ const bool success = file->save(fileName);
+ m_d->m_core->fileManager()->unblockFileChange(file);
+ if (success)
+ m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName());
+ return success;
+}
+
+namespace {
+ enum ReadOnlyAction { RO_Cancel, RO_OpenSCC, RO_MakeWriteable, RO_SaveAs };
+}
+
+static ReadOnlyAction promptReadOnly(const QString &fileName, bool hasSCC, QWidget *parent)
+{
+ QMessageBox msgBox(QMessageBox::Question, QObject::tr("File is Read Only"),
+ QObject::tr("The file %1 is read only.").arg(fileName),
+ QMessageBox::Cancel, parent);
+
+ QPushButton *sccButton = 0;
+ if (hasSCC)
+ sccButton = msgBox.addButton(QObject::tr("Open with SCC"), QMessageBox::AcceptRole);
+ QPushButton *makeWritableButton = msgBox.addButton(QObject::tr("Make writable"), QMessageBox::AcceptRole);
+ QPushButton *saveAsButton = msgBox.addButton(QObject::tr("Save as ..."), QMessageBox::ActionRole);
+ if (hasSCC)
+ msgBox.setDefaultButton(sccButton);
+ else
+ msgBox.setDefaultButton(makeWritableButton);
+ msgBox.exec();
+ QAbstractButton *clickedButton = msgBox.clickedButton();
+ if (clickedButton == sccButton)
+ return RO_OpenSCC;
+ if (clickedButton == makeWritableButton)
+ return RO_MakeWriteable;
+ if (clickedButton == saveAsButton)
+ return RO_SaveAs;
+ return RO_Cancel;
+}
+
+
+MakeWritableResult
+EditorManager::makeEditorWritable(IEditor *editor)
+{
+ QString directory = QFileInfo(editor->file()->fileName()).absolutePath();
+ IVersionControl *versionControl = m_d->m_core->vcsManager()->findVersionControlForDirectory(directory);
+ IFile *file = editor->file();
+ const QString &fileName = file->fileName();
+
+ switch (promptReadOnly(fileName, versionControl, m_d->m_core->mainWindow())) {
+ case RO_OpenSCC:
+ if (!versionControl->vcsOpen(fileName)) {
+ QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for edit with SCC."));
+ return Failed;
+ }
+ return OpenedWithVersionControl;
+ case RO_MakeWriteable: {
+ const bool permsOk = QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser);
+ if (!permsOk) {
+ QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable."));
+ return Failed;
+ }
+ }
+ return MadeWritable;
+ case RO_SaveAs :
+ return saveFileAs(editor) ? SavedAs : Failed;
+ case RO_Cancel:
+ break;
+ }
+ return Failed;
+}
+
+bool EditorManager::saveFileAs(IEditor *editor)
+{
+ if (!editor)
+ editor = currentEditor();
+ if (!editor)
+ return false;
+
+ QString absoluteFilePath = m_d->m_core->fileManager()->getSaveAsFileName(editor->file());
+ if (absoluteFilePath.isEmpty())
+ return false;
+ if (absoluteFilePath != editor->file()->fileName()) {
+ const QList<IEditor *> existList = editorsForFileName(absoluteFilePath);
+ if (!existList.isEmpty()) {
+ closeEditors(existList, false);
+ }
+ }
+
+ m_d->m_core->fileManager()->blockFileChange(editor->file());
+ const bool success = editor->file()->save(absoluteFilePath);
+ m_d->m_core->fileManager()->unblockFileChange(editor->file());
+
+ if(success)
+ m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName());
+
+ updateActions();
+ return success;
+}
+
+void EditorManager::gotoNextDocHistory()
+{
+ OpenEditorsWindow *dialog = windowPopup();
+ dialog->setMode(OpenEditorsWindow::HistoryMode);
+ dialog->selectNextEditor();
+ showWindowPopup();
+}
+
+void EditorManager::gotoPreviousDocHistory()
+{
+ OpenEditorsWindow *dialog = windowPopup();
+ dialog->setMode(OpenEditorsWindow::HistoryMode);
+ dialog->selectPreviousEditor();
+ showWindowPopup();
+}
+
+void EditorManager::makeCurrentEditorWritable()
+{
+ if (IEditor* curEditor = currentEditor())
+ makeEditorWritable(curEditor);
+}
+
+void EditorManager::updateActions()
+{
+ QString fName;
+ IEditor *curEditor = currentEditor();
+ int openedCount = openedEditors().count();
+ if (curEditor) {
+ if (!curEditor->file()->fileName().isEmpty()) {
+ QFileInfo fi(curEditor->file()->fileName());
+ fName = fi.fileName();
+ } else {
+ fName = curEditor->displayName();
+ }
+
+
+ if (curEditor->file()->isModified() && curEditor->file()->isReadOnly()) {
+ // we are about to change a read-only file, warn user
+ showEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"),
+ tr("<b>Warning:</b> You are changing a read-only file."),
+ tr("Make writable"), this, SLOT(makeCurrentEditorWritable()));
+ } else {
+ hideEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"));
+ }
+ }
+
+ m_d->m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified());
+ m_d->m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed());
+ m_d->m_revertToSavedAction->setEnabled(curEditor != 0
+ && !curEditor->file()->fileName().isEmpty() && curEditor->file()->isModified());
+
+ m_d->m_saveAsAction->setText(tr("Save %1 As...").arg(fName));
+ m_d->m_saveAction->setText(tr("&Save %1").arg(fName));
+ m_d->m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(fName));
+
+
+ m_d->m_closeCurrentEditorAction->setEnabled(m_d->m_splitter->currentGroup()->editorCount() > 0);
+ m_d->m_closeCurrentEditorAction->setText(tr("Close %1").arg(fName));
+ m_d->m_closeAllEditorsAction->setEnabled(openedCount > 0);
+
+ m_d->m_gotoNextDocHistoryAction->setEnabled(m_d->m_editorHistory.count() > 0);
+ m_d->m_gotoPreviousDocHistoryAction->setEnabled(m_d->m_editorHistory.count() > 0);
+ m_d->m_goBackAction->setEnabled(m_d->currentNavigationHistoryPosition > 0);
+ m_d->m_goForwardAction->setEnabled(m_d->currentNavigationHistoryPosition < m_d->m_navigationHistory.size()-1);
+
+ m_d->m_duplicateAction->setEnabled(curEditor != 0 && curEditor->duplicateSupported());
+
+ m_d->m_openInExternalEditorAction->setEnabled(curEditor != 0);
+}
+
+QList<IEditor*> EditorManager::openedEditors() const
+{
+ QList<IEditor*> editors;
+ const QList<EditorGroup*> groups = m_d->m_splitter->groups();
+ foreach (EditorGroup *group, groups) {
+ editors += group->editors();
+ }
+ return editors;
+}
+
+QList<EditorGroup *> EditorManager::editorGroups() const
+{
+ return m_d->m_splitter->groups();
+}
+
+QList<IEditor*> EditorManager::editorHistory() const
+{
+ return m_d->m_editorHistory;
+}
+
+void EditorManager::addCurrentPositionToNavigationHistory(bool compress)
+{
+ IEditor *editor = currentEditor();
+ if (!editor)
+ return;
+ if (!editor->file())
+ return;
+ QString fileName = editor->file()->fileName();
+ QByteArray state = editor->saveState();
+ // cut existing
+ int firstIndexToRemove;
+ if (compress && m_d->currentNavigationHistoryPosition >= 0) {
+ EditorManagerPrivate::EditLocation *previousLocation =
+ m_d->m_navigationHistory.at(m_d->currentNavigationHistoryPosition);
+ if ((previousLocation->editor && editor == previousLocation->editor)
+ || (!fileName.isEmpty() && previousLocation->fileName == fileName)) {
+ firstIndexToRemove = m_d->currentNavigationHistoryPosition;
+ }
+ } else {
+ firstIndexToRemove = m_d->currentNavigationHistoryPosition+1;
+ }
+ if (firstIndexToRemove >= 0) {
+ for (int i = m_d->m_navigationHistory.size()-1; i >= firstIndexToRemove; --i) {
+ delete m_d->m_navigationHistory.takeLast();
+ }
+ }
+ while (m_d->m_navigationHistory.size() >= 30) {
+ delete m_d->m_navigationHistory.takeFirst();
+ }
+ EditorManagerPrivate::EditLocation *location = new EditorManagerPrivate::EditLocation;
+ location->editor = editor;
+ location->fileName = editor->file()->fileName();
+ location->kind = editor->kind();
+ location->state = QVariant(state);
+ m_d->m_navigationHistory.append(location);
+ m_d->currentNavigationHistoryPosition = m_d->m_navigationHistory.size()-1;
+ updateActions();
+}
+
+void EditorManager::goBackInNavigationHistory()
+{
+ while (m_d->currentNavigationHistoryPosition > 0) {
+ --m_d->currentNavigationHistoryPosition;
+ EditorManagerPrivate::EditLocation *location = m_d->m_navigationHistory.at(m_d->currentNavigationHistoryPosition);
+ IEditor *editor;
+ if (location->editor) {
+ editor = location->editor;
+ setCurrentEditor(location->editor, true);
+ } else {
+ editor = openEditor(location->fileName, location->kind, true);
+ if (!editor) {
+ delete m_d->m_navigationHistory.takeAt(m_d->currentNavigationHistoryPosition);
+ continue;
+ }
+ }
+ editor->restoreState(location->state.toByteArray());
+ updateActions();
+ ensureEditorManagerVisible();
+ return;
+ }
+}
+
+void EditorManager::goForwardInNavigationHistory()
+{
+ if (m_d->currentNavigationHistoryPosition >= m_d->m_navigationHistory.size()-1)
+ return;
+ ++m_d->currentNavigationHistoryPosition;
+ EditorManagerPrivate::EditLocation *location = m_d->m_navigationHistory.at(m_d->currentNavigationHistoryPosition);
+ IEditor *editor;
+ if (location->editor) {
+ editor = location->editor;
+ setCurrentEditor(location->editor, true);
+ } else {
+ editor = openEditor(location->fileName, location->kind, true);
+ if (!editor) {
+ //TODO
+ qDebug() << Q_FUNC_INFO << "can't open file" << location->fileName;
+ return;
+ }
+ }
+ editor->restoreState(location->state.toByteArray());
+ updateActions();
+ ensureEditorManagerVisible();
+}
+
+OpenEditorsWindow *EditorManager::windowPopup() const
+{
+ return m_d->m_windowPopup;
+}
+
+void EditorManager::showWindowPopup() const
+{
+ const QPoint p(mapToGlobal(QPoint(0, 0)));
+ m_d->m_windowPopup->move((width()-m_d->m_windowPopup->width())/2 + p.x(),
+ (height()-m_d->m_windowPopup->height())/2 + p.y());
+ m_d->m_windowPopup->setVisible(true);
+}
+
+void EditorManager::registerDuplicate(IEditor *original,
+ IEditor *duplicate)
+{
+ QList<IEditor *> *duplicateList;
+ if (m_d->m_duplicates.contains(original)) {
+ duplicateList = m_d->m_duplicates.value(original);
+ } else {
+ duplicateList = new QList<IEditor *>;
+ duplicateList->append(original);
+ m_d->m_duplicates.insert(original, duplicateList);
+ }
+ duplicateList->append(duplicate);
+ m_d->m_duplicates.insert(duplicate, duplicateList);
+}
+
+void EditorManager::unregisterDuplicate(IEditor *editor)
+{
+ if (!m_d->m_duplicates.contains(editor))
+ return;
+ QList<IEditor *> *duplicateList = m_d->m_duplicates.value(editor);
+ duplicateList->removeAll(editor);
+ m_d->m_duplicates.remove(editor);
+ if (duplicateList->count() < 2) {
+ foreach (IEditor *other, *duplicateList) {
+ m_d->m_duplicates.remove(other);
+ }
+ delete duplicateList;
+ }
+}
+
+bool EditorManager::hasDuplicate(IEditor *editor) const
+{
+ return m_d->m_duplicates.contains(editor);
+}
+
+QList<IEditor *>
+ EditorManager::duplicates(IEditor *editor) const
+{
+ if (m_d->m_duplicates.contains(editor))
+ return *m_d->m_duplicates.value(editor);
+ return QList<IEditor *>() << editor;
+}
+
+QByteArray EditorManager::saveState() const
+{
+ //todo: versioning
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::WriteOnly);
+ stream << m_d->m_splitter->saveState();
+ stream << saveOpenEditorList();
+ stream << m_d->m_editorStates;
+ return bytes;
+}
+
+bool EditorManager::restoreState(const QByteArray &state)
+{
+ closeAllEditors(true);
+ //todo: versioning
+ QDataStream stream(state);
+ QByteArray data;
+ QMap<QString, QVariant> editorstates;
+ stream >> data;
+ const bool success = m_d->m_splitter->restoreState(data);
+ if (!success)
+ return false;
+
+ bool editorChangesSuppressed = m_d->m_suppressEditorChanges;
+ m_d->m_suppressEditorChanges = true;
+
+ stream >> data;
+ restoreOpenEditorList(data);
+ stream >> editorstates;
+ QMapIterator<QString, QVariant> i(editorstates);
+ while (i.hasNext()) {
+ i.next();
+ m_d->m_editorStates.insert(i.key(), i.value());
+ }
+
+ m_d->m_suppressEditorChanges = editorChangesSuppressed;
+ if (currentEditor())
+ setCurrentEditor(currentEditor());// looks like a null-op but is not
+
+ return true;
+}
+
+void EditorManager::saveSettings(QSettings *settings)
+{
+ m_d->m_splitter->saveSettings(settings);
+ settings->setValue(QLatin1String("EditorManager/DocumentStates"),
+ m_d->m_editorStates);
+ settings->setValue(QLatin1String("EditorManager/ExternalEditor"),
+ m_d->m_externalEditor);
+}
+
+void EditorManager::readSettings(QSettings *settings)
+{
+ m_d->m_splitter->readSettings(settings);
+ if (settings->contains(QLatin1String("EditorManager/DocumentStates")))
+ m_d->m_editorStates = settings->value(QLatin1String("EditorManager/DocumentStates"))
+ .value<QMap<QString, QVariant> >();
+ if (settings->contains(QLatin1String("EditorManager/ExternalEditor")))
+ m_d->m_externalEditor = settings->value(QLatin1String("EditorManager/ExternalEditor")).toString();
+}
+
+QByteArray EditorManager::saveOpenEditorList() const
+{
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::WriteOnly);
+ QMap<QString, QByteArray> outlist;
+ QMapIterator<QString, EditorGroup *> i(m_d->m_splitter->pathGroupMap());
+ while (i.hasNext()) {
+ i.next();
+ outlist.insert(i.key(), i.value()->saveState());
+ }
+ stream << outlist;
+ return bytes;
+}
+
+void EditorManager::restoreOpenEditorList(const QByteArray &state)
+{
+ QDataStream in(state);
+ QMap<QString, EditorGroup *> pathGroupMap = m_d->m_splitter->pathGroupMap();
+ QMap<QString, QByteArray> inlist;
+ in >> inlist;
+ QMapIterator<QString, QByteArray> i(inlist);
+ while (i.hasNext()) {
+ i.next();
+ EditorGroup *group = pathGroupMap.value(i.key());
+ if (!group)
+ continue;
+ group->restoreState(i.value());
+ }
+}
+
+IEditor *EditorManager::restoreEditor(QString fileName, QString editorKind, EditorGroup *group)
+{
+ IEditor *editor;
+ QList<IEditor *> existing =
+ editorsForFileName(fileName);
+ if (!existing.isEmpty()) {
+ IEditor *first = existing.first();
+ if (!first->duplicateSupported())
+ return 0;
+ editor = first->duplicate(this);
+ registerDuplicate(first, editor);
+ } else {
+ editor = createEditor(editorKind, fileName);
+ if (!editor || !editor->open(fileName))
+ return 0;
+ }
+ insertEditor(editor, false, group);
+ restoreEditorState(editor);
+ return editor;
+}
+
+void EditorManager::revertToSaved()
+{
+ IEditor *currEditor = currentEditor();
+ if (!currEditor)
+ return;
+ const QString fileName = currEditor->file()->fileName();
+ if (fileName.isEmpty())
+ return;
+ if (currEditor->file()->isModified()) {
+ QMessageBox msgBox(QMessageBox::Question, tr("Revert to Saved"),
+ tr("You will lose your current changes if you proceed reverting %1.").arg(fileName),
+ QMessageBox::Yes|QMessageBox::No, m_d->m_core->mainWindow());
+ msgBox.button(QMessageBox::Yes)->setText(tr("Proceed"));
+ msgBox.button(QMessageBox::No)->setText(tr("Cancel"));
+ msgBox.setDefaultButton(QMessageBox::No);
+ msgBox.setEscapeButton(QMessageBox::No);
+ if (msgBox.exec() == QMessageBox::No)
+ return;
+
+ }
+ IFile::ReloadBehavior temp = IFile::ReloadAll;
+ currEditor->file()->modified(&temp);
+}
+
+
+void EditorManager::showEditorInfoBar(const QString &kind,
+ const QString &infoText,
+ const QString &buttonText,
+ QObject *object, const char *member)
+{
+ m_d->m_splitter->currentGroup()->showEditorInfoBar(kind, infoText, buttonText, object, member);
+}
+
+
+void EditorManager::hideEditorInfoBar(const QString &kind)
+{
+ m_d->m_splitter->currentGroup()->hideEditorInfoBar(kind);
+}
+
+QString EditorManager::externalEditorHelpText() const
+{
+ QString help = tr(
+ "<table border=1 cellspacing=0 cellpadding=3>"
+ "<tr><th>Variable</th><th>Expands to</th></tr>"
+ "<tr><td>%f</td><td>file name</td></tr>"
+ "<tr><td>%l</td><td>current line number</td></tr>"
+ "<tr><td>%c</td><td>current column number</td></tr>"
+ "<tr><td>%x</td><td>editor's x position on screen</td></tr>"
+ "<tr><td>%y</td><td>editor's y position on screen</td></tr>"
+ "<tr><td>%w</td><td>editor's width in pixels</td></tr>"
+ "<tr><td>%h</td><td>editor's height in pixels</td></tr>"
+ "<tr><td>%W</td><td>editor's width in characters</td></tr>"
+ "<tr><td>%H</td><td>editor's height in characters</td></tr>"
+ "<tr><td>%%</td><td>%</td></tr>"
+ "</table>");
+ return help;
+}
+
+void EditorManager::openInExternalEditor()
+{
+ IEditor *editor = currentEditor();
+ if (!editor)
+ return;
+ if (editor->file()->isModified()) {
+ bool cancelled = false;
+ QList<IFile*> list = CoreImpl::instance()->fileManager()->
+ saveModifiedFiles(QList<IFile*>() << editor->file(), &cancelled);
+ if (cancelled)
+ return;
+ }
+
+
+ QRect rect = editor->widget()->rect();
+ QFont font = editor->widget()->font();
+ QFontMetrics fm(font);
+ rect.moveTo(editor->widget()->mapToGlobal(QPoint(0,0)));
+
+ QString pre = m_d->m_externalEditor;
+ QString cmd;
+ for (int i = 0; i < pre.size(); ++i) {
+ QChar c = pre.at(i);
+ if (c == QLatin1Char('%') && i < pre.size()-1) {
+ c = pre.at(++i);
+ QString s;
+ if (c == QLatin1Char('f'))
+ s = editor->file()->fileName();
+ else if (c == QLatin1Char('l'))
+ s = QString::number(editor->currentLine());
+ else if (c == QLatin1Char('c'))
+ s = QString::number(editor->currentColumn());
+ else if (c == QLatin1Char('x'))
+ s = QString::number(rect.x());
+ else if (c == QLatin1Char('y'))
+ s = QString::number(rect.y());
+ else if (c == QLatin1Char('w'))
+ s = QString::number(rect.width());
+ else if (c == QLatin1Char('h'))
+ s = QString::number(rect.height());
+ else if (c == QLatin1Char('W'))
+ s = QString::number(rect.width() / fm.width(QLatin1Char('x')));
+ else if (c == QLatin1Char('H'))
+ s = QString::number(rect.height() / fm.lineSpacing());
+ else if (c == QLatin1Char('%'))
+ s = c;
+ else {
+ s = QLatin1Char('%');
+ cmd += c;
+ }
+ cmd += s;
+ continue;
+
+ }
+ cmd += c;
+ }
+
+ QProcess::startDetached(cmd);
+}
+
+void EditorManager::setExternalEditor(const QString &editor)
+{
+ m_d->m_externalEditor = editor;
+}
+
+QString EditorManager::externalEditor() const
+{
+ return m_d->m_externalEditor;
+}
+
+//===================EditorClosingCoreListener======================
+
+EditorClosingCoreListener::EditorClosingCoreListener(EditorManager *em)
+ : m_em(em)
+{
+}
+
+bool EditorClosingCoreListener::editorAboutToClose(IEditor *)
+{
+ return true;
+}
+
+bool EditorClosingCoreListener::coreAboutToClose()
+{
+ // Do not ask for files to save.
+ // MainWindow::closeEvent has already done that.
+ return m_em->closeAllEditors(false);
+}
diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h
new file mode 100644
index 0000000000..750e35b0cb
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/editormanager.h
@@ -0,0 +1,229 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EDITORMANAGER_H
+#define EDITORMANAGER_H
+
+#include "../core_global.h"
+
+#include <coreplugin/icorelistener.h>
+
+#include <QtGui/QWidget>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class EditorGroup;
+class IContext;
+class ICore;
+class IEditor;
+class IEditorFactory;
+class MimeType;
+class IFile;
+class IMode;
+
+enum MakeWritableResult {
+ OpenedWithVersionControl,
+ MadeWritable,
+ SavedAs,
+ Failed
+};
+
+struct EditorManagerPrivate;
+namespace Internal {
+class OpenEditorsWindow;
+class EditorSplitter;
+
+class EditorClosingCoreListener;
+class OpenEditorsViewFactory;
+} // namespace Internal
+
+class CORE_EXPORT EditorManagerPlaceHolder : public QWidget
+{
+ Q_OBJECT
+public:
+ EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent = 0);
+ ~EditorManagerPlaceHolder();
+ static EditorManagerPlaceHolder* current();
+private slots:
+ void currentModeChanged(Core::IMode *);
+private:
+ Core::IMode *m_mode;
+ static EditorManagerPlaceHolder* m_current;
+};
+
+class CORE_EXPORT EditorManager : public QWidget
+{
+ Q_OBJECT
+
+public:
+ typedef QList<IEditorFactory*> EditorFactoryList;
+
+ explicit EditorManager(ICore *core, QWidget *parent);
+ virtual ~EditorManager();
+ void init();
+ static EditorManager *instance() { return m_instance; }
+
+ IEditor *openEditor(const QString &fileName,
+ const QString &editorKind = QString(),
+ bool ignoreNavigationHistory = false);
+ QStringList getOpenFileNames() const;
+ QString getOpenWithEditorKind(const QString &fileName) const;
+
+
+ void ensureEditorManagerVisible();
+ IEditor *newFile(const QString &editorKind,
+ QString *titlePattern = 0,
+ const QString &contents = QString());
+ bool hasEditor(const QString &fileName) const;
+ QList<IEditor *> editorsForFileName(const QString &filename) const;
+
+ void setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory = false);
+ IEditor *currentEditor() const;
+ EditorGroup *currentEditorGroup() const;
+
+ QList<IEditor*> openedEditors() const;
+ QList<IEditor*> editorsForFiles(QList<IFile*> files) const;
+ QList<EditorGroup *> editorGroups() const;
+ QList<IEditor*> editorHistory() const;
+ void addCurrentPositionToNavigationHistory(bool compress = false);
+
+ bool hasDuplicate(IEditor *editor) const;
+
+ bool saveEditor(IEditor *editor);
+
+ bool closeEditors(const QList<IEditor *> editorsToClose, bool askAboutModifiedEditors = true);
+
+ MakeWritableResult makeEditorWritable(IEditor *editor);
+
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+
+ IEditor *restoreEditor(QString fileName, QString editorKind, EditorGroup *group);
+
+ void saveSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+ QSize minimumSizeHint() const;
+
+ Internal::OpenEditorsWindow *windowPopup() const;
+ void showWindowPopup() const;
+
+ Internal::EditorSplitter *editorSplitter() const;
+
+ void showEditorInfoBar(const QString &kind,
+ const QString &infoText,
+ const QString &buttonText = QString(),
+ QObject *object = 0, const char *member = 0);
+
+ void hideEditorInfoBar(const QString &kind);
+
+ EditorFactoryList editorFactories(const MimeType &mimeType, bool bestMatchOnly = true) const;
+
+ void setExternalEditor(const QString &);
+ QString externalEditor() const;
+ QString externalEditorHelpText() const;
+
+signals:
+ void currentEditorChanged(Core::IEditor *editor);
+ void editorCreated(Core::IEditor *editor, const QString &fileName);
+ void editorOpened(Core::IEditor *editor);
+ void editorAboutToClose(Core::IEditor *editor);
+ void editorsClosed(QList<Core::IEditor *> editors);
+ void editorGroupsChanged();
+
+public slots:
+ bool closeAllEditors(bool askAboutModifiedEditors = true);
+ void openInExternalEditor();
+
+private slots:
+ bool saveFile(Core::IEditor *editor = 0);
+ bool saveFileAs(Core::IEditor *editor = 0);
+ void closeEditor();
+ void closeEditor(Core::IEditor *editor);
+ void gotoNextDocHistory();
+ void gotoPreviousDocHistory();
+ void updateCurrentEditorAndGroup(Core::IContext *context);
+ void updateEditorHistory();
+ void updateActions();
+ void duplicateEditor();
+ void revertToSaved();
+ void goBackInNavigationHistory();
+ void goForwardInNavigationHistory();
+ void makeCurrentEditorWritable();
+
+private:
+ QList<IFile *> filesForEditors(QList<IEditor *> editors) const;
+ IEditor *createEditor(const QString &mimeType = QString(),
+ const QString &fileName = QString());
+ void insertEditor(IEditor *editor, bool ignoreNavigationHistory = false, EditorGroup *group = 0);
+ bool registerEditor(IEditor *editor);
+ bool unregisterEditor(IEditor *editor);
+ EditorGroup *groupOfEditor(IEditor *editor) const;
+ void editorChanged(IEditor *editor);
+ void registerDuplicate(IEditor *original,
+ IEditor *duplicate);
+ void unregisterDuplicate(IEditor *editor);
+ QList<IEditor *> duplicates(IEditor *editor) const;
+
+ QByteArray saveOpenEditorList() const;
+ void restoreOpenEditorList(const QByteArray &state);
+ void restoreEditorState(IEditor *editor);
+
+ static EditorManager *m_instance;
+ EditorManagerPrivate *m_d;
+};
+
+//===================EditorClosingCoreListener======================
+
+namespace Internal {
+
+class EditorClosingCoreListener : public ICoreListener {
+ Q_OBJECT
+
+public:
+ EditorClosingCoreListener(EditorManager *em);
+ bool editorAboutToClose(IEditor *editor);
+ bool coreAboutToClose();
+
+private:
+ EditorManager *m_em;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // EDITORMANAGER_H
diff --git a/src/plugins/coreplugin/editormanager/editorsplitter.cpp b/src/plugins/coreplugin/editormanager/editorsplitter.cpp
new file mode 100644
index 0000000000..82710e7e93
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/editorsplitter.cpp
@@ -0,0 +1,664 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "editorsplitter.h"
+#include "editormanager.h"
+#include "openeditorswindow.h"
+#include "stackededitorgroup.h"
+#include "minisplitter.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QMenu>
+#include <QtGui/QApplication>
+
+using namespace Core;
+using namespace Core::Internal;
+
+EditorSplitter::EditorSplitter(ICore *core, QWidget *parent)
+ : QWidget(parent),
+ m_curGroup(0),
+ m_core(core)
+{
+ registerActions();
+ createRootGroup();
+ updateActions();
+}
+
+EditorSplitter::~EditorSplitter()
+{
+}
+
+void EditorSplitter::registerActions()
+{
+ QList<int> gc = QList<int>() << Constants::C_GLOBAL_ID;
+ const QList<int> editorManagerContext =
+ QList<int>() << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_EDITORMANAGER);
+
+ ActionManagerInterface *am = m_core->actionManager();
+ IActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
+ ICommand *cmd;
+
+ //Horizontal Action
+ m_horizontalSplitAction = new QAction(tr("Split Left/Right"), this);
+ cmd = am->registerAction(m_horizontalSplitAction, Constants::HORIZONTAL, editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
+ connect(m_horizontalSplitAction, SIGNAL(triggered()),
+ this, SLOT(splitHorizontal()));
+
+ //Vertical Action
+ m_verticalSplitAction = new QAction(tr("Split Top/Bottom"), this);
+ cmd = am->registerAction(m_verticalSplitAction, Constants::VERTICAL, editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
+ connect(m_verticalSplitAction, SIGNAL(triggered()),
+ this, SLOT(splitVertical()));
+
+ //Unsplit Action
+ m_unsplitAction = new QAction(tr("Unsplit"), this);
+ cmd = am->registerAction(m_unsplitAction, Constants::REMOVE, editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
+ connect(m_unsplitAction, SIGNAL(triggered()),
+ this, SLOT(unsplit()));
+
+ //Default Layout menu
+ IActionContainer *mLayout = am->createMenu("QtCreator.Menu.Window.Layout");
+ mwindow->addMenu(mLayout, Constants::G_WINDOW_SPLIT);
+ mLayout->menu()->setTitle(tr("Default Splitter Layout"));
+
+ //Set Current As Default
+ m_currentAsDefault = new QAction(tr("Save Current as Default"), this);
+ cmd = am->registerAction(m_currentAsDefault, Constants::SAVEASDEFAULT, editorManagerContext);
+ mLayout->addAction(cmd);
+ connect(m_currentAsDefault, SIGNAL(triggered()),
+ this, SLOT(saveCurrentLayout()));
+
+ //Restore Default
+ m_restoreDefault = new QAction(tr("Restore Default Layout"), this);
+ cmd = am->registerAction(m_restoreDefault, Constants::RESTOREDEFAULT, editorManagerContext);
+ mLayout->addAction(cmd);
+ connect(m_restoreDefault, SIGNAL(triggered()),
+ this, SLOT(restoreDefaultLayout()));
+
+ // TODO: The previous and next actions are removed, to be reenabled when they
+ // navigate according to code navigation history. And they need different shortcuts on the mac
+ // since Alt+Left/Right is jumping wordwise in editors
+#if 0
+ // Goto Previous Action
+ m_gotoPreviousEditorAction = new QAction(QIcon(Constants::ICON_PREV), tr("Previous Document"), this);
+ cmd = am->registerAction(m_gotoPreviousEditorAction, Constants::GOTOPREV, editorManagerContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left")));
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+ connect(m_gotoPreviousEditorAction, SIGNAL(triggered()), this, SLOT(gotoPreviousEditor()));
+
+ // Goto Next Action
+ m_gotoNextEditorAction = new QAction(QIcon(Constants::ICON_NEXT), tr("Next Document"), this);
+ cmd = am->registerAction(m_gotoNextEditorAction, Constants::GOTONEXT, editorManagerContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right")));
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
+ connect(m_gotoNextEditorAction, SIGNAL(triggered()), this, SLOT(gotoNextEditor()));
+#endif
+
+ // Previous Group Action
+ m_gotoPreviousGroupAction = new QAction(tr("Previous Group"), this);
+ cmd = am->registerAction(m_gotoPreviousGroupAction, Constants::GOTOPREVIOUSGROUP, editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE_GROUPS);
+ connect(m_gotoPreviousGroupAction, SIGNAL(triggered()), this, SLOT(selectPreviousGroup()));
+
+ // Next Group Action
+ m_gotoNextGroupAction = new QAction(tr("Next Group"), this);
+ cmd = am->registerAction(m_gotoNextGroupAction, Constants::GOTONEXTGROUP, editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE_GROUPS);
+ connect(m_gotoNextGroupAction, SIGNAL(triggered()), this, SLOT(selectNextGroup()));
+
+ // Move to Previous Group
+ m_moveDocToPreviousGroupAction = new QAction(tr("Move Document to Previous Group"), this);
+ cmd = am->registerAction(m_moveDocToPreviousGroupAction, "QtCreator.DocumentToPreviousGroup", editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE_GROUPS);
+ connect(m_moveDocToPreviousGroupAction, SIGNAL(triggered()), this, SLOT(moveDocToPreviousGroup()));
+
+ // Move to Next Group
+ m_moveDocToNextGroupAction = new QAction(tr("Move Document to Next Group"), this);
+ cmd = am->registerAction(m_moveDocToNextGroupAction, "QtCreator.DocumentToNextGroup", editorManagerContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE_GROUPS);
+ connect(m_moveDocToNextGroupAction, SIGNAL(triggered()), this, SLOT(moveDocToNextGroup()));
+}
+
+void EditorSplitter::updateActions()
+{
+ const bool hasMultipleGroups = (qobject_cast<QSplitter*>(m_root) != 0);
+ Q_ASSERT(currentGroup());
+ const bool hasEditors = (currentGroup()->editorCount() != 0);
+ m_unsplitAction->setEnabled(hasMultipleGroups);
+#if 0
+ const bool hasMultipleEditors = (editorCount() > 1);
+ m_gotoNextEditorAction->setEnabled(hasMultipleEditors);
+ m_gotoPreviousEditorAction->setEnabled(hasMultipleEditors);
+#endif
+ m_gotoPreviousGroupAction->setEnabled(hasMultipleGroups);
+ m_gotoNextGroupAction->setEnabled(hasMultipleGroups);
+ m_moveDocToPreviousGroupAction->setEnabled(hasEditors && hasMultipleGroups);
+ m_moveDocToNextGroupAction->setEnabled(hasEditors && hasMultipleGroups);
+}
+
+int EditorSplitter::editorCount() const
+{
+ int count = 0;
+ foreach (EditorGroup *group, groups()) {
+ count += group->editorCount();
+ }
+ return count;
+}
+
+void EditorSplitter::createRootGroup()
+{
+ QHBoxLayout *l = new QHBoxLayout(this);
+ l->setMargin(0);
+ l->setSpacing(0);
+ EditorGroup *rootGroup = createGroup();
+ m_root = rootGroup->widget();
+ l->addWidget(m_root);
+ setCurrentGroup(rootGroup);
+}
+
+void EditorSplitter::splitHorizontal()
+{
+ split(Qt::Horizontal);
+}
+
+void EditorSplitter::splitVertical()
+{
+ split(Qt::Vertical);
+}
+
+void EditorSplitter::gotoNextEditor()
+{
+ OpenEditorsWindow *dialog = EditorManager::instance()->windowPopup();
+ dialog->setMode(OpenEditorsWindow::ListMode);
+ dialog->selectNextEditor();
+ EditorManager::instance()->showWindowPopup();
+}
+
+void EditorSplitter::gotoPreviousEditor()
+{
+ OpenEditorsWindow *dialog = EditorManager::instance()->windowPopup();
+ dialog->setMode(OpenEditorsWindow::ListMode);
+ dialog->selectPreviousEditor();
+ EditorManager::instance()->showWindowPopup();
+}
+
+void EditorSplitter::setCurrentGroup(EditorGroup *group)
+{
+ if (!group || group == m_curGroup)
+ return;
+ m_curGroup = group;
+ if (m_curGroup->widget()->focusWidget() != QApplication::focusWidget())
+ m_curGroup->widget()->setFocus();
+ updateActions();
+}
+
+QList<EditorGroup*> EditorSplitter::groups() const
+{
+ QList<EditorGroup*> grps;
+ collectGroups(m_root, grps);
+ return grps;
+}
+
+void EditorSplitter::collectGroups(QWidget *widget, QList<EditorGroup*> &groups) const
+{
+ EditorGroup *group = qobject_cast<EditorGroup *>(widget);
+ if (group) {
+ groups += group;
+ return;
+ }
+ QSplitter *splitter = qobject_cast<QSplitter*>(widget);
+ Q_ASSERT(splitter);
+ collectGroups(splitter->widget(LEFT), groups);
+ collectGroups(splitter->widget(RIGHT), groups);
+}
+
+
+EditorGroup *EditorSplitter::currentGroup() const
+{
+ return m_curGroup;
+}
+
+void EditorSplitter::split(Qt::Orientation orientation)
+{
+ EditorGroup *curGroup = currentGroup();
+ IEditor *editor = curGroup->currentEditor();
+ split(orientation, 0);
+ if (editor) {
+ EditorGroup *otherGroup = currentGroup();
+ if (curGroup != otherGroup) {
+ curGroup->removeEditor(editor);
+ otherGroup->addEditor(editor);
+ }
+ }
+ emit editorGroupsChanged();
+}
+
+QSplitter *EditorSplitter::split(Qt::Orientation orientation, EditorGroup *group)
+{
+ EditorGroup *curGroup = group;
+ if (!curGroup)
+ curGroup = currentGroup();
+ if (!curGroup)
+ return 0;
+
+ int oldSibling1 = -1;
+ int oldSibling2 = -1;
+ int idx = 1;
+ QWidget *curGroupWidget = curGroup->widget();
+ QSplitter *parentSplitter = qobject_cast<QSplitter*>(curGroupWidget->parentWidget());
+ if (parentSplitter) {
+ if (parentSplitter->orientation() == Qt::Vertical) {
+ oldSibling1 = parentSplitter->widget(LEFT)->height();
+ oldSibling2 = parentSplitter->widget(RIGHT)->height();
+ } else {
+ oldSibling1 = parentSplitter->widget(LEFT)->width();
+ oldSibling2 = parentSplitter->widget(RIGHT)->width();
+ }
+ idx = parentSplitter->indexOf(curGroupWidget);
+ }
+
+ QLayout *l = curGroupWidget->parentWidget()->layout();
+ curGroupWidget->setParent(0);
+
+ QSplitter *splitter = new MiniSplitter(0);
+ splitter->setOrientation(orientation);
+ EditorGroup *eg = createGroup();
+
+ splitter->addWidget(curGroupWidget);
+ splitter->addWidget(eg->widget());
+
+ if (curGroupWidget == m_root) {
+ l->addWidget(splitter);
+ m_root = splitter;
+ } else {
+ parentSplitter->insertWidget(idx, splitter);
+ }
+
+ if (parentSplitter)
+ parentSplitter->setSizes(QList<int>() << oldSibling1 << oldSibling2);
+ if (orientation == Qt::Vertical)
+ splitter->setSizes(QList<int>() << curGroupWidget->height()/2
+ << curGroupWidget->height()/2);
+ else
+ splitter->setSizes(QList<int>() << curGroupWidget->width()/2
+ << curGroupWidget->width()/2);
+ setCurrentGroup(eg);
+ return splitter;
+}
+
+void EditorSplitter::unsplit()
+{
+ EditorGroup *curGroup = currentGroup();
+ if (!curGroup)
+ return;
+ QWidget *curGroupWidget = curGroup->widget();
+ Q_ASSERT(curGroupWidget);
+ IEditor *selectedEditor = curGroup->currentEditor();
+
+ QSplitter *parentSplitter = qobject_cast<QSplitter*>(curGroupWidget->parentWidget());
+ if (parentSplitter) {
+ int oldSibling1 = -1;
+ int oldSibling2 = -1;
+
+ EditorGroup *e1 = qobject_cast<EditorGroup *>(parentSplitter->widget(LEFT));
+ EditorGroup *e2 = qobject_cast<EditorGroup *>(parentSplitter->widget(RIGHT));
+
+ QWidget *w = parentSplitter->parentWidget();
+ QSplitter *grandParentSplitter = qobject_cast<QSplitter*>(w);
+ int idx = 0;
+ if (grandParentSplitter) {
+ idx = grandParentSplitter->indexOf(parentSplitter);
+ if (grandParentSplitter->orientation() == Qt::Vertical) {
+ oldSibling1 = grandParentSplitter->widget(LEFT)->height();
+ oldSibling2 = grandParentSplitter->widget(RIGHT)->height();
+ } else {
+ oldSibling1 = grandParentSplitter->widget(LEFT)->width();
+ oldSibling2 = grandParentSplitter->widget(RIGHT)->width();
+ }
+ }
+ if (e1 && e2) { // we are unsplitting a split that contains of groups directly not one or more additional splits
+ e1->moveEditorsFromGroup(e2);
+ parentSplitter->setParent(0);
+ if (grandParentSplitter) {
+ grandParentSplitter->insertWidget(idx, e1->widget());
+ } else {
+ w->layout()->addWidget(e1->widget());
+ m_root = e1->widget();
+ }
+ setCurrentGroup(e1);
+ deleteGroup(e2);
+ e2 = 0;
+ delete parentSplitter;
+ e1->setCurrentEditor(selectedEditor);
+ } else if (e1 || e2) {
+ parentSplitter->setParent(0);
+ QSplitter *s = 0;
+ if (e1) {
+ s = qobject_cast<QSplitter*>(parentSplitter->widget(RIGHT));
+ } else {
+ s = qobject_cast<QSplitter*>(parentSplitter->widget(LEFT));
+ e1 = e2;
+ }
+
+ if (grandParentSplitter) {
+ grandParentSplitter->insertWidget(idx, s);
+ } else {
+ w->layout()->addWidget(s);
+ m_root = s;
+ }
+ EditorGroup *leftMost = groupFarthestOnSide(s, LEFT);
+ leftMost->moveEditorsFromGroup(e1);
+ leftMost->setCurrentEditor(selectedEditor);
+ setCurrentGroup(leftMost);
+ deleteGroup(e1);
+ }
+ if (grandParentSplitter)
+ grandParentSplitter->setSizes(QList<int>() << oldSibling1 << oldSibling2);
+ emit editorGroupsChanged();
+ }
+ updateActions();
+}
+
+void EditorSplitter::unsplitAll()
+{
+ QSplitter *rootSplit = qobject_cast<QSplitter *>(m_root);
+ if (!rootSplit)
+ return;
+ // first create and set the new root, then kill the original stuff
+ // this way we can avoid unnecessary signals/ context changes
+ rootSplit->setParent(0);
+ EditorGroup *rootGroup = createGroup();
+ QLayout *l = layout();
+ l->addWidget(rootGroup->widget());
+ m_root = rootGroup->widget();
+ setCurrentGroup(rootGroup);
+ // kill old hierarchy
+ QList<IEditor *> editors;
+ unsplitAll(rootSplit->widget(1), editors);
+ unsplitAll(rootSplit->widget(0), editors);
+ delete rootSplit;
+ rootSplit = 0;
+ foreach (IEditor *editor, editors) {
+ rootGroup->addEditor(editor);
+ }
+}
+
+void EditorSplitter::unsplitAll(QWidget *node, QList<IEditor*> &editors)
+{
+ QSplitter *splitter = qobject_cast<QSplitter *>(node);
+ if (splitter) {
+ unsplitAll(splitter->widget(1), editors);
+ unsplitAll(splitter->widget(0), editors);
+ delete splitter;
+ splitter = 0;
+ } else {
+ EditorGroup *group = qobject_cast<EditorGroup *>(node);
+ editors << group->editors();
+ bool blocking = group->widget()->blockSignals(true);
+ foreach (IEditor *editor, group->editors()) {
+ group->removeEditor(editor);
+ }
+ group->widget()->blockSignals(blocking);
+ deleteGroup(group);
+ }
+}
+
+EditorGroup *EditorSplitter::groupFarthestOnSide(QWidget *node, Side side) const
+{
+ QWidget *current = node;
+ QSplitter *split = 0;
+ while ((split = qobject_cast<QSplitter*>(current))) {
+ current = split->widget(side);
+ }
+ return qobject_cast<EditorGroup *>(current);
+}
+
+void EditorSplitter::selectNextGroup()
+{
+ EditorGroup *curGroup = currentGroup();
+ Q_ASSERT(curGroup);
+ setCurrentGroup(nextGroup(curGroup, RIGHT));
+}
+
+void EditorSplitter::selectPreviousGroup()
+{
+ EditorGroup *curGroup = currentGroup();
+ Q_ASSERT(curGroup);
+ setCurrentGroup(nextGroup(curGroup, LEFT));
+}
+
+EditorGroup *EditorSplitter::nextGroup(EditorGroup *curGroup, Side side) const
+{
+ Q_ASSERT(curGroup);
+ QWidget *curWidget = curGroup->widget();
+ QWidget *parent = curWidget->parentWidget();
+ while (curWidget != m_root) {
+ QSplitter *splitter = qobject_cast<QSplitter *>(parent);
+ Q_ASSERT(splitter);
+ if (splitter->widget(side) != curWidget) {
+ curWidget = splitter->widget(side);
+ break;
+ }
+ curWidget = parent;
+ parent = curWidget->parentWidget();
+ }
+ return groupFarthestOnSide(curWidget, side==LEFT ? RIGHT : LEFT);
+}
+
+void EditorSplitter::moveDocToAdjacentGroup(Side side)
+{
+ EditorGroup *curGroup = currentGroup();
+ Q_ASSERT(curGroup);
+ IEditor *editor = curGroup->currentEditor();
+ if (!editor)
+ return;
+ EditorGroup *next = nextGroup(curGroup, side);
+ next->moveEditorFromGroup(curGroup, editor);
+ setCurrentGroup(next);
+}
+
+void EditorSplitter::moveDocToNextGroup()
+{
+ moveDocToAdjacentGroup(RIGHT);
+}
+
+void EditorSplitter::moveDocToPreviousGroup()
+{
+ moveDocToAdjacentGroup(LEFT);
+}
+
+QWidget *EditorSplitter::recreateGroupTree(QWidget *node)
+{
+ QSplitter *splitter = qobject_cast<QSplitter *>(node);
+ if (!splitter) {
+ EditorGroup *group = qobject_cast<EditorGroup *>(node);
+ Q_ASSERT(group);
+ IEditor *currentEditor = group->currentEditor();
+ EditorGroup *newGroup = createGroup();
+ bool block = newGroup->widget()->blockSignals(true);
+ foreach (IEditor *editor, group->editors()) {
+ newGroup->addEditor(editor);
+ }
+ newGroup->setCurrentEditor(currentEditor);
+ deleteGroup(group);
+ newGroup->widget()->blockSignals(block);
+ return newGroup->widget();
+ } else {
+ QByteArray splitterState = splitter->saveState();
+ QWidget *orig0 = splitter->widget(0);
+ QWidget *orig1 = splitter->widget(1);
+ QWidget *g0 = recreateGroupTree(orig0);
+ QWidget *g1 = recreateGroupTree(orig1);
+ splitter->insertWidget(0, g0);
+ splitter->insertWidget(1, g1);
+ splitter->restoreState(splitterState);
+ return node;
+ }
+}
+
+void EditorSplitter::saveCurrentLayout()
+{
+ QSettings *settings = m_core->settings();
+ settings->setValue("EditorManager/Splitting", saveState());
+}
+
+void EditorSplitter::restoreDefaultLayout()
+{
+ QSettings *settings = m_core->settings();
+ if (settings->contains("EditorManager/Splitting"))
+ restoreState(settings->value("EditorManager/Splitting").toByteArray());
+}
+
+void EditorSplitter::saveSettings(QSettings * /*settings*/) const
+{
+}
+
+void EditorSplitter::readSettings(QSettings * /*settings*/)
+{
+ restoreDefaultLayout();
+}
+
+QByteArray EditorSplitter::saveState() const
+{
+ //todo: versioning
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::WriteOnly);
+ saveState(m_root, stream);
+ return bytes;
+}
+
+bool EditorSplitter::restoreState(const QByteArray &state)
+{
+ unsplitAll();
+ //todo: versioning
+ QDataStream stream(state);
+ EditorGroup *curGroup =
+ restoreState(qobject_cast<EditorGroup *>(m_root), stream);
+ setCurrentGroup(curGroup);
+ return true;
+}
+
+void EditorSplitter::saveState(QWidget *current, QDataStream &stream) const
+{
+ QSplitter *splitter = qobject_cast<QSplitter *>(current);
+ quint8 type;
+ if (splitter) {
+ type = 0;
+ stream << type;
+ stream << splitter->saveState();
+ saveState(splitter->widget(0), stream);
+ saveState(splitter->widget(1), stream);
+ } else {
+ EditorGroup *group = qobject_cast<EditorGroup *>(current);
+ Q_ASSERT(group);
+ if (group != currentGroup())
+ type = 1;
+ else
+ type = 2;
+ stream << type;
+ }
+}
+
+EditorGroup *EditorSplitter::restoreState(EditorGroup *current,
+ QDataStream &stream)
+{
+ EditorGroup *curGroup = 0;
+ EditorGroup *group;
+ quint8 type;
+ stream >> type;
+ if (type == 0) {
+ QSplitter *splitter = split(Qt::Horizontal, current);
+ QByteArray splitterState;
+ stream >> splitterState;
+ splitter->restoreState(splitterState);
+ group = restoreState(qobject_cast<EditorGroup *>(splitter->widget(0)),
+ stream);
+ if (group)
+ curGroup = group;
+ group = restoreState(qobject_cast<EditorGroup *>(splitter->widget(1)),
+ stream);
+ if (group)
+ curGroup = group;
+ } else {
+ if (type == 2)
+ return current;
+ }
+ return curGroup;
+}
+
+QMap<QString,EditorGroup *> EditorSplitter::pathGroupMap()
+{
+ QMap<QString,EditorGroup *> map;
+ fillPathGroupMap(m_root, "", map);
+ return map;
+}
+
+void EditorSplitter::fillPathGroupMap(QWidget *current, QString currentPath,
+ QMap<QString,EditorGroup *> &map)
+{
+ EditorGroup *group = qobject_cast<EditorGroup *>(current);
+ if (group) {
+ map.insert(currentPath, group);
+ } else {
+ QSplitter *splitter = qobject_cast<QSplitter *>(current);
+ Q_ASSERT(splitter);
+ fillPathGroupMap(splitter->widget(0), currentPath+"0", map);
+ fillPathGroupMap(splitter->widget(1), currentPath+"1", map);
+ }
+}
+
+EditorGroup *EditorSplitter::createGroup()
+{
+ EditorGroup *group = new StackedEditorGroup(this);
+ connect(group, SIGNAL(closeRequested(Core::IEditor *)),
+ this, SIGNAL(closeRequested(Core::IEditor *)));
+ connect(group, SIGNAL(editorRemoved(Core::IEditor *)),
+ this, SLOT(updateActions()));
+ connect(group, SIGNAL(editorAdded(Core::IEditor *)),
+ this, SLOT(updateActions()));
+ m_core->addContextObject(group->contextObject());
+ return group;
+}
+
+void EditorSplitter::deleteGroup(EditorGroup *group)
+{
+ m_core->removeContextObject(group->contextObject());
+ delete group;
+}
diff --git a/src/plugins/coreplugin/editormanager/editorsplitter.h b/src/plugins/coreplugin/editormanager/editorsplitter.h
new file mode 100644
index 0000000000..12faab68da
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/editorsplitter.h
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EDITORSPLITTER_H
+#define EDITORSPLITTER_H
+
+#include <QtCore/QMap>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QSettings>
+#include <QtGui/QWidget>
+#include <QtGui/QAction>
+#include <QtGui/QSplitter>
+
+namespace Core {
+
+class EditorGroup;
+class ICore;
+class IEditor;
+
+namespace Internal {
+
+class EditorSplitter : public QWidget
+{
+ Q_OBJECT
+
+public:
+ EditorSplitter(ICore *core, QWidget *parent = 0);
+ ~EditorSplitter();
+
+ void setCurrentGroup(Core::EditorGroup *group);
+ EditorGroup *currentGroup() const;
+ QList<EditorGroup*> groups() const;
+
+ void split(Qt::Orientation orientation);
+
+ void saveSettings(QSettings *settings) const;
+ void readSettings(QSettings *settings);
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+
+ QMap<QString,EditorGroup *> pathGroupMap();
+
+public slots:
+ void unsplit();
+
+signals:
+ void closeRequested(Core::IEditor *editor);
+ void editorGroupsChanged();
+
+private slots:
+ void splitHorizontal();
+ void splitVertical();
+ void gotoNextEditor();
+ void gotoPreviousEditor();
+ void updateActions();
+ void selectNextGroup();
+ void selectPreviousGroup();
+ void moveDocToNextGroup();
+ void moveDocToPreviousGroup();
+ void saveCurrentLayout();
+ void restoreDefaultLayout();
+
+private:
+ enum Side {LEFT = 0, RIGHT = 1};
+
+ void registerActions();
+ void createRootGroup();
+ EditorGroup *createGroup();
+ void deleteGroup(EditorGroup *group);
+ void collectGroups(QWidget *widget, QList<EditorGroup*> &groups) const;
+ EditorGroup *groupFarthestOnSide(QWidget *node, Side side) const;
+ EditorGroup *nextGroup(EditorGroup *curGroup, Side side) const;
+ void moveDocToAdjacentGroup(Side side);
+ void saveState(QWidget *current, QDataStream &stream) const;
+ EditorGroup *restoreState(EditorGroup *current, QDataStream &stream);
+ QSplitter *split(Qt::Orientation orientation, EditorGroup *group);
+ void fillPathGroupMap(QWidget *current, QString currentPath,
+ QMap<QString,EditorGroup *> &map);
+ void unsplitAll();
+ void unsplitAll(QWidget *node, QList<IEditor *> &editors);
+ QWidget *recreateGroupTree(QWidget *node);
+ int editorCount() const;
+
+ QWidget *m_root;
+ EditorGroup *m_curGroup;
+ ICore *m_core;
+
+ QAction *m_horizontalSplitAction;
+ QAction *m_verticalSplitAction;
+ QAction *m_unsplitAction;
+#if 0
+ QAction *m_gotoNextEditorAction;
+ QAction *m_gotoPreviousEditorAction;
+#endif
+ QAction *m_gotoNextGroupAction;
+ QAction *m_gotoPreviousGroupAction;
+ QAction *m_moveDocToNextGroupAction;
+ QAction *m_moveDocToPreviousGroupAction;
+ QAction *m_currentAsDefault;
+ QAction *m_restoreDefault;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // EDITORSPLITTER_H
diff --git a/src/plugins/coreplugin/editormanager/ieditor.h b/src/plugins/coreplugin/editormanager/ieditor.h
new file mode 100644
index 0000000000..66a9fdca14
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/ieditor.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IEDITOR_H
+#define IEDITOR_H
+
+#include <coreplugin/core_global.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/ifile.h>
+
+QT_BEGIN_NAMESPACE
+class QToolBar;
+QT_END_NAMESPACE
+
+namespace Core {
+
+/*!
+ \class Core::IEditor
+ \brief The IEditor is an interface for providing different editors for different file types.
+
+ Classes that implement this interface are for example the editors for
+ C++ files, ui-files and resource files.
+
+ Whenever a user wants to edit or create a file, the EditorManager scans all
+ EditorFactoryInterfaces for suitable editors. The selected EditorFactory
+ is then asked to create an editor, which must implement this interface.
+
+ Guidelines for implementing:
+ \list
+ \o displayName() is used as a user visible description of the document (usually filename w/o path).
+ \o kind() must be the same value as the kind() of the corresponding EditorFactory.
+ \o The changed() signal should be emitted when the modified state of the document changes
+ (so /bold{not} every time the document changes, but /bold{only once}).
+ \o If duplication is supported, you need to ensure that all duplicates
+ return the same file().
+ \endlist
+
+ \sa Core::EditorFactoryInterface Core::IContext
+
+*/
+
+class CORE_EXPORT IEditor : public IContext
+{
+ Q_OBJECT
+public:
+ IEditor(QObject *parent = 0) : IContext(parent) {}
+ virtual ~IEditor() {}
+
+ virtual bool createNew(const QString &contents = QString()) = 0;
+ virtual bool open(const QString &fileName = QString()) = 0;
+ virtual IFile *file() = 0;
+ virtual const char *kind() const = 0;
+ virtual QString displayName() const = 0;
+ virtual void setDisplayName(const QString &title) = 0;
+
+ virtual bool duplicateSupported() const = 0;
+ virtual IEditor *duplicate(QWidget *parent) = 0;
+
+ virtual QByteArray saveState() const = 0;
+ virtual bool restoreState(const QByteArray &state) = 0;
+
+ virtual int currentLine() const { return 0; };
+ virtual int currentColumn() const { return 0; };
+
+ virtual QToolBar *toolBar() = 0;
+
+signals:
+ void changed();
+};
+
+} // namespace Core
+
+#endif //IEDITOR_H
diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory.h b/src/plugins/coreplugin/editormanager/ieditorfactory.h
new file mode 100644
index 0000000000..2b70ef95b9
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/ieditorfactory.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IEDITORFACTORY_H
+#define IEDITORFACTORY_H
+
+#include <coreplugin/ifilefactory.h>
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class CORE_EXPORT IEditorFactory : public Core::IFileFactory
+{
+ Q_OBJECT
+public:
+ IEditorFactory(QObject *parent = 0) : IFileFactory(parent) {}
+ virtual ~IEditorFactory() {}
+
+ virtual IEditor *createEditor(QWidget *parent) = 0;
+};
+
+} // namespace Core
+
+#endif // IEDITORFACTORY_H
diff --git a/src/plugins/coreplugin/editormanager/openeditorsview.cpp b/src/plugins/coreplugin/editormanager/openeditorsview.cpp
new file mode 100644
index 0000000000..b2400853ec
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/openeditorsview.cpp
@@ -0,0 +1,310 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "openeditorsview.h"
+#include "editorgroup.h"
+#include "editormanager.h"
+#include "coreimpl.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <QtCore/QTimer>
+#include <QtGui/QMenu>
+#include <QtGui/QPainter>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleOption>
+#include <QtGui/QHeaderView>
+#include <QtGui/QKeyEvent>
+#ifdef Q_WS_MAC
+#include <qmacstyle_mac.h>
+#endif
+
+Q_DECLARE_METATYPE(Core::IEditor*)
+
+using namespace Core;
+using namespace Core::Internal;
+
+OpenEditorsWidget::OpenEditorsWidget()
+{
+ m_ui.setupUi(this);
+ setWindowTitle(tr("Open Documents"));
+ setWindowIcon(QIcon(Constants::ICON_DIR));
+ setFocusProxy(m_ui.editorList);
+ m_ui.editorList->setColumnCount(1);
+ m_ui.editorList->header()->hide();
+ m_ui.editorList->setIndentation(0);
+ m_ui.editorList->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_ui.editorList->setTextElideMode(Qt::ElideMiddle);
+ m_ui.editorList->installEventFilter(this);
+ m_ui.editorList->setFrameStyle(QFrame::NoFrame);
+ EditorManager *em = EditorManager::instance();
+ foreach(IEditor *editor, em->openedEditors()) {
+ registerEditor(editor);
+ }
+ connect(em, SIGNAL(editorOpened(Core::IEditor*)),
+ this, SLOT(registerEditor(Core::IEditor*)));
+ connect(em, SIGNAL(editorsClosed(QList<Core::IEditor*>)),
+ this, SLOT(unregisterEditors(QList<Core::IEditor*>)));
+ connect(em, SIGNAL(editorGroupsChanged()),
+ this, SLOT(updateEditorList()));
+ connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(updateCurrentItem()));
+ connect(m_ui.editorList, SIGNAL(itemActivated(QTreeWidgetItem*, int)),
+ this, SLOT(selectEditor(QTreeWidgetItem*)));
+ updateEditorList();
+}
+
+OpenEditorsWidget::~OpenEditorsWidget()
+{
+
+}
+
+void OpenEditorsWidget::registerEditor(IEditor *editor)
+{
+ connect(editor, SIGNAL(changed()), this, SLOT(updateEditor()));
+ updateEditorList();
+}
+
+void OpenEditorsWidget::unregisterEditors(QList<IEditor *> editors)
+{
+ foreach (IEditor *editor, editors)
+ disconnect(editor, SIGNAL(changed()), this, SLOT(updateEditor()));
+ updateEditorList();
+}
+
+void OpenEditorsWidget::updateEditorList()
+{
+ EditorManager *em = EditorManager::instance();
+ QList<EditorGroup *> groups = em->editorGroups();
+ IEditor *curEditor = em->currentEditor();
+ int oldNum = m_ui.editorList->topLevelItemCount();
+ QTreeWidgetItem *currentItem = 0;
+ int currItemIndex = 0;
+ for (int i = 0; i < groups.count(); ++i) {
+ QTreeWidgetItem *item;
+ if (groups.count() > 1) {
+ if (currItemIndex < oldNum) {
+ item = m_ui.editorList->topLevelItem(currItemIndex);
+ } else {
+ item = new QTreeWidgetItem(QStringList()<<"");
+ m_ui.editorList->addTopLevelItem(item);
+ }
+ currItemIndex++;
+ item->setIcon(0, QIcon());
+ item->setText(0, tr("---Group %1---").arg(i));
+ item->setFlags(0);
+ item->setToolTip(0, "");
+ item->setData(0, Qt::UserRole, QVariant());
+ item->setTextAlignment(0, Qt::AlignLeft);
+ }
+ foreach (IEditor *editor, groups.at(i)->editors()) {
+ if (currItemIndex < oldNum) {
+ item = m_ui.editorList->topLevelItem(currItemIndex);
+ } else {
+ item = new QTreeWidgetItem(QStringList()<<"");
+ m_ui.editorList->addTopLevelItem(item);
+ }
+ currItemIndex++;
+ updateItem(item, editor);
+ if (editor == curEditor)
+ currentItem = item;
+ }
+ }
+ for (int i = oldNum-1; i >= currItemIndex; --i) {
+ delete m_ui.editorList->takeTopLevelItem(i);
+ }
+ updateCurrentItem(currentItem);
+}
+
+void OpenEditorsWidget::updateCurrentItem(QTreeWidgetItem *currentItem)
+{
+ EditorManager *em = EditorManager::instance();
+ IEditor *curEditor = em->currentEditor();
+ m_ui.editorList->clearSelection();
+ if (!currentItem && curEditor) {
+ int count = m_ui.editorList->topLevelItemCount();
+ for (int i = 0; i < count; ++i) {
+ if (m_ui.editorList->topLevelItem(i)->data(0, Qt::UserRole).value<IEditor *>()
+ == curEditor) {
+ currentItem = m_ui.editorList->topLevelItem(i);
+ break;
+ }
+ }
+ }
+ m_ui.editorList->setCurrentItem(currentItem);
+ if (currentItem)
+ m_ui.editorList->scrollTo(m_ui.editorList->currentIndex());
+}
+
+//todo: this is almost duplicated in openeditorswindow
+void OpenEditorsWidget::updateItem(QTreeWidgetItem *item, IEditor *editor)
+{
+ static const QIcon lockedIcon(QLatin1String(":/qworkbench/images/locked.png"));
+ static const QIcon emptyIcon(QLatin1String(":/qworkbench/images/empty14.png"));
+ QString title = editor->displayName();
+ if (editor->file()->isModified())
+ title += tr("*");
+ item->setIcon(0, editor->file()->isReadOnly() ? lockedIcon : emptyIcon);
+ item->setText(0, title);
+ item->setToolTip(0, editor->file()->fileName());
+ item->setData(0, Qt::UserRole, QVariant::fromValue(editor));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ item->setTextAlignment(0, Qt::AlignLeft);
+}
+
+void OpenEditorsWidget::selectEditor(QTreeWidgetItem *item)
+{
+ if (item == 0)
+ item = m_ui.editorList->currentItem();
+ if (item == 0)
+ return;
+ IEditor *editor = item->data(0, Qt::UserRole).value<IEditor*>();
+ EditorManager::instance()->setCurrentEditor(editor);
+}
+
+void OpenEditorsWidget::updateEditor()
+{
+ IEditor *editor = qobject_cast<IEditor *>(sender());
+ Q_ASSERT(editor);
+ int num = m_ui.editorList->topLevelItemCount();
+ for (int i = 0; i < num; ++i) {
+ QTreeWidgetItem *item = m_ui.editorList->topLevelItem(i);
+ if (item->data(0, Qt::UserRole).value<IEditor *>()
+ == editor) {
+ updateItem(item, editor);
+ return;
+ }
+ }
+}
+
+void OpenEditorsWidget::closeEditors()
+{
+ QList<IFile *> selectedFiles;
+ QList<IEditor *> selectedEditors;
+ foreach (QTreeWidgetItem *item, m_ui.editorList->selectedItems()) {
+ selectedEditors.append(item->data(0, Qt::UserRole).value<IEditor *>());
+ selectedFiles.append(item->data(0, Qt::UserRole).value<IEditor *>()->file());
+ }
+ ICore *core = CoreImpl::instance();
+ bool cancelled = false;
+ core->fileManager()->saveModifiedFiles(selectedFiles, &cancelled);
+ if (cancelled)
+ return;
+ core->editorManager()->
+ closeEditors(selectedEditors);
+ updateEditorList();
+}
+
+void OpenEditorsWidget::closeAllEditors()
+{
+ m_ui.editorList->selectAll();
+ closeEditors();
+}
+
+
+bool OpenEditorsWidget::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == m_ui.editorList) {
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ switch (keyEvent->key()) {
+ case Qt::Key_Return:
+ selectEditor(m_ui.editorList->currentItem());
+ return true;
+ case Qt::Key_Delete: //fall through
+ case Qt::Key_Backspace:
+ if (keyEvent->modifiers() == Qt::NoModifier) {
+ closeEditors();
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (event->type() == QEvent::ContextMenu) {
+ QContextMenuEvent *contextMenuEvent = static_cast<QContextMenuEvent *>(event);
+ QMenu menu;
+ menu.addAction(tr("&Select"), this, SLOT(selectEditor()));
+ menu.addAction(tr("&Close"), this, SLOT(closeEditors()));
+ menu.addAction(tr("Close &All"), this, SLOT(closeAllEditors()));
+ if (m_ui.editorList->selectedItems().isEmpty())
+ menu.setEnabled(false);
+ menu.exec(contextMenuEvent->globalPos());
+ return true;
+ }
+ } else if (obj == m_widget) {
+ if (event->type() == QEvent::FocusIn) {
+ QFocusEvent *e = static_cast<QFocusEvent *>(event);
+ if (e->reason() != Qt::MouseFocusReason) {
+ // we should not set the focus in a event filter for a focus event,
+ // so do it when the focus event is processed
+ QTimer::singleShot(0, this, SLOT(putFocusToEditorList()));
+ }
+ }
+ }
+ return false;
+}
+
+void OpenEditorsWidget::putFocusToEditorList()
+{
+ m_ui.editorList->setFocus();
+}
+
+NavigationView OpenEditorsViewFactory::createWidget()
+{
+ NavigationView n;
+ n.widget = new OpenEditorsWidget();
+ return n;
+}
+
+QString OpenEditorsViewFactory::displayName()
+{
+ return "Open Documents";
+}
+
+QKeySequence OpenEditorsViewFactory::activationSequence()
+{
+ return QKeySequence(Qt::ALT + Qt::Key_O);
+}
+
+OpenEditorsViewFactory::OpenEditorsViewFactory()
+{
+
+}
+
+OpenEditorsViewFactory::~OpenEditorsViewFactory()
+{
+
+}
diff --git a/src/plugins/coreplugin/editormanager/openeditorsview.h b/src/plugins/coreplugin/editormanager/openeditorsview.h
new file mode 100644
index 0000000000..d4c20a4a24
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/openeditorsview.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OPENEDITORSVIEW_H
+#define OPENEDITORSVIEW_H
+
+#include "ui_openeditorsview.h"
+
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/inavigationwidgetfactory.h>
+
+#include <QtCore/QList>
+#include <QtGui/QWidget>
+#include <QtGui/QKeySequence>
+#include <QtGui/QAbstractButton>
+#include <QtGui/QTreeWidgetItem>
+
+namespace Core {
+namespace Internal {
+
+class OpenEditorsWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ OpenEditorsWidget();
+ ~OpenEditorsWidget();
+
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private slots:
+ void registerEditor(Core::IEditor *editor);
+ void unregisterEditors(QList<Core::IEditor *> editors);
+ void updateEditorList();
+ void selectEditor(QTreeWidgetItem *item = 0);
+ void updateEditor();
+ void closeEditors();
+ void closeAllEditors();
+ void updateCurrentItem(QTreeWidgetItem *currentItem = 0);
+ void putFocusToEditorList();
+
+private:
+ static void updateItem(QTreeWidgetItem *item, Core::IEditor *editor);
+
+ Ui::OpenEditorsView m_ui;
+ QWidget *m_widget;
+};
+
+class OpenEditorsViewFactory : public Core::INavigationWidgetFactory
+{
+public:
+ OpenEditorsViewFactory();
+ virtual ~OpenEditorsViewFactory();
+ QString displayName();
+ virtual QKeySequence activationSequence();
+ Core::NavigationView createWidget();
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif
diff --git a/src/plugins/coreplugin/editormanager/openeditorsview.ui b/src/plugins/coreplugin/editormanager/openeditorsview.ui
new file mode 100644
index 0000000000..7676ba3967
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/openeditorsview.ui
@@ -0,0 +1,39 @@
+<ui version="4.0" >
+ <class>OpenEditorsView</class>
+ <widget class="QWidget" name="OpenEditorsView" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>263</width>
+ <height>217</height>
+ </rect>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>200</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QTreeWidget" name="editorList" >
+ <property name="uniformRowHeights" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
new file mode 100644
index 0000000000..2e97d444f7
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
@@ -0,0 +1,351 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "openeditorswindow.h"
+#include "editorgroup.h"
+#include "editormanager.h"
+
+#include <QtGui/QHeaderView>
+
+Q_DECLARE_METATYPE(Core::IEditor *)
+
+using namespace Core;
+using namespace Core::Internal;
+
+const int OpenEditorsWindow::WIDTH = 300;
+const int OpenEditorsWindow::HEIGHT = 200;
+const int OpenEditorsWindow::MARGIN = 4;
+
+OpenEditorsWindow::OpenEditorsWindow(QWidget *parent) :
+ QWidget(parent, Qt::Popup),
+ m_editorList(new QTreeWidget(this)),
+ m_mode(HistoryMode),
+ m_current(0)
+{
+ resize(QSize(WIDTH, HEIGHT));
+ m_editorList->setColumnCount(1);
+ m_editorList->header()->hide();
+ m_editorList->setIndentation(0);
+ m_editorList->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_editorList->setSelectionBehavior(QAbstractItemView::SelectItems);
+ m_editorList->setTextElideMode(Qt::ElideMiddle);
+#ifdef Q_WS_MAC
+ m_editorList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+#endif
+ m_editorList->installEventFilter(this);
+ m_editorList->setGeometry(MARGIN, MARGIN, WIDTH-2*MARGIN, HEIGHT-2*MARGIN);
+
+ connect(m_editorList, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
+ this, SLOT(editorClicked(QTreeWidgetItem*)));
+
+ m_autoHide.setSingleShot(true);
+ connect(&m_autoHide, SIGNAL(timeout()), this, SLOT(selectAndHide()));
+ EditorManager *em = EditorManager::instance();
+ connect(em, SIGNAL(editorOpened(Core::IEditor *)),
+ this, SLOT(updateEditorList()));
+ connect(em, SIGNAL(editorsClosed(QList<Core::IEditor *>)),
+ this, SLOT(updateEditorList()));
+ connect(em, SIGNAL(editorGroupsChanged()),
+ this, SLOT(updateEditorList()));
+ connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(updateEditorList()));
+}
+
+void OpenEditorsWindow::selectAndHide()
+{
+ selectEditor(m_editorList->currentItem());
+ setVisible(false);
+}
+
+void OpenEditorsWindow::setVisible(bool visible)
+{
+ QWidget::setVisible(visible);
+ if (visible) {
+ updateEditorList(m_current);
+ m_autoHide.start(600);
+ setFocus();
+ }
+}
+
+bool OpenEditorsWindow::isCentering()
+{
+ if (m_mode == OpenEditorsWindow::HistoryMode || m_editorList->topLevelItemCount() < 3)
+ return false;
+ int internalMargin = m_editorList->viewport()->mapTo(m_editorList, QPoint(0,0)).y();
+ QRect rect0 = m_editorList->visualItemRect(m_editorList->topLevelItem(0));
+ QRect rect1 = m_editorList->visualItemRect(m_editorList->topLevelItem(m_editorList->topLevelItemCount()-1));
+ int height = rect1.y() + rect1.height() - rect0.y();
+ height += 2*internalMargin + 2*MARGIN;
+ if (height > HEIGHT)
+ return true;
+ return false;
+}
+
+void OpenEditorsWindow::setMode(Mode mode)
+{
+ m_mode = mode;
+ updateEditorList(m_current);
+}
+
+bool OpenEditorsWindow::event(QEvent *e) {
+ if (e->type() == QEvent::KeyRelease) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ m_autoHide.stop();
+ if (ke->modifiers() == 0
+ /*HACK this is to overcome some event inconsistencies between platforms*/
+ || (ke->modifiers() == Qt::AltModifier && (ke->key() == Qt::Key_Alt || ke->key() == -1))) {
+ selectAndHide();
+ }
+ }
+ return QWidget::event(e);
+}
+
+bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e)
+{
+ if (obj == m_editorList) {
+ if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->key() == Qt::Key_Escape) {
+ m_current = EditorManager::instance()->currentEditor();
+ updateSelectedEditor();
+ setVisible(false);
+ return true;
+ }
+ if (ke->key() == Qt::Key_Return) {
+ selectEditor(m_editorList->currentItem());
+ return true;
+ }
+ }
+ }
+ return QWidget::eventFilter(obj, e);
+}
+
+void OpenEditorsWindow::focusInEvent(QFocusEvent *)
+{
+ m_editorList->setFocus();
+}
+
+void OpenEditorsWindow::selectUpDown(bool up)
+{
+ int itemCount = m_editorList->topLevelItemCount();
+ if (itemCount < 2)
+ return;
+ int index = m_editorList->indexOfTopLevelItem(m_editorList->currentItem());
+ if (index < 0)
+ return;
+ IEditor *editor = 0;
+ int count = 0;
+ while (!editor && count < itemCount) {
+ if (up) {
+ index--;
+ if (index < 0)
+ index = itemCount-1;
+ } else {
+ index++;
+ if (index >= itemCount)
+ index = 0;
+ }
+ editor = m_editorList->topLevelItem(index)
+ ->data(0, Qt::UserRole).value<IEditor *>();
+ count++;
+ }
+ if (editor)
+ updateEditorList(editor);
+}
+
+void OpenEditorsWindow::selectPreviousEditor()
+{
+ selectUpDown(m_mode == ListMode);
+}
+
+void OpenEditorsWindow::selectNextEditor()
+{
+ selectUpDown(m_mode != ListMode);
+}
+
+void OpenEditorsWindow::updateEditorList(IEditor *editor)
+{
+ if (!editor)
+ editor = EditorManager::instance()->currentEditor();
+ m_current = editor;
+ if (m_mode == ListMode)
+ updateList();
+ else if (m_mode == HistoryMode)
+ updateHistory();
+}
+
+void OpenEditorsWindow::updateHistory()
+{
+ EditorManager *em = EditorManager::instance();
+ QList<IEditor *> history = em->editorHistory();
+ int oldNum = m_editorList->topLevelItemCount();
+ int num = history.count();
+ int common = qMin(oldNum, num);
+ int selectedIndex = -1;
+ QTreeWidgetItem *item;
+ for (int i = 0; i < common; ++i) {
+ item = m_editorList->topLevelItem(i);
+ updateItem(item, history.at(i));
+ if (history.at(i) == m_current)
+ selectedIndex = i;
+ }
+ for (int i = common; i < num; ++i) {
+ item = new QTreeWidgetItem(QStringList() << "");
+ updateItem(item, history.at(i));
+ m_editorList->addTopLevelItem(item);
+ if (history.at(i) == m_current)
+ selectedIndex = i;
+ }
+ for (int i = oldNum-1; i >= common; --i) {
+ delete m_editorList->takeTopLevelItem(i);
+ }
+ if (isCentering())
+ centerOnItem(selectedIndex);
+ updateSelectedEditor();
+}
+
+void OpenEditorsWindow::updateList()
+{
+ EditorManager *em = EditorManager::instance();
+ QList<EditorGroup *> groups = em->editorGroups();
+ int oldNum = m_editorList->topLevelItemCount();
+ int curItem = 0;
+ int selectedIndex = -1;
+ QTreeWidgetItem *item;
+ for (int i = 0; i < groups.count(); ++i) {
+ if (groups.count() > 1) {
+ if (curItem < oldNum) {
+ item = m_editorList->topLevelItem(curItem);
+ } else {
+ item = new QTreeWidgetItem(QStringList()<<"");
+ m_editorList->addTopLevelItem(item);
+ }
+ curItem++;
+ item->setText(0, tr("---Group %1---").arg(i));
+ item->setFlags(0);
+ item->setData(0, Qt::UserRole, QVariant());
+ }
+ foreach (IEditor *editor, groups.at(i)->editors()) {
+ if (curItem < oldNum) {
+ item = m_editorList->topLevelItem(curItem);
+ } else {
+ item = new QTreeWidgetItem(QStringList()<<"");
+ m_editorList->addTopLevelItem(item);
+ }
+ updateItem(item, editor);
+ if (editor == m_current) {
+ m_editorList->setCurrentItem(item);
+ selectedIndex = curItem;
+ }
+ curItem++;
+ }
+ }
+ for (int i = oldNum-1; i >= curItem; --i) {
+ delete m_editorList->takeTopLevelItem(i);
+ }
+ if (isCentering())
+ centerOnItem(selectedIndex);
+ if (m_current == 0 && m_editorList->currentItem())
+ m_editorList->currentItem()->setSelected(false);
+ m_editorList->scrollTo(m_editorList->currentIndex(), QAbstractItemView::PositionAtCenter);
+}
+
+void OpenEditorsWindow::centerOnItem(int selectedIndex)
+{
+ if (selectedIndex >= 0) {
+ QTreeWidgetItem *item;
+ int num = m_editorList->topLevelItemCount();
+ int rotate = selectedIndex-(num-1)/2;
+ for (int i = 0; i < rotate; ++i) {
+ item = m_editorList->takeTopLevelItem(0);
+ m_editorList->addTopLevelItem(item);
+ }
+ rotate = -rotate;
+ for (int i = 0; i < rotate; ++i) {
+ item = m_editorList->takeTopLevelItem(num-1);
+ m_editorList->insertTopLevelItem(0, item);
+ }
+ }
+}
+
+void OpenEditorsWindow::updateItem(QTreeWidgetItem *item, IEditor *editor)
+{
+ static const QIcon lockedIcon(QLatin1String(":/qworkbench/images/locked.png"));
+ static const QIcon emptyIcon(QLatin1String(":/qworkbench/images/empty14.png"));
+
+ QString title = editor->displayName();
+ if (editor->file()->isModified())
+ title += tr("*");
+ item->setIcon(0, editor->file()->isReadOnly() ? lockedIcon : emptyIcon);
+ item->setText(0, title);
+ item->setToolTip(0, editor->file()->fileName());
+ item->setData(0, Qt::UserRole, QVariant::fromValue(editor));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ item->setTextAlignment(0, Qt::AlignLeft);
+}
+
+void OpenEditorsWindow::selectEditor(QTreeWidgetItem *item)
+{
+ IEditor *editor = 0;
+ if (item)
+ editor = item->data(0, Qt::UserRole).value<IEditor*>();
+ EditorManager::instance()->setCurrentEditor(editor);
+}
+
+void OpenEditorsWindow::editorClicked(QTreeWidgetItem *item)
+{
+ selectEditor(item);
+ setFocus();
+}
+
+void OpenEditorsWindow::updateSelectedEditor()
+{
+ if (m_current == 0 && m_editorList->currentItem()) {
+ m_editorList->currentItem()->setSelected(false);
+ return;
+ }
+ int num = m_editorList->topLevelItemCount();
+ for (int i = 0; i < num; ++i) {
+ IEditor *editor = m_editorList->topLevelItem(i)
+ ->data(0, Qt::UserRole).value<IEditor *>();
+ if (editor == m_current) {
+ m_editorList->setCurrentItem(m_editorList->topLevelItem(i));
+ break;
+ }
+ }
+ m_editorList->scrollTo(m_editorList->currentIndex(), QAbstractItemView::PositionAtCenter);
+}
+
+void OpenEditorsWindow::setSelectedEditor(IEditor *editor)
+{
+ updateEditorList(editor);
+}
diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.h b/src/plugins/coreplugin/editormanager/openeditorswindow.h
new file mode 100644
index 0000000000..fcefe42eff
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/openeditorswindow.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OPENEDITORSWINDOW_H
+#define OPENEDITORSWINDOW_H
+
+#include <QtCore/QTimer>
+#include <QtGui/QWidget>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QTreeWidget>
+#include <QtDebug>
+
+namespace Core {
+
+class IEditor;
+
+namespace Internal {
+
+class OpenEditorsWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ enum Mode {ListMode, HistoryMode };
+
+ OpenEditorsWindow(QWidget *parent = 0);
+ ~OpenEditorsWindow() {}
+
+ void setMode(Mode mode);
+ Mode mode() const { return m_mode; }
+
+ bool event(QEvent *e);
+ bool eventFilter(QObject *src, QEvent *e);
+ void focusInEvent(QFocusEvent *);
+ void setVisible(bool visible);
+ void setSelectedEditor(IEditor *editor);
+ void selectNextEditor();
+ void selectPreviousEditor();
+ IEditor *selectedEditor() const { return m_current; }
+
+private slots:
+ void updateEditorList(IEditor *current = 0);
+ void editorClicked(QTreeWidgetItem *item);
+ void selectEditor(QTreeWidgetItem *item);
+ void selectAndHide();
+
+private:
+ static const int WIDTH;
+ static const int HEIGHT;
+ static const int MARGIN;
+
+ static void updateItem(QTreeWidgetItem *item, IEditor *editor);
+ void updateList();
+ void updateHistory();
+ void updateSelectedEditor();
+ bool isCentering();
+ void centerOnItem(int selectedIndex);
+ void selectUpDown(bool up);
+
+ QTreeWidget *m_editorList;
+ Mode m_mode;
+ QTimer m_autoHide;
+ IEditor *m_current;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // OPENEDITORSWINDOW_H
diff --git a/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp b/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp
new file mode 100644
index 0000000000..ffb0b14743
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp
@@ -0,0 +1,375 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "stackededitorgroup.h"
+#include "editormanager.h"
+#include "coreimpl.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QMimeData>
+#include <QtGui/QComboBox>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleOption>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QApplication>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+#include <QtGui/QLabel>
+#include <QtGui/QStackedWidget>
+#include <QtDebug>
+#ifdef Q_WS_MAC
+#include <qmacstyle_mac.h>
+#endif
+
+Q_DECLARE_METATYPE(Core::IEditor *)
+
+using namespace Core;
+using namespace Core::Internal;
+
+StackedEditorGroup::StackedEditorGroup(QWidget *parent) :
+ EditorGroup(parent),
+ m_toplevel(new QWidget),
+ m_toolBar(new QWidget),
+ m_container(new QStackedWidget(this)),
+ m_editorList(new QComboBox),
+ m_closeButton(new QToolButton),
+ m_lockButton(new QToolButton),
+ m_defaultToolBar(new QToolBar(this)),
+ m_infoWidget(new QFrame(this)),
+ m_editorForInfoWidget(0)
+{
+ QVBoxLayout *tl = new QVBoxLayout(m_toplevel);
+ tl->setSpacing(0);
+ tl->setMargin(0);
+ {
+ m_editorList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ m_editorList->setMinimumContentsLength(20);
+ m_proxyModel.setSourceModel(model());
+ m_proxyModel.sort(0);
+ m_editorList->setModel(&m_proxyModel);
+ m_editorList->setMaxVisibleItems(40);
+
+ QToolBar *editorListToolBar = new QToolBar;
+
+ editorListToolBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
+ editorListToolBar->addWidget(m_editorList);
+
+ m_defaultToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_activeToolBar = m_defaultToolBar;
+
+ QHBoxLayout *toolBarLayout = new QHBoxLayout;
+ toolBarLayout->setMargin(0);
+ toolBarLayout->setSpacing(0);
+ toolBarLayout->addWidget(m_defaultToolBar);
+ m_toolBar->setLayout(toolBarLayout);
+
+ m_lockButton->setAutoRaise(true);
+ m_lockButton->setProperty("type", QLatin1String("dockbutton"));
+
+ m_closeButton->setAutoRaise(true);
+ m_closeButton->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+ m_closeButton->setProperty("type", QLatin1String("dockbutton"));
+
+ QToolBar *rightToolBar = new QToolBar;
+ rightToolBar->setLayoutDirection(Qt::RightToLeft);
+ rightToolBar->addWidget(m_closeButton);
+ rightToolBar->addWidget(m_lockButton);
+
+ QHBoxLayout *toplayout = new QHBoxLayout;
+ toplayout->setSpacing(0);
+ toplayout->setMargin(0);
+ toplayout->addWidget(editorListToolBar);
+ toplayout->addWidget(m_toolBar, 1); // Custom toolbar stretches
+ toplayout->addWidget(rightToolBar);
+
+ QWidget *top = new QWidget;
+ QVBoxLayout *vlayout = new QVBoxLayout(top);
+ vlayout->setSpacing(0);
+ vlayout->setMargin(0);
+ vlayout->addLayout(toplayout);
+ tl->addWidget(top);
+
+ connect(m_editorList, SIGNAL(currentIndexChanged(int)), this, SLOT(listSelectionChanged(int)));
+ connect(m_lockButton, SIGNAL(clicked()), this, SLOT(makeEditorWritable()));
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(sendCloseRequest()));
+ }
+ {
+ m_infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ m_infoWidget->setLineWidth(1);
+ m_infoWidget->setForegroundRole(QPalette::ToolTipText);
+ m_infoWidget->setBackgroundRole(QPalette::ToolTipBase);
+ m_infoWidget->setAutoFillBackground(true);
+
+
+ QHBoxLayout *hbox = new QHBoxLayout(m_infoWidget);
+ hbox->setMargin(2);
+ m_infoWidgetLabel = new QLabel("Placeholder");
+ m_infoWidgetLabel->setForegroundRole(QPalette::ToolTipText);
+ hbox->addWidget(m_infoWidgetLabel);
+ hbox->addStretch(1);
+
+ m_infoWidgetButton = new QToolButton;
+ m_infoWidgetButton->setText(tr("Placeholder"));
+ hbox->addWidget(m_infoWidgetButton);
+
+ QToolButton *closeButton = new QToolButton;
+ closeButton->setAutoRaise(true);
+ closeButton->setIcon(QIcon(":/qworkbench/images/clear.png"));
+ closeButton->setToolTip(tr("Close"));
+ connect(closeButton, SIGNAL(clicked()), m_infoWidget, SLOT(hide()));
+
+ hbox->addWidget(closeButton);
+
+
+ tl->addWidget(m_infoWidget);
+ }
+ tl->addWidget(m_container);
+
+ QHBoxLayout *l = new QHBoxLayout;
+ l->setSpacing(0);
+ l->setMargin(0);
+ l->addWidget(m_toplevel);
+ setLayout(l);
+
+ m_toplevel->setVisible(false);
+}
+
+void StackedEditorGroup::showEditorInfoBar(const QString &kind,
+ const QString &infoText,
+ const QString &buttonText,
+ QObject *object, const char *member)
+{
+ m_infoWidgetKind = kind;
+ m_infoWidgetLabel->setText(infoText);
+ m_infoWidgetButton->setText(buttonText);
+ m_infoWidgetButton->disconnect();
+ if (object && member)
+ connect(m_infoWidgetButton, SIGNAL(clicked()), object, member);
+ m_infoWidget->setVisible(true);
+ m_editorForInfoWidget = currentEditor();
+}
+
+void StackedEditorGroup::hideEditorInfoBar(const QString &kind)
+{
+ if (kind == m_infoWidgetKind)
+ m_infoWidget->setVisible(false);
+}
+
+
+StackedEditorGroup::~StackedEditorGroup()
+{
+}
+
+void StackedEditorGroup::focusInEvent(QFocusEvent *e)
+{
+ if (m_container->count() > 0) {
+ setEditorFocus(m_container->currentIndex());
+ } else {
+ EditorGroup::focusInEvent(e);
+ }
+}
+
+void StackedEditorGroup::setEditorFocus(int index)
+{
+ QWidget *w = m_container->widget(index);
+ w->setFocus();
+}
+
+void StackedEditorGroup::addEditor(IEditor *editor)
+{
+ insertEditor(editorCount(), editor);
+}
+
+void StackedEditorGroup::insertEditor(int index, IEditor *editor)
+{
+ EditorGroup::insertEditor(index, editor);
+ if (m_container->indexOf(editor->widget()) != -1)
+ return;
+
+ m_container->insertWidget(index, editor->widget());
+ m_widgetEditorMap.insert(editor->widget(), editor);
+
+ QToolBar *toolBar = editor->toolBar();
+ if (toolBar)
+ m_toolBar->layout()->addWidget(toolBar);
+ connect(editor, SIGNAL(changed()), this, SLOT(updateEditorStatus()));
+
+ updateEditorStatus(editor);
+ updateToolBar(editor);
+
+ emit editorAdded(editor);
+}
+
+void StackedEditorGroup::sendCloseRequest()
+{
+ emit closeRequested(currentEditor());
+}
+
+void StackedEditorGroup::removeEditor(IEditor *editor)
+{
+ Q_ASSERT(editor);
+ EditorGroup::removeEditor(editor);
+ const int index = m_container->indexOf(editor->widget());
+ if (index != -1) {
+ m_container->removeWidget(editor->widget());
+ m_widgetEditorMap.remove(editor->widget());
+ editor->widget()->setParent(0);
+ disconnect(editor, SIGNAL(changed()), this, SLOT(updateEditorStatus()));
+ QToolBar *toolBar = editor->toolBar();
+ if (toolBar != 0) {
+ if (m_activeToolBar == toolBar) {
+ m_activeToolBar = m_defaultToolBar;
+ m_activeToolBar->setVisible(true);
+ }
+ m_toolBar->layout()->removeWidget(toolBar);
+ toolBar->setVisible(false);
+ toolBar->setParent(0);
+ }
+ if (m_container->count() == 0) {
+ m_toplevel->setVisible(false);
+ setFocus();
+ }
+ emit editorRemoved(editor);
+ }
+}
+
+IEditor *StackedEditorGroup::currentEditor() const
+{
+ if (m_container->count() > 0)
+ return m_widgetEditorMap.value(m_container->currentWidget());
+ return 0;
+}
+
+void StackedEditorGroup::setCurrentEditor(IEditor *editor)
+{
+ if (!editor || m_container->count() <= 0
+ || m_container->indexOf(editor->widget()) == -1)
+ return;
+ m_toplevel->setVisible(true);
+ const int idx = m_container->indexOf(editor->widget());
+ Q_ASSERT(idx >= 0);
+ if (m_container->currentIndex() != idx) {
+ m_container->setCurrentIndex(idx);
+
+ const bool block = m_editorList->blockSignals(true);
+ m_editorList->setCurrentIndex(indexOf(editor));
+ m_editorList->blockSignals(block);
+
+ updateEditorStatus(editor);
+ updateToolBar(editor);
+ }
+ setEditorFocus(idx);
+ if (editor != m_editorForInfoWidget) {
+ m_infoWidget->hide();
+ m_editorForInfoWidget = 0;
+ }
+}
+
+void StackedEditorGroup::updateEditorStatus(IEditor *editor) {
+ if (!editor)
+ editor = qobject_cast<IEditor *>(sender());
+ Q_ASSERT(editor);
+
+ static const QIcon lockedIcon(QLatin1String(":/qworkbench/images/locked.png"));
+ static const QIcon unlockedIcon(QLatin1String(":/qworkbench/images/unlocked.png"));
+
+ if (editor->file()->isReadOnly()) {
+ m_lockButton->setIcon(lockedIcon);
+ m_lockButton->setEnabled(!editor->file()->fileName().isEmpty());
+ m_lockButton->setToolTip(tr("Make writable"));
+ } else {
+ m_lockButton->setIcon(unlockedIcon);
+ m_lockButton->setEnabled(false);
+ m_lockButton->setToolTip(tr("File is writable"));
+ }
+ if (currentEditor() == editor)
+ m_editorList->setToolTip(model()->data(model()->indexOf(editor), Qt::ToolTipRole).toString());
+ model()->emitDataChanged(editor);
+}
+
+void StackedEditorGroup::updateToolBar(IEditor *editor)
+{
+ QToolBar *toolBar = editor->toolBar();
+ if (!toolBar)
+ toolBar = m_defaultToolBar;
+ if (m_activeToolBar == toolBar)
+ return;
+ m_activeToolBar->setVisible(false);
+ toolBar->setVisible(true);
+ m_activeToolBar = toolBar;
+}
+
+int StackedEditorGroup::editorCount() const
+{
+ return model()->editors().count();
+}
+
+QList<IEditor *> StackedEditorGroup::editors() const
+{
+ QAbstractItemModel *model = m_editorList->model();
+ QList<IEditor*> output;
+ int rows = model->rowCount();
+ for (int i = 0; i < rows; ++i)
+ output.append(model->data(model->index(i, 0), Qt::UserRole).value<IEditor*>());
+ return output;
+}
+
+QList<IEditor *> StackedEditorGroup::editorsInNaturalOrder() const
+{
+ return model()->editors();
+}
+
+void StackedEditorGroup::makeEditorWritable()
+{
+ CoreImpl::instance()->editorManager()->makeEditorWritable(currentEditor());
+}
+
+void StackedEditorGroup::listSelectionChanged(int index)
+{
+ QAbstractItemModel *model = m_editorList->model();
+ setCurrentEditor(model->data(model->index(index, 0), Qt::UserRole).value<IEditor*>());
+}
+
+int StackedEditorGroup::indexOf(IEditor *editor)
+{
+ QAbstractItemModel *model = m_editorList->model();
+ int rows = model->rowCount();
+ for (int i = 0; i < rows; ++i) {
+ if (editor == model->data(model->index(i, 0), Qt::UserRole).value<IEditor*>())
+ return i;
+ }
+ Q_ASSERT(false);
+ return 0;
+}
diff --git a/src/plugins/coreplugin/editormanager/stackededitorgroup.h b/src/plugins/coreplugin/editormanager/stackededitorgroup.h
new file mode 100644
index 0000000000..5b7cfd5298
--- /dev/null
+++ b/src/plugins/coreplugin/editormanager/stackededitorgroup.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef STACKEDEDITORGROUP_H
+#define STACKEDEDITORGROUP_H
+
+#include "editorgroup.h"
+
+#include <QtCore/QMap>
+#include <QtGui/QSortFilterProxyModel>
+
+QT_BEGIN_NAMESPACE
+class QComboBox;
+class QToolBar;
+class QToolButton;
+class QLabel;
+class QStackedWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Internal {
+
+class StackedEditorGroup : public EditorGroup
+{
+ Q_OBJECT
+
+public:
+ StackedEditorGroup(QWidget *parent = 0);
+ virtual ~StackedEditorGroup();
+
+ //EditorGroup
+ int editorCount() const;
+ void addEditor(IEditor *editor);
+ void insertEditor(int i, IEditor *editor);
+ void removeEditor(IEditor *editor);
+ IEditor *currentEditor() const;
+ void setCurrentEditor(IEditor *editor);
+ QList<IEditor *> editors() const;
+ void showEditorInfoBar(const QString &kind,
+ const QString &infoText,
+ const QString &buttonText,
+ QObject *object, const char *member);
+ void hideEditorInfoBar(const QString &kind);
+
+ void focusInEvent(QFocusEvent *e);
+
+protected:
+ QList<IEditor *> editorsInNaturalOrder() const;
+
+private slots:
+ void sendCloseRequest();
+ void updateEditorStatus(Core::IEditor *editor = 0);
+ void setEditorFocus(int index);
+ void makeEditorWritable();
+ void listSelectionChanged(int index);
+
+private:
+ void updateToolBar(IEditor *editor);
+ int indexOf(IEditor *editor);
+ void checkProjectLoaded(IEditor *editor);
+
+ QWidget *m_toplevel;
+ QWidget *m_toolBar;
+ QToolBar *m_activeToolBar;
+ QStackedWidget *m_container;
+ QComboBox *m_editorList;
+ QToolButton *m_closeButton;
+ QToolButton *m_lockButton;
+ QToolBar *m_defaultToolBar;
+ QString m_infoWidgetKind;
+ QFrame *m_infoWidget;
+ QLabel *m_infoWidgetLabel;
+ QToolButton *m_infoWidgetButton;
+ IEditor *m_editorForInfoWidget;
+ QSortFilterProxyModel m_proxyModel;
+ QMap<QWidget *, IEditor *> m_widgetEditorMap;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // STACKEDEDITORGROUP_H
diff --git a/src/plugins/coreplugin/fancyactionbar.cpp b/src/plugins/coreplugin/fancyactionbar.cpp
new file mode 100644
index 0000000000..08ad842eed
--- /dev/null
+++ b/src/plugins/coreplugin/fancyactionbar.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fancyactionbar.h"
+
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QPicture>
+#include <QtGui/QVBoxLayout>
+#include <QtSvg/QSvgRenderer>
+
+using namespace Core;
+using namespace Internal;
+
+static const char* const svgIdButtonBase = "ButtonBase";
+static const char* const svgIdButtonNormalBase = "ButtonNormalBase";
+static const char* const svgIdButtonNormalOverlay = "ButtonNormalOverlay";
+static const char* const svgIdButtonPressedBase = "ButtonPressedBase";
+static const char* const svgIdButtonPressedOverlay = "ButtonPressedOverlay";
+static const char* const svgIdButtonDisabledOverlay = "ButtonDisabledOverlay";
+static const char* const svgIdButtonHoverOverlay = "ButtonHoverOverlay";
+
+static const char* const elementsSvgIds[] = {
+ svgIdButtonBase,
+ svgIdButtonNormalBase,
+ svgIdButtonNormalOverlay,
+ svgIdButtonPressedBase,
+ svgIdButtonPressedOverlay,
+ svgIdButtonDisabledOverlay,
+ svgIdButtonHoverOverlay
+};
+
+const QMap<QString, QPicture> &buttonElementsMap()
+{
+ static QMap<QString, QPicture> result;
+ if (result.isEmpty()) {
+ QSvgRenderer renderer(QLatin1String(":/fancyactionbar/images/fancytoolbutton.svg"));
+ for (size_t i = 0; i < sizeof(elementsSvgIds)/sizeof(elementsSvgIds[0]); i++) {
+ QString elementId(elementsSvgIds[i]);
+ QPicture elementPicture;
+ QPainter elementPainter(&elementPicture);
+ renderer.render(&elementPainter, elementId);
+ result.insert(elementId, elementPicture);
+ }
+ }
+ return result;
+}
+
+FancyToolButton::FancyToolButton(QWidget *parent)
+ : QToolButton(parent)
+ , m_buttonElements(buttonElementsMap())
+{
+ setAttribute(Qt::WA_Hover, true);
+}
+
+void FancyToolButton::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+ QPainter p(this);
+ p.drawPicture(0, 0, m_buttonElements.value(svgIdButtonBase));
+ p.drawPicture(0, 0, m_buttonElements.value(isDown() ? svgIdButtonPressedBase : svgIdButtonNormalBase));
+#ifndef Q_WS_MAC // Mac UI's dont usually do hover
+ if (underMouse() && isEnabled())
+ p.drawPicture(0, 0, m_buttonElements.value(svgIdButtonHoverOverlay));
+#endif
+ if (!icon().isNull()) {
+ icon().paint(&p, rect());
+ } else {
+ const int margin = 4;
+ p.drawText(rect().adjusted(margin, margin, -margin, -margin), Qt::AlignCenter | Qt::TextWordWrap, text());
+ }
+ if (!isEnabled())
+ p.drawPicture(0, 0, m_buttonElements.value(svgIdButtonDisabledOverlay));
+ p.drawPicture(0, 0, m_buttonElements.value(isDown() ? svgIdButtonPressedOverlay : svgIdButtonNormalOverlay));
+}
+
+void FancyActionBar::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+}
+
+QSize FancyToolButton::sizeHint() const
+{
+ return m_buttonElements.value(svgIdButtonBase).boundingRect().size();
+}
+
+FancyActionBar::FancyActionBar(QWidget *parent)
+ : QWidget(parent)
+{
+ m_actionsLayout = new QVBoxLayout;
+
+ QHBoxLayout *centeringLayout = new QHBoxLayout;
+ centeringLayout->addStretch();
+ centeringLayout->addLayout(m_actionsLayout);
+ centeringLayout->addStretch();
+ setLayout(centeringLayout);
+}
+
+void FancyActionBar::insertAction(int index, QAction *action, QMenu *menu)
+{
+ FancyToolButton *toolButton = new FancyToolButton(this);
+ toolButton->setDefaultAction(action);
+ if (menu) {
+ toolButton->setMenu(menu);
+ toolButton->setPopupMode(QToolButton::DelayedPopup);
+ }
+ m_actionsLayout->insertWidget(index, toolButton);
+}
diff --git a/src/plugins/coreplugin/fancyactionbar.h b/src/plugins/coreplugin/fancyactionbar.h
new file mode 100644
index 0000000000..701e834ad6
--- /dev/null
+++ b/src/plugins/coreplugin/fancyactionbar.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FANCYACTIONBAR_H
+#define FANCYACTIONBAR_H
+
+#include <QtCore/QMap>
+#include <QtGui/QToolButton>
+
+QT_BEGIN_NAMESPACE
+class QMenu;
+class QVBoxLayout;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Internal {
+
+class FancyToolButton : public QToolButton
+{
+public:
+ FancyToolButton(QWidget *parent = 0);
+
+ void paintEvent(QPaintEvent *event);
+ QSize sizeHint() const;
+
+private:
+ const QMap<QString, QPicture> &m_buttonElements;
+};
+
+class FancyActionBar : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FancyActionBar(QWidget *parent = 0);
+
+ void paintEvent(QPaintEvent *event);
+ void insertAction(int index, QAction *action, QMenu *menu = 0);
+
+private:
+ QVBoxLayout *m_actionsLayout;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // FANCYACTIONBAR_H
diff --git a/src/plugins/coreplugin/fancyactionbar.qrc b/src/plugins/coreplugin/fancyactionbar.qrc
new file mode 100644
index 0000000000..e54a3c578c
--- /dev/null
+++ b/src/plugins/coreplugin/fancyactionbar.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/fancyactionbar" >
+ <file>images/fancytoolbutton.svg</file>
+ <file>images/mode_Debug.png</file>
+ <file>images/mode_Edit.png</file>
+ <file>images/mode_Output.png</file>
+ <file>images/mode_Project.png</file>
+ <file>images/mode_Reference.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/coreplugin/fancytabwidget.cpp b/src/plugins/coreplugin/fancytabwidget.cpp
new file mode 100644
index 0000000000..ed57c27b92
--- /dev/null
+++ b/src/plugins/coreplugin/fancytabwidget.cpp
@@ -0,0 +1,373 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fancytabwidget.h"
+#include "stylehelper.h"
+
+#include <QDebug>
+
+#include <QtGui/QColorDialog>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QWindowsStyle>
+#include <QtGui/QPainter>
+#include <QtGui/QSplitter>
+#include <QtGui/QStackedLayout>
+#include <QtGui/QStatusBar>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+
+using namespace Core;
+using namespace Internal;
+
+const int FancyTabBar::m_rounding = 22;
+const int FancyTabBar::m_textPadding = 4;
+
+FancyTabBar::FancyTabBar(QWidget *parent)
+ : QTabBar(parent)
+{
+ setStyle(new QWindowsStyle);
+ setDrawBase(false);
+ setElideMode(Qt::ElideNone);
+ setMinimumWidth(qMax(2 * m_rounding, 40));
+ setAttribute(Qt::WA_Hover, true);
+ setFocusPolicy(Qt::NoFocus);
+ m_hoverControl.setFrameRange(0, 20);
+ m_hoverControl.setDuration(130);
+ m_hoverControl.setCurveShape(QTimeLine::EaseInCurve);
+ connect(&m_hoverControl, SIGNAL(frameChanged(int)), this, SLOT(updateHover()));
+ setMouseTracking(true); // Needed for hover events
+ setExpanding(false);
+}
+
+FancyTabBar::~FancyTabBar()
+{
+ delete style();
+}
+
+QSize FancyTabBar::tabSizeHint(int index) const
+{
+ QFont boldFont(font());
+ boldFont.setPointSizeF(StyleHelper::sidebarFontSize());
+ boldFont.setBold(true);
+ QFontMetrics fm(boldFont);
+ int spacing = 6;
+ int width = 60 + spacing + 2;
+ return QSize(width, tabIcon(index).actualSize(QSize(64, 64)).height() + spacing + fm.height());
+}
+
+void FancyTabBar::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+ QPainter p(this);
+
+ for (int i = 0; i < count(); ++i)
+ if (i != currentIndex())
+ paintTab(&p, i);
+
+ // paint active tab last, since it overlaps the neighbors
+ paintTab(&p, currentIndex());
+
+
+}
+
+// Handle hover events for mouse fade ins
+void FancyTabBar::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!m_hoverRect.contains(e->pos())) {
+ for (int i = 0; i < count(); ++i) {
+ QRect area = tabRect(i);
+ if (area.contains(e->pos())) {
+ QRect oldHoverRect = m_hoverRect;
+ m_hoverRect = area;
+ update(oldHoverRect);
+ m_hoverControl.stop();
+ m_hoverControl.start();
+ break;
+ }
+ }
+ }
+}
+
+void FancyTabBar::updateHover()
+{
+ update(m_hoverRect);
+}
+
+// Resets hover animation on mouse enter
+void FancyTabBar::enterEvent(QEvent *e)
+{
+ Q_UNUSED(e);
+ m_hoverRect = QRect();
+}
+
+// Resets hover animation on mouse enter
+void FancyTabBar::leaveEvent(QEvent *e)
+{
+ Q_UNUSED(e);
+
+ m_hoverControl.stop();
+ m_hoverControl.start();
+}
+
+void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
+{
+ QStyleOptionTabV2 tab;
+ initStyleOption(&tab, tabIndex);
+ QRect rect = tab.rect;
+ painter->save();
+
+
+ bool selected = tab.state & QStyle::State_Selected;
+ bool hover = tab.state & QStyle::State_MouseOver;
+
+#ifdef Q_WS_MAC
+ hover = false; // Dont hover on Mac
+#endif
+
+ QColor background = QColor(0, 0, 0, 10);
+ QColor hoverColor;
+
+ if (hover) {
+ hoverColor = QColor(255, 255, 255, m_hoverControl.currentFrame()*2);
+ }
+
+ QColor light = QColor(255, 255, 255, 40);
+ QColor dark = QColor(0, 0, 0, 60);
+
+ if (selected) {
+ QLinearGradient selectedGradient(rect.topLeft(), QPoint(rect.center().x(), rect.bottom()));
+ selectedGradient.setColorAt(0, Qt::white);
+ selectedGradient.setColorAt(0.3, Qt::white);
+ selectedGradient.setColorAt(0.7, QColor(230, 230, 230));
+
+ painter->fillRect(rect, selectedGradient);
+ painter->setPen(QColor(200, 200, 200));
+ painter->drawLine(rect.topLeft(), rect.topRight());
+ painter->setPen(QColor(150, 160, 200));
+ painter->drawLine(rect.bottomLeft(), rect.bottomRight());
+ } else {
+ painter->fillRect(tab.rect, background);
+ if (hover)
+ painter->fillRect(tab.rect, hoverColor);
+ painter->setPen(QPen(light, 0));
+ painter->drawLine(rect.topLeft(), rect.topRight());
+ painter->setPen(QPen(dark, 0));
+ painter->drawLine(rect.bottomLeft(), rect.bottomRight());
+ }
+
+ QString tabText(tab.text);
+ QRect tabTextRect(tab.rect);
+ QRect tabIconRect(tab.rect);
+ QFont boldFont(painter->font());
+ boldFont.setPointSizeF(StyleHelper::sidebarFontSize());
+ boldFont.setBold(true);
+ painter->setFont(boldFont);
+ painter->setPen(selected ? StyleHelper::panelTextColor() : QColor(30, 30, 30, 80));
+ int textFlags = Qt::AlignCenter | Qt::AlignBottom | Qt::ElideRight | Qt::TextWordWrap;
+ painter->drawText(tabTextRect, textFlags, tabText);
+ painter->setPen(selected ? QColor(60, 60, 60) : StyleHelper::panelTextColor());
+ int textHeight = painter->fontMetrics().boundingRect(QRect(0, 0, width(), height()), Qt::TextWordWrap, tabText).height();
+ tabIconRect.adjust(0, 4, 0, -textHeight);
+ style()->drawItemPixmap(painter, tabIconRect, Qt::AlignCenter | Qt::AlignVCenter,
+ tab.icon.pixmap(QSize(64, 64)));
+ painter->translate(0, -1);
+ painter->drawText(tabTextRect, textFlags, tabText);
+ painter->restore();
+}
+
+void FancyTabBar::tabInserted(int index)
+{
+ Q_UNUSED(index)
+}
+
+void FancyTabBar::tabRemoved(int index)
+{
+ Q_UNUSED(index)
+}
+
+//////
+// FancyColorButton
+//////
+
+class FancyColorButton : public QWidget
+{
+public:
+ FancyColorButton(QWidget *parent)
+ : m_parent(parent)
+ {
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ }
+
+ void mousePressEvent(QMouseEvent *ev)
+ {
+ if (ev->modifiers() & Qt::ShiftModifier)
+ StyleHelper::setBaseColor(QColorDialog::getColor(StyleHelper::baseColor(), m_parent));
+ }
+private:
+ QWidget *m_parent;
+};
+
+//////
+// FancyTabWidget
+//////
+
+FancyTabWidget::FancyTabWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ m_tabBar = new FancyTabBar(this);
+ m_tabBar->setShape(QTabBar::RoundedEast);
+ m_tabBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ m_tabBar->setUsesScrollButtons(false);
+
+ m_selectionWidget = new QWidget(this);
+ QVBoxLayout *selectionLayout = new QVBoxLayout;
+ selectionLayout->setSpacing(0);
+ selectionLayout->setMargin(0);
+
+ QToolBar *bar = new QToolBar;
+ bar->addWidget(new FancyColorButton(this));
+ bar->setFixedHeight(StyleHelper::navigationWidgetHeight());
+ selectionLayout->addWidget(bar);
+
+ selectionLayout->addWidget(m_tabBar, 1);
+ m_selectionWidget->setLayout(selectionLayout);
+ m_selectionWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
+
+ m_cornerWidgetContainer = new QWidget(this);
+ m_cornerWidgetContainer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
+ m_cornerWidgetContainer->setAutoFillBackground(false);
+
+ QVBoxLayout *cornerWidgetLayout = new QVBoxLayout;
+ cornerWidgetLayout->setSpacing(0);
+ cornerWidgetLayout->setMargin(0);
+ cornerWidgetLayout->addStretch();
+ m_cornerWidgetContainer->setLayout(cornerWidgetLayout);
+
+ selectionLayout->addWidget(m_cornerWidgetContainer, 0);
+
+ m_modesStack = new QStackedLayout;
+ m_statusBar = new QStatusBar;
+ m_statusBar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->setMargin(0);
+ vlayout->setSpacing(0);
+ vlayout->addLayout(m_modesStack);
+ vlayout->addWidget(m_statusBar);
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->setMargin(0);
+ layout->setSpacing(1);
+ layout->addWidget(m_selectionWidget);
+ layout->addLayout(vlayout);
+ setLayout(layout);
+
+ connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(showWidget(int)));
+}
+
+void FancyTabWidget::insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label)
+{
+ m_modesStack->insertWidget(index, tab);
+ m_tabBar->insertTab(index, icon, label);
+}
+
+void FancyTabWidget::removeTab(int index)
+{
+ m_modesStack->removeWidget(m_modesStack->widget(index));
+ m_tabBar->removeTab(index);
+}
+
+void FancyTabWidget::setBackgroundBrush(const QBrush &brush)
+{
+ QPalette pal = m_tabBar->palette();
+ pal.setBrush(QPalette::Mid, brush);
+ m_tabBar->setPalette(pal);
+ pal = m_cornerWidgetContainer->palette();
+ pal.setBrush(QPalette::Mid, brush);
+ m_cornerWidgetContainer->setPalette(pal);
+}
+
+void FancyTabWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+ QPainter p(this);
+
+ QRect rect = m_selectionWidget->rect().adjusted(0, 0, 1, 0);
+ StyleHelper::verticalGradient(&p, rect, rect);
+ p.setPen(StyleHelper::borderColor());
+ p.drawLine(rect.topRight(), rect.bottomRight());
+}
+
+void FancyTabWidget::insertCornerWidget(int pos, QWidget *widget)
+{
+ QVBoxLayout *layout = static_cast<QVBoxLayout *>(m_cornerWidgetContainer->layout());
+ layout->insertWidget(pos, widget);
+}
+
+int FancyTabWidget::cornerWidgetCount() const
+{
+ return m_cornerWidgetContainer->layout()->count();
+}
+
+void FancyTabWidget::addCornerWidget(QWidget *widget)
+{
+ m_cornerWidgetContainer->layout()->addWidget(widget);
+}
+
+int FancyTabWidget::currentIndex() const
+{
+ return m_tabBar->currentIndex();
+}
+
+QStatusBar *FancyTabWidget::statusBar() const
+{
+ return m_statusBar;
+}
+
+void FancyTabWidget::setCurrentIndex(int index)
+{
+ m_tabBar->setCurrentIndex(index);
+}
+
+void FancyTabWidget::showWidget(int index)
+{
+ emit currentAboutToShow(index);
+ m_modesStack->setCurrentIndex(index);
+ emit currentChanged(index);
+}
+
+void FancyTabWidget::setTabToolTip(int index, const QString &toolTip)
+{
+ m_tabBar->setTabToolTip(index, toolTip);
+}
diff --git a/src/plugins/coreplugin/fancytabwidget.h b/src/plugins/coreplugin/fancytabwidget.h
new file mode 100644
index 0000000000..19fd173110
--- /dev/null
+++ b/src/plugins/coreplugin/fancytabwidget.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FANCYTABWIDGET_H
+#define FANCYTABWIDGET_H
+
+#include <QtGui/QPushButton>
+#include <QtGui/QTabBar>
+#include <QtGui/QStyleOptionTabV2>
+#include <QtCore/QTimeLine>
+
+QT_BEGIN_NAMESPACE
+class QPainter;
+class QStackedLayout;
+class QStatusBar;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Internal {
+
+class FancyTabBar : public QTabBar
+{
+ Q_OBJECT
+
+public:
+ FancyTabBar(QWidget *parent = 0);
+ ~FancyTabBar();
+
+ QSize tabSizeHint(int index) const;
+ void paintEvent(QPaintEvent *event);
+ void paintTab(QPainter *painter, int tabIndex) const;
+ void mouseMoveEvent(QMouseEvent *);
+ void enterEvent(QEvent *);
+ void leaveEvent(QEvent *);
+ void tabInserted(int index);
+ void tabRemoved(int index);
+
+public slots:
+ void updateHover();
+
+private:
+ static const int m_rounding;
+ static const int m_textPadding;
+ QTimeLine m_hoverControl;
+ QRect m_hoverRect;
+};
+
+class FancyTabWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FancyTabWidget(QWidget *parent = 0);
+
+ void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label);
+ void removeTab(int index);
+ void setBackgroundBrush(const QBrush &brush);
+ void addCornerWidget(QWidget *widget);
+ void insertCornerWidget(int pos, QWidget *widget);
+ int cornerWidgetCount() const;
+ void setTabToolTip(int index, const QString &toolTip);
+
+ void paintEvent(QPaintEvent *event);
+
+ int currentIndex() const;
+ QStatusBar *statusBar() const;
+
+signals:
+ void currentAboutToShow(int index);
+ void currentChanged(int index);
+
+public slots:
+ void setCurrentIndex(int index);
+
+private slots:
+ void showWidget(int index);
+
+private:
+ FancyTabBar *m_tabBar;
+ QWidget *m_cornerWidgetContainer;
+ QStackedLayout *m_modesStack;
+ QWidget *m_selectionWidget;
+ QStatusBar *m_statusBar;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif
diff --git a/src/plugins/coreplugin/fileiconprovider.cpp b/src/plugins/coreplugin/fileiconprovider.cpp
new file mode 100644
index 0000000000..8e01ecbb8d
--- /dev/null
+++ b/src/plugins/coreplugin/fileiconprovider.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fileiconprovider.h"
+
+using namespace Core;
+
+/*!
+ \class FileIconProvider
+
+ Provides icons based on file suffixes.
+
+ The class is a singleton: It's instance can be accessed via the static instance() method.
+ Plugins can register custom icons via registerIconSuffix(), and retrieve icons via the icon()
+ method.
+ */
+
+FileIconProvider *FileIconProvider::m_instance = 0;
+
+FileIconProvider::FileIconProvider():
+ m_unknownFileIcon(QLatin1String(":/qworkbench/images/unknownfile.png"))
+{
+}
+
+FileIconProvider::~FileIconProvider()
+{
+ m_instance = 0;
+}
+
+/*!
+ Returns the icon associated with the file suffix in fileInfo. If there is none,
+ the default icon of the operating system is returned.
+ */
+QIcon FileIconProvider::icon(const QFileInfo &fileInfo)
+{
+ const QString suffix = fileInfo.suffix();
+ QIcon icon = iconForSuffix(suffix);
+
+ if (icon.isNull()) {
+ // Get icon from OS and store it in the cache
+
+ // Disabled since for now we'll make sure that all icons fit with our
+ // own custom icons by returning an empty one if we don't know it.
+#if 0
+ // This is incorrect if the OS does not always return the same icon for the
+ // same suffix (Mac OS X), but should speed up the retrieval a lot ...
+ icon = m_systemIconProvider.icon(fileInfo);
+ if (!suffix.isEmpty())
+ registerIconForSuffix(icon, suffix);
+#else
+ if (fileInfo.isDir()) {
+ icon = m_systemIconProvider.icon(fileInfo);
+ } else {
+ icon = m_unknownFileIcon;
+ }
+#endif
+ }
+
+ return icon;
+}
+
+/*!
+ Registers an icon for a given suffix, overriding any existing icon.
+ */
+void FileIconProvider::registerIconForSuffix(const QIcon &icon, const QString &suffix)
+{
+ // delete old icon, if it exists
+ QList<QPair<QString,QIcon> >::iterator iter = m_cache.begin();
+ for(; iter != m_cache.end(); ++iter) {
+ if ((*iter).first == suffix) {
+ iter = m_cache.erase(iter);
+ break;
+ }
+ }
+
+ QPair<QString,QIcon> newEntry(suffix, icon);
+ m_cache.append(newEntry);
+}
+
+/*!
+ Returns an icon for the given suffix, or an empty one if none registered.
+ */
+QIcon FileIconProvider::iconForSuffix(const QString &suffix) const
+{
+ QIcon icon;
+
+ if (suffix.isEmpty())
+ return icon;
+
+ QList<QPair<QString,QIcon> >::const_iterator iter = m_cache.constBegin();
+ for(; iter != m_cache.constEnd(); ++iter) {
+ if ((*iter).first == suffix) {
+ icon = (*iter).second;
+ break;
+ }
+ }
+
+ return icon;
+}
+
+/*!
+ Returns the sole instance of FileIconProvider.
+ */
+FileIconProvider *FileIconProvider::instance()
+{
+ if (!m_instance)
+ m_instance = new FileIconProvider;
+ return m_instance;
+}
diff --git a/src/plugins/coreplugin/fileiconprovider.h b/src/plugins/coreplugin/fileiconprovider.h
new file mode 100644
index 0000000000..4124eeb43d
--- /dev/null
+++ b/src/plugins/coreplugin/fileiconprovider.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILEICONPROVIDER_H
+#define FILEICONPROVIDER_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QPair>
+#include <QtGui/QFileIconProvider>
+#include <QtGui/QIcon>
+
+namespace Core {
+
+class CORE_EXPORT FileIconProvider {
+public:
+ ~FileIconProvider(); // used to clear the cache
+ QIcon icon(const QFileInfo &fileInfo);
+
+ void registerIconForSuffix(const QIcon &icon, const QString &suffix);
+
+ static FileIconProvider *instance();
+
+private:
+ QIcon iconForSuffix(const QString &suffix) const;
+
+ // mapping of file ending to icon
+ // TODO: Check if this is really faster than a QHash
+ mutable QList<QPair<QString, QIcon> > m_cache;
+
+ QFileIconProvider m_systemIconProvider;
+ QIcon m_unknownFileIcon;
+
+ // singleton pattern
+ FileIconProvider();
+ static FileIconProvider *m_instance;
+};
+
+} // namespace Core
+
+#endif // FILEICONPROVIDER_H
diff --git a/src/plugins/coreplugin/filemanager.cpp b/src/plugins/coreplugin/filemanager.cpp
new file mode 100644
index 0000000000..299bba4ff9
--- /dev/null
+++ b/src/plugins/coreplugin/filemanager.cpp
@@ -0,0 +1,592 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filemanager.h"
+#include "ifile.h"
+#include "mainwindow.h"
+#include "saveitemsdialog.h"
+#include "vcsmanager.h"
+#include "editormanager.h"
+#include "mimedatabase.h"
+#include "iversioncontrol.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QTimer>
+#include <QtCore/QFileSystemWatcher>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+using namespace Core;
+using namespace Core::Internal;
+
+/*!
+ \class FileManager
+ \mainclass
+ \ingroup qwb
+ \inheaderfile filemanager.h
+ \brief Manages a set of IFile objects.
+
+ The FileManager service monitors a set of IFile's. Plugins should register
+ files they work with at the service. The files the IFile's point to will be
+ monitored at filesystem level. If a file changes, the status of the IFile's
+ will be adjusted accordingly. Furthermore, on application exit the user will
+ be asked to save all modified files.
+
+ Different IFile objects in the set can point to the same file in the
+ filesystem. The monitoring of a file can be blocked by blockFileChange(), and
+ enabled again by unblockFileChange().
+
+ The FileManager service also provides two convenience methods for saving
+ files: saveModifiedFiles() and saveModifiedFilesSilently(). Both take a list
+ of FileInterfaces as an argument, and return the list of files which were
+ _not_ saved.
+
+ The service also manages the list of recent files to be shown to the user
+ (see addToRecentFiles() and recentFiles()).
+ */
+
+static const char *settingsGroup = "RecentFiles";
+static const char *filesKey = "Files";
+
+FileManager::FileManager(Core::ICore *core, MainWindow *mw) :
+ QObject(mw),
+ m_core(core),
+ m_mainWindow(mw),
+ m_fileWatcher(new QFileSystemWatcher(this)),
+ m_blockActivated(false)
+{
+ connect(m_fileWatcher, SIGNAL(fileChanged(const QString&)),
+ this, SLOT(changedFile(const QString&)));
+ connect(m_mainWindow, SIGNAL(windowActivated()),
+ this, SLOT(mainWindowActivated()));
+ connect(m_core, SIGNAL(contextChanged(Core::IContext*)),
+ this, SLOT(syncWithEditor(Core::IContext*)));
+
+ QSettings *s = m_mainWindow->settings();
+ s->beginGroup(QLatin1String(settingsGroup));
+ m_recentFiles = s->value(QLatin1String(filesKey), QStringList()).toStringList();
+ s->endGroup();
+ for (QStringList::iterator it = m_recentFiles.begin(); it != m_recentFiles.end(); ) {
+ if (QFileInfo(*it).isFile()) {
+ ++it;
+ } else {
+ it = m_recentFiles.erase(it);
+ }
+ }
+}
+
+/*!
+ \fn bool FileManager::addFiles(const QList<IFile *> &files)
+
+ Adds a list of IFile's to the collection.
+
+ Returns true if the file specified by \a files have not been yet part of the file list.
+*/
+bool FileManager::addFiles(const QList<IFile *> &files)
+{
+ bool filesAdded = false;
+ foreach (IFile *file, files) {
+ if (!file || m_managedFiles.contains(file))
+ continue;
+ connect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
+ connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
+ filesAdded = true;
+ addWatch(fixFileName(file->fileName()));
+ updateFileInfo(file);
+ }
+ return filesAdded;
+}
+
+/*!
+ \fn bool FileManager::addFile(IFile *files)
+
+ Adds a IFile object to the collection.
+
+ Returns true if the file specified by \a file has not been yet part of the file list.
+*/
+bool FileManager::addFile(IFile *file)
+{
+ return addFiles(QList<IFile *>() << file);
+}
+
+void FileManager::fileDestroyed(QObject *obj)
+{
+ // we can't use qobject_cast here, because meta data is already destroyed
+ IFile *file = static_cast<IFile*>(obj);
+ const QString filename = m_managedFiles.value(file).fileName;
+ m_managedFiles.remove(file);
+ removeWatch(filename);
+}
+
+/*!
+ \fn bool FileManager::removeFile(IFile *file)
+
+ Removes a IFile object from the collection.
+
+ Returns true if the file specified by \a file has been part of the file list.
+*/
+bool FileManager::removeFile(IFile *file)
+{
+ if (!file)
+ return false;
+
+ disconnect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
+ disconnect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
+
+ if (!m_managedFiles.contains(file))
+ return false;
+ const FileInfo info = m_managedFiles.take(file);
+ const QString filename = info.fileName;
+ removeWatch(filename);
+ return true;
+}
+
+void FileManager::addWatch(const QString &filename)
+{
+ if (!filename.isEmpty() && managedFiles(filename).isEmpty()) {
+ m_fileWatcher->addPath(filename);
+ }
+}
+
+void FileManager::removeWatch(const QString &filename)
+{
+ if (!filename.isEmpty() && managedFiles(filename).isEmpty()) {
+ m_fileWatcher->removePath(filename);
+ }
+}
+
+void FileManager::checkForNewFileName()
+{
+ IFile *file = qobject_cast<IFile *>(sender());
+ Q_ASSERT(file);
+ const QString newfilename = fixFileName(file->fileName());
+ const QString oldfilename = m_managedFiles.value(file).fileName;
+ if (!newfilename.isEmpty() && newfilename != oldfilename) {
+ m_managedFiles[file].fileName = newfilename;
+ removeWatch(oldfilename);
+ addWatch(newfilename);
+ }
+}
+
+// TODO Rename to nativeFileName
+QString FileManager::fixFileName(const QString &fileName)
+{
+ QString s = fileName;
+#ifdef Q_OS_WIN
+ s = s.toLower();
+#endif
+ if (!QFile::exists(s))
+ return QDir::toNativeSeparators(s);
+ return QFileInfo(QDir::toNativeSeparators(s)).canonicalFilePath();
+}
+
+/*!
+ \fn bool FileManager::isFileManaged(const QString &fileName) const
+
+ Returns true if at least one IFile in the set points to \a fileName.
+*/
+bool FileManager::isFileManaged(const QString &fileName) const
+{
+ if (fileName.isEmpty())
+ return false;
+
+ return !managedFiles(fixFileName(fileName)).isEmpty();
+}
+
+/*!
+ \fn QList<IFile*> FileManager::modifiedFiles() const
+
+ Returns the list of IFile's that have been modified.
+*/
+QList<IFile *> FileManager::modifiedFiles() const
+{
+ QList<IFile *> modifiedFiles;
+
+ const QMap<IFile*, FileInfo>::const_iterator cend = m_managedFiles.constEnd();
+ for (QMap<IFile*, FileInfo>::const_iterator i = m_managedFiles.constBegin(); i != cend; ++i) {
+ IFile *fi = i.key();
+ if (fi->isModified())
+ modifiedFiles << fi;
+ }
+ return modifiedFiles;
+}
+
+/*!
+ \fn void FileManager::blockFileChange(IFile *file)
+
+ Blocks the monitoring of the file the \a file argument points to.
+*/
+void FileManager::blockFileChange(IFile *file)
+{
+ if (!file->fileName().isEmpty())
+ m_fileWatcher->removePath(file->fileName());
+}
+
+/*!
+ \fn void FileManager::unblockFileChange(IFile *file)
+
+ Enables the monitoring of the file the \a file argument points to, and update the status of the corresponding IFile's.
+*/
+void FileManager::unblockFileChange(IFile *file)
+{
+ foreach (IFile *managedFile, managedFiles(file->fileName()))
+ updateFileInfo(managedFile);
+ if (!file->fileName().isEmpty())
+ m_fileWatcher->addPath(file->fileName());
+}
+
+void FileManager::updateFileInfo(IFile *file)
+{
+ const QString fixedname = fixFileName(file->fileName());
+ const QFileInfo fi(file->fileName());
+ FileInfo info;
+ info.fileName = fixedname;
+ info.modified = fi.lastModified();
+ info.permissions = fi.permissions();
+ m_managedFiles.insert(file, info);
+}
+
+/*!
+ \fn QList<IFile*> FileManager::saveModifiedFilesSilently(const QList<IFile*> &files)
+
+ Tries to save the files listed in \a files . Returns the files that could not be saved.
+*/
+QList<IFile *> FileManager::saveModifiedFilesSilently(const QList<IFile *> &files)
+{
+ return saveModifiedFiles(files, 0, true, QString());
+}
+
+/*!
+ \fn QList<IFile*> FileManager::saveModifiedFiles(const QList<IFile*> &files, bool *cancelled, const QString &message)
+
+ Asks the user whether to save the files listed in \a files . Returns the files that have not been saved.
+*/
+QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files,
+ bool *cancelled, const QString &message)
+{
+ return saveModifiedFiles(files, cancelled, false, message);
+}
+
+static QMessageBox::StandardButton skipFailedPrompt(QWidget *parent, const QString &fileName)
+{
+ return QMessageBox::question(parent,
+ QObject::tr("Can't save file"),
+ QObject::tr("Can't save changes to '%1'. Do you want to continue and loose your changes?").arg(fileName),
+ QMessageBox::YesToAll| QMessageBox::Yes|QMessageBox::No,
+ QMessageBox::No);
+}
+
+QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files,
+ bool *cancelled, bool silently, const QString &message)
+{
+ if (cancelled)
+ (*cancelled) = false;
+
+ QList<IFile *> notSaved;
+ QMap<IFile*, QString> modifiedFiles;
+
+ foreach (IFile *file, files) {
+ if (file->isModified()) {
+ QString name = file->fileName();
+ if (name.isEmpty())
+ name = file->suggestedFileName();
+
+ // There can be several FileInterfaces pointing to the same file
+ // Select one that is not readonly.
+ if (!(modifiedFiles.values().contains(name)
+ && file->isReadOnly()))
+ modifiedFiles.insert(file, name);
+ }
+ }
+
+ if (!modifiedFiles.isEmpty()) {
+ QList<IFile *> filesToSave;
+ QSet<IFile *> filesToOpen;
+ if (silently) {
+ filesToSave = modifiedFiles.keys();
+ } else {
+ SaveItemsDialog dia(m_mainWindow, modifiedFiles);
+ if (!message.isEmpty())
+ dia.setMessage(message);
+ if (dia.exec() != QDialog::Accepted) {
+ if (cancelled)
+ (*cancelled) = true;
+ notSaved = modifiedFiles.keys();
+ return notSaved;
+ }
+ filesToSave = dia.itemsToSave();
+ filesToOpen = dia.itemsToOpen();
+ }
+
+ bool yestoall = false;
+ foreach (IFile *file, filesToSave) {
+ if (file->isReadOnly() && filesToOpen.contains(file)) {
+ QString directory = QFileInfo(file->fileName()).absolutePath();
+ IVersionControl *versionControl = m_mainWindow->vcsManager()->findVersionControlForDirectory(directory);
+ if (versionControl)
+ versionControl->vcsOpen(file->fileName());
+ }
+ if (!file->isReadOnly() && !file->fileName().isEmpty()) {
+ blockFileChange(file);
+ const bool ok = file->save();
+ unblockFileChange(file);
+ if (!ok)
+ notSaved.append(file);
+ } else if (QFile::exists(file->fileName()) && !file->isSaveAsAllowed()) {
+ if (yestoall)
+ continue;
+ const QFileInfo fi(file->fileName());
+ switch (skipFailedPrompt(m_mainWindow, fi.fileName())) {
+ case QMessageBox::YesToAll:
+ yestoall = true;
+ break;
+ case QMessageBox::No:
+ if (cancelled)
+ *cancelled = true;
+ return filesToSave;
+ default:
+ break;
+ }
+ } else {
+ QString fileName = getSaveAsFileName(file);
+ bool ok = false;
+ if (!fileName.isEmpty()) {
+ blockFileChange(file);
+ ok = file->save(fileName);
+ unblockFileChange(file);
+ }
+ if (!ok)
+ notSaved.append(file);
+ }
+ }
+ }
+ return notSaved;
+}
+
+QString FileManager::getSaveFileNameWithExtension(const QString &title, const QString &path,
+ const QString &fileFilter, const QString &extension)
+{
+ QString fileName;
+ bool repeat;
+ do {
+ repeat = false;
+ fileName = QFileDialog::getSaveFileName(m_mainWindow, title, path, fileFilter);
+ if (!fileName.isEmpty() && !extension.isEmpty() && !fileName.endsWith(extension)) {
+ fileName.append(extension);
+ if (QFile::exists(fileName)) {
+ if (QMessageBox::warning(m_mainWindow, tr("Overwrite?"),
+ tr("An item named '%1' already exists at this location. Do you want to overwrite it?").arg(fileName),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ repeat = true;
+ }
+ }
+ } while (repeat);
+ return fileName;
+}
+
+/*!
+ \fn QString FileManager::getSaveAsFileName(IFile *file)
+
+ Asks the user for a new file name (Save File As) for /arg file.
+*/
+QString FileManager::getSaveAsFileName(IFile *file)
+{
+ if (!file)
+ return QLatin1String("");
+ QString absoluteFilePath = file->fileName();
+ const QFileInfo fi(absoluteFilePath);
+ QString fileName = fi.fileName();
+ QString path = fi.absolutePath();
+ if (absoluteFilePath.isEmpty()) {
+ fileName = file->suggestedFileName();
+ const QString defaultPath = file->defaultPath();
+ if (!defaultPath.isEmpty())
+ path = defaultPath;
+ }
+ QString filterString;
+ QString preferredSuffix;
+ if (const MimeType mt = m_core->mimeDatabase()->findByFile(fi)) {
+ filterString = mt.filterString();
+ preferredSuffix = mt.preferredSuffix();
+ }
+
+ absoluteFilePath = getSaveFileNameWithExtension(tr("Save File As"),
+ path + QDir::separator() + fileName,
+ filterString,
+ preferredSuffix);
+ return absoluteFilePath;
+}
+
+void FileManager::changedFile(const QString &file)
+{
+ const bool wasempty = m_changedFiles.isEmpty();
+ foreach (IFile *fileinterface, managedFiles(file))
+ m_changedFiles << fileinterface;
+ if (wasempty && !m_changedFiles.isEmpty()) {
+ QTimer::singleShot (200, this, SLOT(checkForReload()));
+ }
+}
+
+void FileManager::mainWindowActivated()
+{
+ checkForReload();
+}
+
+void FileManager::checkForReload()
+{
+ if (QApplication::activeWindow() == m_mainWindow &&
+ !m_blockActivated && !m_changedFiles.isEmpty()) {
+ m_blockActivated = true;
+ const QList<QPointer<IFile> > changed = m_changedFiles;
+ m_changedFiles.clear();
+ IFile::ReloadBehavior behavior =
+ IFile::AskForReload;
+ foreach (IFile *f, changed) {
+ if (!f)
+ continue;
+ QFileInfo fi(f->fileName());
+ FileInfo info = m_managedFiles.value(f);
+ if (info.modified != fi.lastModified()
+ || info.permissions != fi.permissions()) {
+ if (info.modified != fi.lastModified())
+ f->modified(&behavior);
+ else {
+ IFile::ReloadBehavior tempBeh =
+ IFile::ReloadPermissions;
+ f->modified(&tempBeh);
+ }
+ updateFileInfo(f);
+
+ // the file system watchers loses inodes when a file is removed/renamed. Work around it.
+ m_fileWatcher->removePath(f->fileName());
+ m_fileWatcher->addPath(f->fileName());
+ }
+ }
+ m_blockActivated = false;
+ checkForReload();
+ }
+}
+
+void FileManager::syncWithEditor(Core::IContext *context)
+{
+ if (!context)
+ return;
+
+ Core::IEditor *editor = m_core->editorManager()->currentEditor();
+ if (editor && (editor->widget() == context->widget()))
+ setCurrentFile(editor->file()->fileName());
+}
+
+/*!
+ \fn void FileManager::addToRecentFiles(const QString &fileName)
+
+ Adds the \a fileName to the list of recent files.
+*/
+void FileManager::addToRecentFiles(const QString &fileName)
+{
+ if (fileName.isEmpty())
+ return;
+ QString prettyFileName(QDir::toNativeSeparators(fileName));
+ m_recentFiles.removeAll(prettyFileName);
+ if (m_recentFiles.count() > m_maxRecentFiles)
+ m_recentFiles.removeLast();
+ m_recentFiles.prepend(prettyFileName);
+}
+
+/*!
+ \fn QStringList FileManager::recentFiles() const
+
+ Returns the list of recent files.
+*/
+QStringList FileManager::recentFiles() const
+{
+ return m_recentFiles;
+}
+
+void FileManager::saveRecentFiles()
+{
+ QSettings *s = m_mainWindow->settings();
+ s->beginGroup(QLatin1String(settingsGroup));
+ s->setValue(QLatin1String(filesKey), m_recentFiles);
+ s->endGroup();
+}
+
+/*!
+
+ The current file is e.g. the file currently opened when an editor is active,
+ or the selected file in case a Project Explorer is active ...
+
+ \see currentFile
+ */
+void FileManager::setCurrentFile(const QString &filePath)
+{
+ if (m_currentFile == filePath)
+ return;
+ m_currentFile = filePath;
+ emit currentFileChanged(m_currentFile);
+}
+
+/*!
+ Returns the absolute path of the current file
+
+ The current file is e.g. the file currently opened when an editor is active,
+ or the selected file in case a Project Explorer is active ...
+
+ \see setCurrentFile
+ */
+QString FileManager::currentFile() const
+{
+ return m_currentFile;
+}
+
+/*!
+ \fn QList<IFile*> FileManager::managedFiles(const QString &fileName) const
+
+ Returns the list one IFile's in the set that point to \a fileName.
+*/
+QList<IFile *> FileManager::managedFiles(const QString &fileName) const
+{
+ const QString fixedName = fixFileName(fileName);
+ QList<IFile *> result;
+ if (!fixedName.isEmpty()) {
+ const QMap<IFile*, FileInfo>::const_iterator cend = m_managedFiles.constEnd();
+ for (QMap<IFile*, FileInfo>::const_iterator i = m_managedFiles.constBegin(); i != cend; ++i) {
+ if (i.value().fileName == fixedName)
+ result << i.key();
+ }
+ }
+ return result;
+}
diff --git a/src/plugins/coreplugin/filemanager.h b/src/plugins/coreplugin/filemanager.h
new file mode 100644
index 0000000000..c6759d5b45
--- /dev/null
+++ b/src/plugins/coreplugin/filemanager.h
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILEMANAGER_H
+#define FILEMANAGER_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QDateTime>
+#include <QtCore/QFile>
+#include <QtCore/QStringList>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+class QFileSystemWatcher;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class ICore;
+class IContext;
+class IFile;
+
+namespace Internal {
+class MainWindow;
+}
+
+class CORE_EXPORT FileManager : public QObject
+{
+ Q_OBJECT
+
+ struct FileInfo {
+ QString fileName;
+ QDateTime modified;
+ QFile::Permissions permissions;
+ };
+
+public:
+ FileManager(Core::ICore *core, Internal::MainWindow *ew);
+
+ // file pool to monitor
+ bool addFiles(const QList<IFile *> &files);
+ bool addFile(IFile *file);
+ bool removeFile(IFile *file);
+ bool isFileManaged(const QString &fileName) const;
+ QList<IFile *> managedFiles(const QString &fileName) const;
+ QList<IFile *> modifiedFiles() const;
+
+ void blockFileChange(IFile *file);
+ void unblockFileChange(IFile *file);
+
+ // recent files
+ void addToRecentFiles(const QString &fileName);
+ QStringList recentFiles() const;
+ void saveRecentFiles();
+
+ // current file
+ void setCurrentFile(const QString &filePath);
+ QString currentFile() const;
+
+ // helper methods
+ static QString fixFileName(const QString &fileName);
+
+ QString getSaveFileNameWithExtension(const QString &title, const QString &path,
+ const QString &fileFilter, const QString &extension);
+ QString getSaveAsFileName(IFile *file);
+
+ QList<IFile *> saveModifiedFilesSilently(const QList<IFile *> &files);
+ QList<IFile *> saveModifiedFiles(
+ const QList<IFile *> &files,
+ bool *cancelled = 0,
+ const QString &message = QString());
+
+signals:
+ void currentFileChanged(const QString &filePath);
+
+private slots:
+ void fileDestroyed(QObject *obj);
+ void checkForNewFileName();
+ void checkForReload();
+ void changedFile(const QString &file);
+ void mainWindowActivated();
+ void syncWithEditor(Core::IContext *context);
+
+private:
+ void addWatch(const QString &filename);
+ void removeWatch(const QString &filename);
+ void updateFileInfo(IFile *file);
+
+ QList<IFile *> saveModifiedFiles(const QList<IFile *> &files,
+ bool *cancelled, bool silently, const QString &message);
+
+ QMap<IFile*, FileInfo> m_managedFiles;
+
+ QStringList m_recentFiles;
+ static const int m_maxRecentFiles = 7;
+
+ QString m_currentFile;
+
+ Core::ICore *m_core;
+ Internal::MainWindow *m_mainWindow;
+ QFileSystemWatcher *m_fileWatcher;
+ QList<QPointer<IFile> > m_changedFiles;
+ bool m_blockActivated;
+};
+
+} // namespace Core
+
+#endif // FILEMANAGER_H
diff --git a/src/plugins/coreplugin/findplaceholder.cpp b/src/plugins/coreplugin/findplaceholder.cpp
new file mode 100644
index 0000000000..ec80b530b5
--- /dev/null
+++ b/src/plugins/coreplugin/findplaceholder.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "findplaceholder.h"
+#include "modemanager.h"
+
+#include <QtGui/QVBoxLayout>
+
+
+using namespace Core;
+
+FindToolBarPlaceHolder *FindToolBarPlaceHolder::m_current = 0;
+
+FindToolBarPlaceHolder::FindToolBarPlaceHolder(Core::IMode *mode, QWidget *parent)
+ :QWidget(parent), m_mode(mode)
+{
+ setLayout(new QVBoxLayout);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+ layout()->setMargin(0);
+ connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
+ this, SLOT(currentModeChanged(Core::IMode *)));
+}
+
+FindToolBarPlaceHolder::~FindToolBarPlaceHolder()
+{
+
+}
+
+void FindToolBarPlaceHolder::currentModeChanged(Core::IMode *mode)
+{
+ if (m_current == this)
+ m_current = 0;
+ if (m_mode == mode)
+ m_current = this;
+}
+
+FindToolBarPlaceHolder *FindToolBarPlaceHolder::getCurrent()
+{
+ return m_current;
+}
diff --git a/src/plugins/coreplugin/findplaceholder.h b/src/plugins/coreplugin/findplaceholder.h
new file mode 100644
index 0000000000..89850d812e
--- /dev/null
+++ b/src/plugins/coreplugin/findplaceholder.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FINDPLACEHOLDER_H
+#define FINDPLACEHOLDER_H
+
+#include "core_global.h"
+#include <QtGui/QWidget>
+
+namespace Core {
+
+class IMode;
+
+class CORE_EXPORT FindToolBarPlaceHolder : public QWidget
+{
+ Q_OBJECT
+public:
+ FindToolBarPlaceHolder(Core::IMode *mode, QWidget *parent = 0);
+ ~FindToolBarPlaceHolder();
+
+ static FindToolBarPlaceHolder *getCurrent();
+private slots:
+ void currentModeChanged(Core::IMode *);
+private:
+ Core::IMode *m_mode;
+ static FindToolBarPlaceHolder *m_current;
+};
+
+} // namespace Core
+
+#endif // FINDPLACEHOLDER_H
diff --git a/src/plugins/coreplugin/flowlayout.cpp b/src/plugins/coreplugin/flowlayout.cpp
new file mode 100644
index 0000000000..1c43dead53
--- /dev/null
+++ b/src/plugins/coreplugin/flowlayout.cpp
@@ -0,0 +1,155 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2004-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+
+#include "flowlayout.h"
+
+using namespace Core::Internal;
+
+FlowLayout::FlowLayout(QWidget *parent, int margin, int spacing)
+ : QLayout(parent)
+{
+ setMargin(margin);
+ setSpacing(spacing);
+}
+
+FlowLayout::FlowLayout(int spacing)
+{
+ setSpacing(spacing);
+}
+
+FlowLayout::~FlowLayout()
+{
+ QLayoutItem *item;
+ while ((item = takeAt(0)))
+ delete item;
+}
+
+void FlowLayout::addItem(QLayoutItem *item)
+{
+ itemList.append(item);
+}
+
+int FlowLayout::count() const
+{
+ return itemList.size();
+}
+
+QLayoutItem *FlowLayout::itemAt(int index) const
+{
+ return itemList.value(index);
+}
+
+QLayoutItem *FlowLayout::takeAt(int index)
+{
+ if (index >= 0 && index < itemList.size())
+ return itemList.takeAt(index);
+ else
+ return 0;
+}
+
+Qt::Orientations FlowLayout::expandingDirections() const
+{
+ return 0;
+}
+
+bool FlowLayout::hasHeightForWidth() const
+{
+ return true;
+}
+
+int FlowLayout::heightForWidth(int width) const
+{
+ int height = doLayout(QRect(0, 0, width, 0), true);
+ return height;
+}
+
+void FlowLayout::setGeometry(const QRect &rect)
+{
+ QLayout::setGeometry(rect);
+ doLayout(rect, false);
+}
+
+QSize FlowLayout::sizeHint() const
+{
+ return minimumSize();
+}
+
+QSize FlowLayout::minimumSize() const
+{
+ QSize size;
+ QLayoutItem *item;
+ foreach (item, itemList)
+ size = size.expandedTo(item->minimumSize());
+
+ size += QSize(2*margin(), 2*margin());
+ return size;
+}
+
+int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
+{
+ int x = rect.x();
+ int y = rect.y();
+ int lineHeight = 0;
+
+ QLayoutItem *item;
+ foreach (item, itemList) {
+ int nextX = x + item->sizeHint().width() + spacing();
+ if (nextX - spacing() > rect.right() && lineHeight > 0) {
+ x = rect.x();
+ y = y + lineHeight + spacing();
+ nextX = x + item->sizeHint().width() + spacing();
+ lineHeight = 0;
+ }
+
+ if (!testOnly)
+ item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
+
+ x = nextX;
+ lineHeight = qMax(lineHeight, item->sizeHint().height());
+ }
+ return y + lineHeight - rect.y() + margin();
+}
diff --git a/src/plugins/coreplugin/flowlayout.h b/src/plugins/coreplugin/flowlayout.h
new file mode 100644
index 0000000000..f0a7d4235b
--- /dev/null
+++ b/src/plugins/coreplugin/flowlayout.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2004-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef FLOWLAYOUT_H
+#define FLOWLAYOUT_H
+
+#include <QLayout>
+#include <QRect>
+#include <QWidgetItem>
+
+namespace Core {
+namespace Internal {
+
+class FlowLayout : public QLayout
+{
+public:
+ FlowLayout(QWidget *parent, int margin = 0, int spacing = -1);
+ FlowLayout(int spacing = -1);
+ ~FlowLayout();
+
+ void addItem(QLayoutItem *item);
+ Qt::Orientations expandingDirections() const;
+ bool hasHeightForWidth() const;
+ int heightForWidth(int) const;
+ int count() const;
+ QLayoutItem *itemAt(int index) const;
+ QSize minimumSize() const;
+ void setGeometry(const QRect &rect);
+ QSize sizeHint() const;
+ QLayoutItem *takeAt(int index);
+
+private:
+ int doLayout(const QRect &rect, bool testOnly) const;
+
+ QList<QLayoutItem *> itemList;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif
diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp
new file mode 100644
index 0000000000..8595eb03ee
--- /dev/null
+++ b/src/plugins/coreplugin/generalsettings.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "generalsettings.h"
+
+#include "stylehelper.h"
+#include "utils/qtcolorbutton.h"
+#include <coreplugin/editormanager/editormanager.h>
+#include <QtGui/QMessageBox>
+
+#include "ui_generalsettings.h"
+
+using namespace Core::Internal;
+
+GeneralSettings::GeneralSettings()
+{
+}
+
+QString GeneralSettings::name() const
+{
+ return tr("General");
+}
+
+QString GeneralSettings::category() const
+{
+ return QLatin1String("Environment");
+}
+
+QString GeneralSettings::trCategory() const
+{
+ return tr("Environment");
+}
+
+QWidget* GeneralSettings::createPage(QWidget *parent)
+{
+ m_page = new Ui_GeneralSettings();
+ QWidget *w = new QWidget(parent);
+ m_page->setupUi(w);
+
+ m_page->colorButton->setColor(StyleHelper::baseColor());
+ m_page->externalEditorEdit->setText(EditorManager::instance()->externalEditor());
+
+ connect(m_page->resetButton, SIGNAL(clicked()),
+ this, SLOT(resetInterfaceColor()));
+ connect(m_page->helpExternalEditorButton, SIGNAL(clicked()),
+ this, SLOT(showHelpForExternalEditor()));
+
+
+ return w;
+}
+
+void GeneralSettings::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ // Apply the new base color if accepted
+ StyleHelper::setBaseColor(m_page->colorButton->color());
+ EditorManager::instance()->setExternalEditor(m_page->externalEditorEdit->text());
+
+}
+
+void GeneralSettings::resetInterfaceColor()
+{
+ m_page->colorButton->setColor(0x666666);
+}
+
+
+void GeneralSettings::showHelpForExternalEditor()
+{
+ if (m_dialog) {
+ m_dialog->show();
+ m_dialog->raise();
+ m_dialog->activateWindow();
+ return;
+ }
+ QMessageBox *mb = new QMessageBox(QMessageBox::Information,
+ tr("Variables"),
+ EditorManager::instance()->externalEditorHelpText(),
+ QMessageBox::Cancel,
+ m_page->helpExternalEditorButton);
+ mb->setWindowModality(Qt::NonModal);
+ m_dialog = mb;
+ mb->show();
+}
diff --git a/src/plugins/coreplugin/generalsettings.h b/src/plugins/coreplugin/generalsettings.h
new file mode 100644
index 0000000000..0cffc9caaf
--- /dev/null
+++ b/src/plugins/coreplugin/generalsettings.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GENERALSETTINGS_H
+#define GENERALSETTINGS_H
+
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class Ui_GeneralSettings;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Internal {
+
+class GeneralSettings : public IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ GeneralSettings();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+ QWidget* createPage(QWidget *parent);
+ void finished(bool accepted);
+
+private slots:
+ void resetInterfaceColor();
+ void showHelpForExternalEditor();
+
+private:
+ Ui_GeneralSettings *m_page;
+ QWidget *m_dialog;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // GENERALSETTINGS_H
diff --git a/src/plugins/coreplugin/generalsettings.ui b/src/plugins/coreplugin/generalsettings.ui
new file mode 100644
index 0000000000..1e5357d154
--- /dev/null
+++ b/src/plugins/coreplugin/generalsettings.ui
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GeneralSettings</class>
+ <widget class="QWidget" name="GeneralSettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>540</width>
+ <height>236</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>General settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="colorLabel">
+ <property name="text">
+ <string>User &amp;interface color:</string>
+ </property>
+ <property name="buddy">
+ <cstring>colorButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Core::Utils::QtColorButton" name="colorButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>64</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alphaAllowed" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="resetButton">
+ <property name="toolTip">
+ <string>Reset to default</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="core.qrc">
+ <normaloff>:/qworkbench/images/reset.png</normaloff>:/qworkbench/images/reset.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>External editor:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="externalEditorEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="helpExternalEditorButton">
+ <property name="text">
+ <string>?</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>111</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::QtColorButton</class>
+ <extends>QToolButton</extends>
+ <header location="global">utils/qtcolorbutton.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="core.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plugins/coreplugin/html/images/bg_site_header_dark_grey.png b/src/plugins/coreplugin/html/images/bg_site_header_dark_grey.png
new file mode 100644
index 0000000000..044c695a4d
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/bg_site_header_dark_grey.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/body_bg_circles_bottom_right.png b/src/plugins/coreplugin/html/images/body_bg_circles_bottom_right.png
new file mode 100644
index 0000000000..543e35071f
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/body_bg_circles_bottom_right.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/body_bg_gradient.png b/src/plugins/coreplugin/html/images/body_bg_gradient.png
new file mode 100644
index 0000000000..ebaa078c3e
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/body_bg_gradient.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/btn_getting_started.png b/src/plugins/coreplugin/html/images/btn_getting_started.png
new file mode 100644
index 0000000000..affd4b25ac
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/btn_getting_started.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/btn_getting_started_hover.png b/src/plugins/coreplugin/html/images/btn_getting_started_hover.png
new file mode 100644
index 0000000000..e6145de709
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/btn_getting_started_hover.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/btn_restore_session.png b/src/plugins/coreplugin/html/images/btn_restore_session.png
new file mode 100644
index 0000000000..4698c19a9c
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/btn_restore_session.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/btn_restore_session_hover.png b/src/plugins/coreplugin/html/images/btn_restore_session_hover.png
new file mode 100644
index 0000000000..30c878207d
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/btn_restore_session_hover.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/list_bullet_arrow.png b/src/plugins/coreplugin/html/images/list_bullet_arrow.png
new file mode 100644
index 0000000000..acf9f5da5e
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/list_bullet_arrow.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/mode_Project.png b/src/plugins/coreplugin/html/images/mode_Project.png
new file mode 100644
index 0000000000..05d7759cf1
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/mode_Project.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/nokia_logo.png b/src/plugins/coreplugin/html/images/nokia_logo.png
new file mode 100644
index 0000000000..c149f71b62
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/nokia_logo.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/product_logo.png b/src/plugins/coreplugin/html/images/product_logo.png
new file mode 100644
index 0000000000..7f8992e92c
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/product_logo.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/qt_logo.png b/src/plugins/coreplugin/html/images/qt_logo.png
new file mode 100644
index 0000000000..c8755ec090
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/qt_logo.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_bottom_left.png b/src/plugins/coreplugin/html/images/rc_bottom_left.png
new file mode 100644
index 0000000000..106f92f462
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_bottom_left.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_bottom_mid.png b/src/plugins/coreplugin/html/images/rc_bottom_mid.png
new file mode 100644
index 0000000000..7c01362073
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_bottom_mid.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_bottom_right.png b/src/plugins/coreplugin/html/images/rc_bottom_right.png
new file mode 100644
index 0000000000..eed56c4f5c
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_bottom_right.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_mid_left.png b/src/plugins/coreplugin/html/images/rc_mid_left.png
new file mode 100644
index 0000000000..d6dd8de8cf
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_mid_left.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_mid_mid.png b/src/plugins/coreplugin/html/images/rc_mid_mid.png
new file mode 100644
index 0000000000..26040bdd97
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_mid_mid.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_mid_right.png b/src/plugins/coreplugin/html/images/rc_mid_right.png
new file mode 100644
index 0000000000..2714b81f17
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_mid_right.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_top_left.png b/src/plugins/coreplugin/html/images/rc_top_left.png
new file mode 100644
index 0000000000..ffed637a15
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_top_left.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_top_mid.png b/src/plugins/coreplugin/html/images/rc_top_mid.png
new file mode 100644
index 0000000000..10f5abd31c
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_top_mid.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/images/rc_top_right.png b/src/plugins/coreplugin/html/images/rc_top_right.png
new file mode 100644
index 0000000000..830bb46c5d
--- /dev/null
+++ b/src/plugins/coreplugin/html/images/rc_top_right.png
Binary files differ
diff --git a/src/plugins/coreplugin/html/qt.css b/src/plugins/coreplugin/html/qt.css
new file mode 100644
index 0000000000..fa91bf8b93
--- /dev/null
+++ b/src/plugins/coreplugin/html/qt.css
@@ -0,0 +1,351 @@
+/**************************************
+Nokia, QT Software CSS - IDE Startseite
+**************************************/
+
+/**************************************
+Reset
+**************************************/
+* {
+
+ vertical-align: baseline;
+ font-weight: inherit;
+ font-family: inherit;
+ font-style: inherit;
+ padding: 0;
+ margin: 0;
+
+}
+
+/*image link*/
+a.img_link:link {text-decoration:none;}
+a.img_link:visited {text-decoration:none}
+a.img_link:active {text-decoration:none}
+a.img_link:hover {text-decoration:none}
+
+/*regular link*/
+a:link {color:#5e5e5e; text-decoration:none;}
+a:visited {color:#5e5e5e; text-decoration:none}
+a:active {color:#5e5e5e; text-decoration:none}
+a:hover {color:#5e5e5e; text-decoration:underline}
+
+p{
+
+ font-size:9pt;
+
+ }
+
+strong{
+ font-weight: bold;
+}
+
+em {
+ font-style: italic;
+}
+
+ul{
+
+ list-style-type: none;
+ margin:0px 0px;
+ padding:15px 0px;
+
+ }
+
+li {
+
+ background:url(images/list_bullet_arrow.png) top left no-repeat;
+ font-size:9pt;
+ padding:1px 0px 0px 22px;
+ margin:0px 0px 15px 0px;
+ }
+
+li:last-child{
+
+ margin:0px;
+
+ }
+
+
+
+
+
+img {
+
+ border: 0 none;
+
+ }
+
+/*Welcome Headline*/
+h1{
+
+ font-size:2em;
+ font-weight:normal;
+ padding-bottom:22px;
+
+ color:#4d4d4d;
+
+ }
+
+/*Headlines Recent...*/
+h2{
+
+ font-size:18px;
+ font-weight:normal;
+ color:#7c92a1;
+ border-bottom:1px solid #a6b5c1;
+ padding:5px 0px 10px 0px;
+
+ }
+
+.clear_float{
+
+ clear:both;
+
+ }
+
+.clear_left{
+
+ clear:left;
+
+ }
+
+.clear_right{
+
+ clear:right;
+
+ }
+
+/**************************************
+HTML / BODY
+**************************************/
+html, body {
+ font-family: Arial, Trebuchet, Lucida, sans-serif;
+ color: #5e5e5e;
+ background:#d7d7d7 url(images/body_bg_gradient.png) top left repeat-x;
+ height:100%;
+}
+
+/*Platzierung der Circles unten rechts*/
+.global_container {
+ position:relative;
+ width:100%;
+ min-height:100%;
+ min-width:550px;
+}
+
+
+.footer {
+ position:relative;
+ list-style-type:none;
+ margin:0;
+ padding:0;
+ width:100%;
+ height:100px;
+ margin-top:-100px;
+}
+
+.left-logo {
+ float:left;
+ background:none;
+ margin:0;
+ padding:0;
+ content:url(images/qt_logo.png);
+ }
+
+.right-logo {
+ float:right;
+ background:none;
+ margin:0;
+ padding:0;
+ content:url(images/nokia_logo.png);
+ }
+
+/**************************************
+Site Header
+**************************************/
+.site_header{
+
+ height:21px;
+ background:#686868 url(images/bg_site_header_dark_grey.png) top left repeat-x;
+
+ }
+
+.site_header p{
+
+ padding:3px 10px;
+ color:#fff;
+
+ }
+
+
+/**************************************
+Content
+**************************************/
+.content_container{
+
+ margin:0px auto;
+
+ /*CUSTOMIZE WIDTH*/
+ width:600px;
+ }
+
+
+/**************************************
+Layout TOP - Logo und Welcome Text
+**************************************/
+.layout_top{
+
+ padding-top:50px;
+ min-height:250px;
+
+ }
+
+
+/*Product Logo*/
+.layout_top .product_logo{
+
+ float:left;
+ width:210px;
+
+ }
+
+.layout_top .product_logo img{
+
+
+ }
+
+/*Welcome Text*/
+.layout_top .welcome_text{
+
+ margin-left:210px;
+ padding-top:50px;
+
+
+ }
+
+.layout_top .welcome_text p{
+
+ font-size:9pt;
+ line-height:180%;
+
+ }
+
+.layout_top .welcome_text .get_started_container{
+
+ border-top:1px solid #a8a8a8;
+ margin-top:20px;
+ padding:10px 0px;
+
+ }
+
+/*Getting started Button inlusive CSS HOVER*/
+a.btn_getting_started{
+
+ float:right;
+ display:block;
+ background-image:url(images/btn_getting_started.png);
+ width:133px;
+ height:29px;
+
+ }
+
+a.btn_getting_started:hover{
+
+ background-image:url(images/btn_getting_started_hover.png)
+
+ };
+
+
+/**************************************
+Layout BOTTOM - Recent Projects und Recent Sessions
+**************************************/
+
+
+/*ROUNDED CORNER BOX - fluid layout compatible*/
+.rc_box{}
+
+.rc_box .top{height:8px;}
+
+.rc_box .top .left{float:left; height:8px; width:8px; background:url(images/rc_top_left.png) top left no-repeat;}
+
+.rc_box .top .mid{margin-left:8px; margin-right:8px; height:8px; background:url(images/rc_top_mid.png) top left repeat-x;}
+
+.rc_box .top .right{float:right; height:8px; width:8px; background:url(images/rc_top_right.png) top left no-repeat;}
+
+
+.rc_box .mid{}
+
+.rc_box .mid .mid{padding:0px 20px 0px 10px; min-height:203px; background:#e6e6e6 url(images/rc_mid_mid.png) top left repeat-x; border-left:1px solid #a6b5c1; border-right:1px solid #a6b5c1;}
+
+.rc_box .icon{
+
+ width:35px;
+ float:left;
+ padding-top:3px;
+
+ }
+
+.rc_box .box_content{
+
+ margin-left:35px;
+
+ }
+
+
+.rc_box .bottom{height:8px;}
+
+.rc_box .bottom .left{float:left; height:8px; width:8px; background:url(images/rc_bottom_left.png) top left no-repeat;}
+
+.rc_box .bottom .mid{margin-left:8px; margin-right:8px; height:8px; background:url(images/rc_bottom_mid.png) top left repeat-x;}
+
+.rc_box .bottom .right{float:right; height:8px; width:8px; background:url(images/rc_bottom_right.png) top left no-repeat;}
+
+/*Layout Bottom*/
+.layout_bottom{ padding:10px 0px 50px 0px; }
+
+/*Recent Projects*/
+.layout_bottom .rec_proj_container{
+
+ width:50%;
+ float:left;
+
+ }
+
+.layout_bottom .rec_proj_container .rec_proj_box{
+
+ margin-right:10px;
+
+ }
+
+
+
+/*Recent Sessions*/
+.layout_bottom .rec_sess_container{
+
+ margin-left:50%;
+
+ }
+
+.layout_bottom .rec_sess_container .rec_sess_box{
+
+ margin-left:10px;
+
+ }
+
+/*Restore Session Button inlusive CSS HOVER*/
+a.restore_session{
+
+ float:right;
+ display:block;
+ background-image:url(images/btn_restore_session.png);
+ width:137px;
+ height:27px;
+
+ }
+
+a.restore_session:hover{
+
+ background-image:url(images/btn_restore_session_hover.png)
+
+ };
+
+
diff --git a/src/plugins/coreplugin/html/recent_projects.html b/src/plugins/coreplugin/html/recent_projects.html
new file mode 100644
index 0000000000..db1bab8bcf
--- /dev/null
+++ b/src/plugins/coreplugin/html/recent_projects.html
@@ -0,0 +1,41 @@
+ <div class="rc_box rec_proj_container">
+ <div class="rec_proj_box">
+ <!-- top -->
+ <div class="top">
+ <div class="left"></div>
+ <div class="right"></div>
+ <div class="mid"></div>
+ </div>
+
+ <!-- mid -->
+ <div class="mid">
+
+ <div class="mid">
+
+ <div class="icon">
+ <img src="images/mode_Project.png"></img>
+ </div>
+ <div class="box_content">
+ <h2>Recent Projects</h2>
+ <ul>
+ <!-- RECENT PROJECTS LIST -->
+ <!--<li><p><a href="#">Project 1</a></p></li>
+ <li><p><a href="#">Project 2</a></p></li>
+ <li><p><a href="#">Project 3</a></p></li>
+ <li><p><a href="#">Project 4</a></p></li>
+ <li><p><a href="#">Project 5</a></p></li>-->
+ </ul>
+ </div>
+
+ </div>
+
+ </div>
+
+ <!-- bottom -->
+ <div class="bottom">
+ <div class="left"></div>
+ <div class="right"></div>
+ <div class="mid"></div>
+ </div>
+ </div>
+ </div>
diff --git a/src/plugins/coreplugin/html/recent_sessions.html b/src/plugins/coreplugin/html/recent_sessions.html
new file mode 100644
index 0000000000..d2f6f2a596
--- /dev/null
+++ b/src/plugins/coreplugin/html/recent_sessions.html
@@ -0,0 +1,43 @@
+ <div class="rc_box rec_sess_container">
+ <div class="rec_sess_box">
+ <!-- top -->
+ <div class="top">
+ <div class="left"></div>
+ <div class="right"></div>
+ <div class="mid"></div>
+ </div>
+
+ <!-- mid -->
+ <div class="mid">
+
+ <div class="mid">
+
+ <div class="icon">
+ <img src="images/mode_Project.png"></img>
+ </div>
+ <div class="box_content">
+ <h2>Recent Sessions</h2>
+ <ul>
+ <!-- RECENT SESSIONS LIST -->
+ <!--<li><p><a href="#">Session 1</a></p></li>
+ <li><p><a href="#">Session 2</a></p></li>
+ <li><p><a href="#">Session 3</a></p></li>
+ <li><p><a href="#">Session 4</a></p></li>-->
+ </ul>
+
+ <a class="restore_session img_link" href="gh-session:LAST_SESSION">&nbsp;</a>
+ <div class="clear_right"></div>
+ </div>
+
+ </div>
+
+ </div>
+
+ <!-- bottom -->
+ <div class="bottom">
+ <div class="left"></div>
+ <div class="right"></div>
+ <div class="mid"></div>
+ </div>
+ </div>
+ </div>
diff --git a/src/plugins/coreplugin/html/welcome.html b/src/plugins/coreplugin/html/welcome.html
new file mode 100644
index 0000000000..40cdafe812
--- /dev/null
+++ b/src/plugins/coreplugin/html/welcome.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+ <title>Nokia, Qt Software</title>
+ <!--<meta name="expires" content="0">-->
+
+ <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+
+ <link rel="stylesheet" type="text/css" href="qt.css">
+ <script type="text/javascript">
+ var preloadImg01 = new Image();
+ preloadImg01.src = "images/btn_getting_started_hover.png";
+ var preloadImg02 = new Image();
+ preloadImg02.src = "images/btn_restore_session_hover.png";
+ </script>
+</head>
+<body>
+ <div class="global_container">
+ <!-- Obere dunkelgraue Zeile "Welcome" -->
+ <!-- <div class="site_header">
+ <p>Welcome</p>
+ </div>
+ -->
+
+ <!-- Content START -->
+ <!-- Zentrierung des Contents -->
+ <div class="content_container">
+ <!-- TOP - Logo und Welcome Text -->
+ <div class="layout_top">
+ <div class="product_logo">
+ <img src="images/product_logo.png" alt="product_logo"></img>
+ </div>
+ <div class="welcome_text">
+ <h1>Welcome</h1>
+ <p>Qt Creator is an intuitive, modern cross platform IDE that enables
+ developers to create graphically appealing applications for desktop,
+ embedded, and mobile devices. Click on <strong>Getting Started</strong> to
+ begin developing with Qt Creator.</p>
+ <!--<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
+ <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>-->
+ <div class="get_started_container">
+
+ <a class="btn_getting_started img_link" href="gh:getting-started">&nbsp;</a>
+ <div class="clear_right"></div>
+
+ </div>
+ </div>
+ </div>
+
+ <!-- BOTTOM - Recent Projects und Recent Sessions -->
+ <div class="layout_bottom">
+
+ <!-- RECENT PROJECTS -->
+
+
+ <!-- RECENT SESSIONS -->
+
+
+ <!-- clear floating of sessions and projects -->
+ <div class="clear_left"></div>
+
+ </div>
+ <!-- Layout Bottom END -->
+
+ </div>
+
+ <!-- Content END -->
+
+ </div>
+ <ul class="footer">
+ <li class="right-logo"/>
+ <li class="left-logo"/>
+ </ul>
+</body>
diff --git a/src/plugins/coreplugin/icontext.h b/src/plugins/coreplugin/icontext.h
new file mode 100644
index 0000000000..a873afb4c5
--- /dev/null
+++ b/src/plugins/coreplugin/icontext.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ICONTEXT_H
+#define ICONTEXT_H
+
+#include <coreplugin/core_global.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class CORE_EXPORT IContext : public QObject
+{
+ Q_OBJECT
+public:
+ IContext(QObject *parent = 0) : QObject(parent) {}
+ virtual ~IContext() {}
+
+ virtual QList<int> context() const = 0;
+ virtual QWidget *widget() = 0;
+ virtual QString contextHelpId() const { return QString(); }
+};
+
+} // namespace Core
+
+#endif //ICONTEXT_H
diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h
new file mode 100644
index 0000000000..ad85e4be18
--- /dev/null
+++ b/src/plugins/coreplugin/icore.h
@@ -0,0 +1,134 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef ICORE_H
+#define ICORE_H
+
+#include "core_global.h"
+#include <extensionsystem/pluginmanager.h>
+#include <QtCore/QObject>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+class QStatusBar;
+class QFocusEvent;
+class QMainWindow;
+class QPrinter;
+QT_END_NAMESPACE
+
+namespace Core {
+
+// forward declarations
+class ActionManagerInterface;
+class IFile;
+class FileManager;
+class MessageManager;
+class IEditor;
+class UniqueIDManager;
+class ViewManagerInterface;
+class EditorManager;
+class ProgressManagerInterface;
+class ScriptManagerInterface;
+class VariableManager;
+class IContext;
+class VCSManager;
+class ModeManager;
+class IWizard;
+class MimeDatabase;
+
+class CORE_EXPORT ICore : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ ICore() {}
+ virtual ~ICore() {}
+
+ virtual QStringList showNewItemDialog(const QString &title,
+ const QList<IWizard *> &wizards,
+ const QString &defaultLocation = QString()) = 0;
+
+ virtual void showOptionsDialog(const QString &group = QString(),
+ const QString &page = QString()) = 0;
+
+ virtual ActionManagerInterface *actionManager() const = 0;
+ virtual FileManager *fileManager() const = 0;
+ virtual UniqueIDManager *uniqueIDManager() const = 0;
+ virtual MessageManager *messageManager() const = 0;
+ virtual ViewManagerInterface *viewManager() const = 0;
+ virtual ExtensionSystem::PluginManager *pluginManager() const = 0;
+ virtual EditorManager *editorManager() const = 0;
+ virtual ProgressManagerInterface *progressManager() const = 0;
+ virtual ScriptManagerInterface *scriptManager() const = 0;
+ virtual VariableManager *variableManager() const = 0;
+ virtual VCSManager *vcsManager() const = 0;
+ virtual ModeManager *modeManager() const = 0;
+ virtual MimeDatabase *mimeDatabase() const = 0;
+
+ virtual QSettings *settings() const = 0;
+ virtual QPrinter *printer() const = 0;
+
+ virtual QString resourcePath() const = 0;
+ virtual QString libraryPath() const = 0;
+
+ virtual IContext *currentContextObject() const = 0;
+
+ virtual QMainWindow *mainWindow() const = 0;
+ virtual QStatusBar *statusBar() const = 0;
+
+ // adds and removes additional active contexts, this context is appended to the
+ // currently active contexts. call updateContext after changing
+ virtual void addAdditionalContext(int context) = 0;
+ virtual void removeAdditionalContext(int context) = 0;
+ virtual bool hasContext(int context) const = 0;
+ virtual void addContextObject(IContext *contex) = 0;
+ virtual void removeContextObject(IContext *contex) = 0;
+
+ virtual void updateContext() = 0;
+
+ virtual void openFiles(const QStringList &fileNames) = 0;
+
+signals:
+ void coreOpened();
+ void saveSettingsRequested();
+ void settingsDialogRequested();
+ void coreAboutToClose();
+ void contextAboutToChange(Core::IContext *context);
+ void contextChanged(Core::IContext *context);
+};
+
+} // namespace Core
+
+#endif //ICORE_H
diff --git a/src/plugins/coreplugin/icorelistener.h b/src/plugins/coreplugin/icorelistener.h
new file mode 100644
index 0000000000..3ff0a859a1
--- /dev/null
+++ b/src/plugins/coreplugin/icorelistener.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ICORELISTENER_H
+#define ICORELISTENER_H
+
+#include "core_global.h"
+#include <coreplugin/editormanager/ieditor.h>
+#include <QtCore/QObject>
+
+namespace Core {
+
+/*!
+ \class Core::ICoreListener
+ \brief Provides a hook for plugins to veto on certain events emitted from the core plugin.
+
+ You implement this interface if you want to prevent certain events from occurring, e.g.
+ if you want to prevent the closing of the whole application or to prevent the closing
+ of an editor window under certain conditions.
+
+ If e.g. the application window requests a close, then first
+ ICoreListener::coreAboutToClose() is called (in arbitrary order)
+ on all registered objects implementing this interface. If one if these calls returns
+ false, the process is aborted and the event is ignored.
+ If all calls return true, the corresponding signal is emitted and the event is accepted/performed.
+
+ Guidelines for implementing:
+ \list
+ \o Return false from the implemented method if you want to prevent the event.
+ \o You need to add your implementing object to the plugin managers objects:
+ ICore::pluginManager()->addObject(yourImplementingObject);
+ \o Don't forget to remove the object again at deconstruction (e.g. in the destructor of
+ your plugin).
+*/
+class CORE_EXPORT ICoreListener : public QObject
+{
+ Q_OBJECT
+public:
+ ICoreListener(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ICoreListener() {}
+
+ virtual bool editorAboutToClose(IEditor * /*editor*/) { return true; }
+ virtual bool coreAboutToClose() { return true; }
+};
+
+} // namespace Core
+
+#endif // ICORELISTENER_H
diff --git a/src/plugins/coreplugin/ifile.h b/src/plugins/coreplugin/ifile.h
new file mode 100644
index 0000000000..40a03b484e
--- /dev/null
+++ b/src/plugins/coreplugin/ifile.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IFILE_H
+#define IFILE_H
+
+#include "core_global.h"
+#include <QtCore/QObject>
+
+namespace Core {
+
+class MimeType;
+
+class CORE_EXPORT IFile : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ReloadBehavior { AskForReload, ReloadAll, ReloadPermissions, ReloadNone };
+
+ IFile(QObject *parent = 0) : QObject(parent) {}
+ virtual ~IFile() {}
+
+ virtual bool save(const QString &fileName = QString()) = 0;
+ virtual QString fileName() const = 0;
+
+ virtual QString defaultPath() const = 0;
+ virtual QString suggestedFileName() const = 0;
+ virtual QString mimeType() const = 0;
+
+ virtual bool isModified() const = 0;
+ virtual bool isReadOnly() const = 0;
+ virtual bool isSaveAsAllowed() const = 0;
+
+ virtual void modified(ReloadBehavior *behavior) = 0;
+
+signals:
+ void changed();
+};
+
+} //namespace
+
+#endif //IFILE_H
diff --git a/src/plugins/coreplugin/ifilefactory.h b/src/plugins/coreplugin/ifilefactory.h
new file mode 100644
index 0000000000..e8dcf155e1
--- /dev/null
+++ b/src/plugins/coreplugin/ifilefactory.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IFILEFACTORY_H
+#define IFILEFACTORY_H
+
+#include "core_global.h"
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class IFile;
+
+class CORE_EXPORT IFileFactory : public QObject
+{
+ Q_OBJECT
+public:
+ IFileFactory(QObject *parent = 0) : QObject(parent) {}
+ virtual ~IFileFactory() {}
+
+ virtual QStringList mimeTypes() const = 0;
+
+ virtual QString kind() const = 0;
+ virtual Core::IFile *open(const QString &fileName) = 0;
+};
+
+} // namespace Core
+
+#endif // IFILEFACTORY_H
diff --git a/src/plugins/coreplugin/ifilewizardextension.h b/src/plugins/coreplugin/ifilewizardextension.h
new file mode 100644
index 0000000000..238d628a78
--- /dev/null
+++ b/src/plugins/coreplugin/ifilewizardextension.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IFILEWIZARDEXTENSION_H
+#define IFILEWIZARDEXTENSION_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QWizardPage;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class IWizard;
+class GeneratedFile;
+
+/*!
+ Hook to add generic wizard pages to implementations of IWizard.
+ Used e.g. to add "Add to Project File/Add to version control" page
+ */
+class CORE_EXPORT IFileWizardExtension : public QObject
+{
+ Q_OBJECT
+public:
+ /* Return a list of pages to be added to the Wizard (empty list if not
+ * applicable). */
+ virtual QList<QWizardPage *> extensionPages(const IWizard *wizard) = 0;
+
+ /* Process the files using the extension parameters */
+ virtual bool process(const QList<GeneratedFile> &files, QString *errorMessage) = 0;
+
+public slots:
+ /* Notification about the first extension page being shown. */
+ virtual void firstExtensionPageShown(const QList<GeneratedFile> &) {}
+};
+
+} // namespace Core
+
+#endif // IFILEWIZARDEXTENSION_H
diff --git a/src/plugins/coreplugin/images/clean_pane_small.png b/src/plugins/coreplugin/images/clean_pane_small.png
new file mode 100644
index 0000000000..341e23861a
--- /dev/null
+++ b/src/plugins/coreplugin/images/clean_pane_small.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/clear.png b/src/plugins/coreplugin/images/clear.png
new file mode 100644
index 0000000000..72279e1c69
--- /dev/null
+++ b/src/plugins/coreplugin/images/clear.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/closebutton.png b/src/plugins/coreplugin/images/closebutton.png
new file mode 100644
index 0000000000..c978cf51aa
--- /dev/null
+++ b/src/plugins/coreplugin/images/closebutton.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/dir.png b/src/plugins/coreplugin/images/dir.png
new file mode 100644
index 0000000000..57cec6bcd3
--- /dev/null
+++ b/src/plugins/coreplugin/images/dir.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/editcopy.png b/src/plugins/coreplugin/images/editcopy.png
new file mode 100644
index 0000000000..ceb520e305
--- /dev/null
+++ b/src/plugins/coreplugin/images/editcopy.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/editcut.png b/src/plugins/coreplugin/images/editcut.png
new file mode 100644
index 0000000000..700ccb0cfd
--- /dev/null
+++ b/src/plugins/coreplugin/images/editcut.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/editpaste.png b/src/plugins/coreplugin/images/editpaste.png
new file mode 100644
index 0000000000..7238fae7f1
--- /dev/null
+++ b/src/plugins/coreplugin/images/editpaste.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/empty14.png b/src/plugins/coreplugin/images/empty14.png
new file mode 100644
index 0000000000..7346e58082
--- /dev/null
+++ b/src/plugins/coreplugin/images/empty14.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/fancytoolbutton.svg b/src/plugins/coreplugin/images/fancytoolbutton.svg
new file mode 100644
index 0000000000..8c9c0f1d62
--- /dev/null
+++ b/src/plugins/coreplugin/images/fancytoolbutton.svg
@@ -0,0 +1,539 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="64"
+ height="64"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="fancytoolbutton.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:docbase="C:\depot\ide\research\modes\src\plugins\coreplugin\images"
+ style="display:inline">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3213">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.21969697;"
+ offset="0"
+ id="stop3215" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0530303;"
+ offset="1"
+ id="stop3217" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3227">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.13559322;"
+ offset="0"
+ id="stop3229" />
+ <stop
+ style="stop-color:#3a3a3a;stop-opacity:0.11016949;"
+ offset="1"
+ id="stop3231" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3284">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.62931037;"
+ offset="0"
+ id="stop3286" />
+ <stop
+ style="stop-color:#a3a3a3;stop-opacity:0;"
+ offset="1"
+ id="stop3288" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 32 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="64 : 32 : 1"
+ inkscape:persp3d-origin="32 : 21.333333 : 1"
+ id="perspective62" />
+ <linearGradient
+ id="linearGradient3299">
+ <stop
+ id="stop3301"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:0.31384614;" />
+ <stop
+ id="stop3303"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0.15686275;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3293">
+ <stop
+ id="stop3295"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3297"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0.02157165;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3218">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.78431374;"
+ offset="0"
+ id="stop3220" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3222" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3204">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="0"
+ id="stop3206" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.25098041;"
+ offset="1"
+ id="stop3208" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3162">
+ <stop
+ style="stop-color:#424242;stop-opacity:0.13793103;"
+ offset="0"
+ id="stop3164" />
+ <stop
+ style="stop-color:#f0f0f0;stop-opacity:0;"
+ offset="1"
+ id="stop3166" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3204"
+ id="linearGradient3210"
+ x1="32"
+ y1="32"
+ x2="32"
+ y2="61"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3218"
+ id="linearGradient3224"
+ x1="24"
+ y1="1.9999999"
+ x2="24"
+ y2="31.571428"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3162"
+ id="linearGradient3267"
+ gradientUnits="userSpaceOnUse"
+ x1="32"
+ y1="64"
+ x2="32"
+ y2="0" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3218"
+ id="linearGradient3271"
+ gradientUnits="userSpaceOnUse"
+ x1="24"
+ y1="1.9999999"
+ x2="24"
+ y2="31.571428" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3299"
+ id="radialGradient3283"
+ cx="32"
+ cy="32"
+ fx="32"
+ fy="32"
+ r="29"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3213"
+ id="radialGradient2210"
+ gradientUnits="userSpaceOnUse"
+ cx="32"
+ cy="32"
+ fx="32"
+ fy="32"
+ r="29"
+ gradientTransform="matrix(0.962963,0,0,0.9444445,1.1851851,1.7777776)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3218"
+ id="radialGradient4673"
+ cx="24"
+ cy="-2.0519459"
+ fx="24"
+ fy="-2.0519459"
+ r="18"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.8095239,-6.9383612e-8,5.1646454e-8,1.8333332,-19.428571,1.7619038)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3218"
+ id="radialGradient4675"
+ cx="24"
+ cy="-0.72727227"
+ fx="24"
+ fy="-0.72727227"
+ r="18"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.8095238,0,0,1.8333332,-19.42857,-1.6666668)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3227"
+ id="radialGradient3233"
+ cx="48.656292"
+ cy="51.519093"
+ fx="48.656292"
+ fy="51.519093"
+ r="29.444443"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#3e5e7e"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.6568542"
+ inkscape:cx="-11.541044"
+ inkscape:cy="27.695432"
+ inkscape:document-units="px"
+ inkscape:current-layer="LayerPressed"
+ showgrid="true"
+ inkscape:window-width="1551"
+ inkscape:window-height="972"
+ inkscape:window-x="103"
+ inkscape:window-y="25"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:grid-points="true"
+ inkscape:snap-nodes="true"
+ inkscape:snap-global="false"
+ inkscape:snap-intersection-grid-guide="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2388"
+ spacingx="0.5px"
+ spacingy="0.5px"
+ empspacing="4"
+ dotted="false"
+ enabled="true"
+ visible="false" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="32,44.910714"
+ id="guide3214" />
+ <sodipodi:guide
+ orientation="horizontal"
+ position="32.880465,29.521708"
+ id="guide2214" />
+ <inkscape:grid
+ id="GridFromPre046Settings"
+ type="xygrid"
+ originx="0px"
+ originy="0px"
+ spacingx="1px"
+ spacingy="1px"
+ color="#0000ff"
+ empcolor="#0000ff"
+ opacity="0.2"
+ empopacity="0.4"
+ empspacing="1"
+ visible="true"
+ enabled="false" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="45.749998,96.999996"
+ id="guide4677" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="69.999997,64.124997"
+ id="guide4679" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="14.437499,62"
+ id="guide4681" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <dc:date />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:publisher>
+ <dc:identifier />
+ <dc:source />
+ <dc:relation />
+ <dc:language />
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <dc:coverage />
+ <dc:description />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <cc:license
+ rdf:resource="" />
+ </cc:Work>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="LayerBase"
+ inkscape:label="LayerBase"
+ style="display:none">
+ <g
+ style="fill:none;stroke:url(#radialGradient3233);stroke-width:2.17741656;stroke-miterlimit:4;stroke-dasharray:none;display:inline"
+ id="ButtonBase"
+ transform="matrix(0.6792453,0,0,0.6792453,10.26415,10.26415)">
+ <path
+ d="M 61.444443,32 A 29.444443,29.444443 0 1 1 60.441148,24.379217"
+ sodipodi:ry="29.444443"
+ sodipodi:rx="29.444443"
+ sodipodi:cy="32"
+ sodipodi:cx="32"
+ id="path3257"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient3233);stroke-width:2.17741656;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc"
+ sodipodi:start="0"
+ sodipodi:end="6.0213859"
+ sodipodi:open="true" />
+ <path
+ transform="matrix(0.9498207,0,0,0.9498207,1.6057361,1.6057361)"
+ d="M 63,32 A 31,31 0 1 1 1,32 A 31,31 0 1 1 63,32 z"
+ sodipodi:ry="31"
+ sodipodi:rx="31"
+ sodipodi:cy="32"
+ sodipodi:cx="32"
+ id="path3259"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient3233);stroke-width:2.7574501;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.9,0,0,0.9,3.1999999,3.1999999)"
+ d="M 62,32 A 30,30 0 1 1 2,32 A 30,30 0 1 1 62,32 z"
+ sodipodi:ry="30"
+ sodipodi:rx="30"
+ sodipodi:cy="32"
+ sodipodi:cx="32"
+ id="path3281"
+ style="opacity:1;fill:none;fill-opacity:0.62672813;fill-rule:evenodd;stroke:#2b2b2b;stroke-width:1.92861104;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50228307"
+ sodipodi:type="arc" />
+ </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="LayerPressed"
+ inkscape:label="LayerPressed"
+ style="display:inline">
+ <g
+ id="ButtonPressedBase"
+ transform="matrix(0.6792453,0,0,0.6792453,10.26415,10.26415)">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4724"
+ width="64"
+ height="64"
+ x="0"
+ y="0" />
+ <path
+ transform="matrix(0.9310345,0,0,0.9310345,2.2068967,2.2068968)"
+ d="M 61,32 A 29,29 0 1 1 3,32 A 29,29 0 1 1 61,32 z"
+ sodipodi:ry="29"
+ sodipodi:rx="29"
+ sodipodi:cy="32"
+ sodipodi:cx="32"
+ id="path3263"
+ style="opacity:1;fill:url(#radialGradient2210);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(1.4166666,0,0,1.4027778,-1.9999995,3.1944446)"
+ d="M 42,20 A 18,18 0 1 1 6,20 A 18,18 0 1 1 42,20 z"
+ sodipodi:ry="18"
+ sodipodi:rx="18"
+ sodipodi:cy="20"
+ sodipodi:cx="24"
+ id="path3209"
+ style="opacity:1;fill:#ffffff;fill-opacity:0;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ sodipodi:type="arc" />
+ </g>
+ <g
+ id="ButtonPressedOverlay"
+ transform="matrix(0.6792453,0,0,0.6792453,10.26415,12.739024)"
+ style="opacity:0.56682028">
+ <rect
+ y="0"
+ x="0"
+ height="64"
+ width="64"
+ id="rect3182"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.47465436999999999;fill:url(#radialGradient4675);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ id="path3226"
+ sodipodi:cx="24"
+ sodipodi:cy="20"
+ sodipodi:rx="18"
+ sodipodi:ry="18"
+ d="M 42,20 A 18,18 0 1 1 6,20 A 18,18 0 1 1 42,20 z"
+ transform="matrix(1.1666668,0,0,1,3.9999975,4.9999993)" />
+ </g>
+ </g>
+ <g
+ inkscape:label="LayerNormal"
+ inkscape:groupmode="layer"
+ id="LayerNormal"
+ style="display:none">
+ <g
+ style="display:inline"
+ id="ButtonNormalBase"
+ transform="matrix(0.6792453,0,0,0.7011564,10.26415,10.26415)">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4730"
+ width="64"
+ height="64"
+ x="0"
+ y="0"
+ ry="0" />
+ <path
+ transform="matrix(1.4722222,0,0,1.4444445,-3.3333336,2.1111101)"
+ d="M 42,20 A 18,18 0 1 1 6,20 A 18,18 0 1 1 42,20 z"
+ sodipodi:ry="18"
+ sodipodi:rx="18"
+ sodipodi:cy="20"
+ sodipodi:cx="24"
+ id="path4734"
+ style="opacity:1;fill:#ffffff;fill-opacity:0.1254902;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ sodipodi:type="arc" />
+ </g>
+ <g
+ id="ButtonNormalOverlay"
+ style="display:inline"
+ transform="matrix(0.6792453,0,0,0.6792453,10.528302,9.6981123)">
+ <rect
+ ry="0"
+ y="0"
+ x="0"
+ height="64"
+ width="64"
+ id="rect2202"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:url(#radialGradient4673);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3188"
+ sodipodi:cx="24"
+ sodipodi:cy="20"
+ sodipodi:rx="18"
+ sodipodi:ry="18"
+ d="M 42,20 A 18,18 0 1 1 6,20 A 18,18 0 1 1 42,20 z"
+ transform="matrix(1.1666667,0,0,1.0000001,3.9999997,3.9999987)" />
+ </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="LayerDisabled"
+ inkscape:label="LayerDisabled"
+ style="display:none">
+ <g
+ id="ButtonDisabledOverlay"
+ transform="matrix(0.6792453,0,0,0.6792453,10.26415,10.26415)">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2247"
+ width="64"
+ height="64"
+ x="0"
+ y="0"
+ ry="0" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:#808080;fill-opacity:0.17351595;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2250"
+ sodipodi:cx="32"
+ sodipodi:cy="32"
+ sodipodi:rx="30"
+ sodipodi:ry="30"
+ d="M 62,32 A 30,30 0 1 1 2,32 A 30,30 0 1 1 62,32 z"
+ transform="matrix(0.9,0,0,0.9,3.2,3.2)" />
+ </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="LayerButtonHover"
+ inkscape:label="LayerButtonHover"
+ style="display:none">
+ <g
+ id="ButtonHoverOverlay"
+ transform="matrix(0.6792453,0,0,0.6792453,10.26415,10.26415)">
+ <rect
+ ry="0"
+ y="0"
+ x="0"
+ height="64"
+ width="64"
+ id="rect2209"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ transform="matrix(0.9,0,0,0.9,3.2,3.2)"
+ d="M 62,32 A 30,30 0 1 1 2,32 A 30,30 0 1 1 62,32 z"
+ sodipodi:ry="30"
+ sodipodi:rx="30"
+ sodipodi:cy="32"
+ sodipodi:cx="32"
+ id="path2211"
+ style="opacity:1;fill:#ffffff;fill-opacity:0.04020099;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </g>
+ </g>
+</svg>
diff --git a/src/plugins/coreplugin/images/filenew.png b/src/plugins/coreplugin/images/filenew.png
new file mode 100644
index 0000000000..dd795cfffc
--- /dev/null
+++ b/src/plugins/coreplugin/images/filenew.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/fileopen.png b/src/plugins/coreplugin/images/fileopen.png
new file mode 100644
index 0000000000..58d70149e9
--- /dev/null
+++ b/src/plugins/coreplugin/images/fileopen.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/filesave.png b/src/plugins/coreplugin/images/filesave.png
new file mode 100644
index 0000000000..604ee3b834
--- /dev/null
+++ b/src/plugins/coreplugin/images/filesave.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/find.png b/src/plugins/coreplugin/images/find.png
new file mode 100644
index 0000000000..cbe2f31521
--- /dev/null
+++ b/src/plugins/coreplugin/images/find.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/findnext.png b/src/plugins/coreplugin/images/findnext.png
new file mode 100644
index 0000000000..a2889e439f
--- /dev/null
+++ b/src/plugins/coreplugin/images/findnext.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/inputfield.png b/src/plugins/coreplugin/images/inputfield.png
new file mode 100644
index 0000000000..8020c8f731
--- /dev/null
+++ b/src/plugins/coreplugin/images/inputfield.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/inputfield_disabled.png b/src/plugins/coreplugin/images/inputfield_disabled.png
new file mode 100644
index 0000000000..c69f082f08
--- /dev/null
+++ b/src/plugins/coreplugin/images/inputfield_disabled.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/linkicon.png b/src/plugins/coreplugin/images/linkicon.png
new file mode 100644
index 0000000000..864f36f174
--- /dev/null
+++ b/src/plugins/coreplugin/images/linkicon.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/locked.png b/src/plugins/coreplugin/images/locked.png
new file mode 100644
index 0000000000..0ff602714e
--- /dev/null
+++ b/src/plugins/coreplugin/images/locked.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/magnifier.png b/src/plugins/coreplugin/images/magnifier.png
new file mode 100644
index 0000000000..0e652c945e
--- /dev/null
+++ b/src/plugins/coreplugin/images/magnifier.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/minus.png b/src/plugins/coreplugin/images/minus.png
new file mode 100644
index 0000000000..4466844662
--- /dev/null
+++ b/src/plugins/coreplugin/images/minus.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/mode_Debug.png b/src/plugins/coreplugin/images/mode_Debug.png
new file mode 100644
index 0000000000..e6ab1e40e3
--- /dev/null
+++ b/src/plugins/coreplugin/images/mode_Debug.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/mode_Edit.png b/src/plugins/coreplugin/images/mode_Edit.png
new file mode 100644
index 0000000000..c43fd4251a
--- /dev/null
+++ b/src/plugins/coreplugin/images/mode_Edit.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/mode_Output.png b/src/plugins/coreplugin/images/mode_Output.png
new file mode 100644
index 0000000000..25e403c780
--- /dev/null
+++ b/src/plugins/coreplugin/images/mode_Output.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/mode_Project.png b/src/plugins/coreplugin/images/mode_Project.png
new file mode 100644
index 0000000000..20f54e786b
--- /dev/null
+++ b/src/plugins/coreplugin/images/mode_Project.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/mode_Reference.png b/src/plugins/coreplugin/images/mode_Reference.png
new file mode 100644
index 0000000000..7d6a46a48a
--- /dev/null
+++ b/src/plugins/coreplugin/images/mode_Reference.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/next.png b/src/plugins/coreplugin/images/next.png
new file mode 100644
index 0000000000..7700d6fce6
--- /dev/null
+++ b/src/plugins/coreplugin/images/next.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/panel_button.png b/src/plugins/coreplugin/images/panel_button.png
new file mode 100644
index 0000000000..a101043f41
--- /dev/null
+++ b/src/plugins/coreplugin/images/panel_button.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/panel_button_checked.png b/src/plugins/coreplugin/images/panel_button_checked.png
new file mode 100644
index 0000000000..fd7753bceb
--- /dev/null
+++ b/src/plugins/coreplugin/images/panel_button_checked.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/panel_button_checked_hover.png b/src/plugins/coreplugin/images/panel_button_checked_hover.png
new file mode 100644
index 0000000000..045c23aa02
--- /dev/null
+++ b/src/plugins/coreplugin/images/panel_button_checked_hover.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/panel_button_hover.png b/src/plugins/coreplugin/images/panel_button_hover.png
new file mode 100644
index 0000000000..54e2d2b3a5
--- /dev/null
+++ b/src/plugins/coreplugin/images/panel_button_hover.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/panel_button_pressed.png b/src/plugins/coreplugin/images/panel_button_pressed.png
new file mode 100644
index 0000000000..b92a1dda0c
--- /dev/null
+++ b/src/plugins/coreplugin/images/panel_button_pressed.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/plus.png b/src/plugins/coreplugin/images/plus.png
new file mode 100644
index 0000000000..be8c961df1
--- /dev/null
+++ b/src/plugins/coreplugin/images/plus.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/prev.png b/src/plugins/coreplugin/images/prev.png
new file mode 100644
index 0000000000..99dc8733c7
--- /dev/null
+++ b/src/plugins/coreplugin/images/prev.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/pushbutton.png b/src/plugins/coreplugin/images/pushbutton.png
new file mode 100644
index 0000000000..a9efaf2522
--- /dev/null
+++ b/src/plugins/coreplugin/images/pushbutton.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/pushbutton_hover.png b/src/plugins/coreplugin/images/pushbutton_hover.png
new file mode 100644
index 0000000000..910f6980b1
--- /dev/null
+++ b/src/plugins/coreplugin/images/pushbutton_hover.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/pushbutton_pressed.png b/src/plugins/coreplugin/images/pushbutton_pressed.png
new file mode 100644
index 0000000000..7a5a4768ff
--- /dev/null
+++ b/src/plugins/coreplugin/images/pushbutton_pressed.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtcreator_logo_128.png b/src/plugins/coreplugin/images/qtcreator_logo_128.png
new file mode 100644
index 0000000000..c3ddf74c74
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtcreator_logo_128.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtcreator_logo_16.png b/src/plugins/coreplugin/images/qtcreator_logo_16.png
new file mode 100644
index 0000000000..6e48e979b8
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtcreator_logo_16.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtcreator_logo_24.png b/src/plugins/coreplugin/images/qtcreator_logo_24.png
new file mode 100644
index 0000000000..797fc705a9
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtcreator_logo_24.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtcreator_logo_32.png b/src/plugins/coreplugin/images/qtcreator_logo_32.png
new file mode 100644
index 0000000000..992620b8ae
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtcreator_logo_32.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtcreator_logo_48.png b/src/plugins/coreplugin/images/qtcreator_logo_48.png
new file mode 100644
index 0000000000..4bedd55219
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtcreator_logo_48.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtcreator_logo_64.png b/src/plugins/coreplugin/images/qtcreator_logo_64.png
new file mode 100644
index 0000000000..88a11abf6e
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtcreator_logo_64.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/qtwatermark.png b/src/plugins/coreplugin/images/qtwatermark.png
new file mode 100644
index 0000000000..d5eec355dc
--- /dev/null
+++ b/src/plugins/coreplugin/images/qtwatermark.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/redo.png b/src/plugins/coreplugin/images/redo.png
new file mode 100644
index 0000000000..9d679fe6fc
--- /dev/null
+++ b/src/plugins/coreplugin/images/redo.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/replace.png b/src/plugins/coreplugin/images/replace.png
new file mode 100644
index 0000000000..baa05997bc
--- /dev/null
+++ b/src/plugins/coreplugin/images/replace.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/reset.png b/src/plugins/coreplugin/images/reset.png
new file mode 100644
index 0000000000..cc0d6a26bd
--- /dev/null
+++ b/src/plugins/coreplugin/images/reset.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/sidebaricon.png b/src/plugins/coreplugin/images/sidebaricon.png
new file mode 100644
index 0000000000..8aab325d6e
--- /dev/null
+++ b/src/plugins/coreplugin/images/sidebaricon.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/splitbutton_horizontal.png b/src/plugins/coreplugin/images/splitbutton_horizontal.png
new file mode 100644
index 0000000000..7b5f493758
--- /dev/null
+++ b/src/plugins/coreplugin/images/splitbutton_horizontal.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/statusbar.png b/src/plugins/coreplugin/images/statusbar.png
new file mode 100644
index 0000000000..dd426ef78f
--- /dev/null
+++ b/src/plugins/coreplugin/images/statusbar.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/undo.png b/src/plugins/coreplugin/images/undo.png
new file mode 100644
index 0000000000..eee23d24a3
--- /dev/null
+++ b/src/plugins/coreplugin/images/undo.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/unknownfile.png b/src/plugins/coreplugin/images/unknownfile.png
new file mode 100644
index 0000000000..88f77592d1
--- /dev/null
+++ b/src/plugins/coreplugin/images/unknownfile.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/unlocked.png b/src/plugins/coreplugin/images/unlocked.png
new file mode 100644
index 0000000000..72f659d098
--- /dev/null
+++ b/src/plugins/coreplugin/images/unlocked.png
Binary files differ
diff --git a/src/plugins/coreplugin/imode.h b/src/plugins/coreplugin/imode.h
new file mode 100644
index 0000000000..080b5d9be0
--- /dev/null
+++ b/src/plugins/coreplugin/imode.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IMODE_H
+#define IMODE_H
+
+#include "icontext.h"
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QObject>
+#include <QtGui/QIcon>
+#include <QtGui/QKeySequence>
+#include <QtGui/QLayout>
+
+namespace Core {
+
+class CORE_EXPORT IMode : public IContext
+{
+ Q_OBJECT
+public:
+ IMode(QObject *parent = 0) : IContext(parent) {}
+ virtual ~IMode() {}
+
+ virtual QString name() const = 0;
+ virtual QIcon icon() const = 0;
+ virtual int priority() const = 0;
+ virtual const char *uniqueModeName() const = 0;
+};
+
+} // namespace Core
+
+#endif // IMODE_H
diff --git a/src/plugins/coreplugin/inavigationwidgetfactory.cpp b/src/plugins/coreplugin/inavigationwidgetfactory.cpp
new file mode 100644
index 0000000000..74772c4cc9
--- /dev/null
+++ b/src/plugins/coreplugin/inavigationwidgetfactory.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "inavigationwidgetfactory.h"
+
+using namespace Core;
+
+INavigationWidgetFactory::INavigationWidgetFactory()
+{
+
+}
+
+INavigationWidgetFactory::~INavigationWidgetFactory()
+{
+
+}
+
+QKeySequence INavigationWidgetFactory::activationSequence()
+{
+ return QKeySequence();
+}
+
diff --git a/src/plugins/coreplugin/inavigationwidgetfactory.h b/src/plugins/coreplugin/inavigationwidgetfactory.h
new file mode 100644
index 0000000000..f182f3acca
--- /dev/null
+++ b/src/plugins/coreplugin/inavigationwidgetfactory.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INAVIGATIONWIDGET_H
+#define INAVIGATIONWIDGET_H
+
+#include <coreplugin/core_global.h>
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtGui/QKeySequence>
+
+QT_BEGIN_NAMESPACE
+class QToolButton;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+
+struct NavigationView {
+ QWidget *widget;
+ QList<QToolButton *> doockToolBarWidgets;
+};
+
+class CORE_EXPORT INavigationWidgetFactory : public QObject
+{
+ Q_OBJECT
+public:
+ INavigationWidgetFactory();
+ virtual ~INavigationWidgetFactory();
+
+ virtual QString displayName() = 0;
+ virtual QKeySequence activationSequence();
+ // This design is not optimal, think about it again once we need to extend it
+ // It could be implemented as returning an object which has both the widget
+ // and the docktoolbar widgets
+ // Similar to how IView
+ virtual NavigationView createWidget() = 0;
+};
+}
+
+#endif // INAVIGATIONWIDGET_H
diff --git a/src/plugins/coreplugin/ioutputpane.h b/src/plugins/coreplugin/ioutputpane.h
new file mode 100644
index 0000000000..9847c1a1b2
--- /dev/null
+++ b/src/plugins/coreplugin/ioutputpane.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IOUTPUTPANE_H
+#define IOUTPUTPANE_H
+
+#include "core_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtGui/QWidget>
+
+namespace Core {
+
+class CORE_EXPORT IOutputPane : public QObject
+{
+ Q_OBJECT
+public:
+ IOutputPane(QObject *parent = 0) : QObject(parent) {}
+ virtual ~IOutputPane() {}
+
+ virtual QWidget *outputWidget(QWidget *parent) = 0;
+ virtual QList<QWidget*> toolBarWidgets(void) const = 0;
+ virtual QString name() const = 0;
+
+ // -1 don't show in statusBar
+ // 100...0 show at front...end
+ virtual int priorityInStatusBar() const = 0;
+
+ virtual void clearContents() = 0;
+ virtual void visibilityChanged(bool visible) = 0;
+
+ // This function is called to give the outputwindow focus
+ virtual void setFocus() = 0;
+ // Wheter the outputpane has focus
+ virtual bool hasFocus() = 0;
+ // Wheter the outputpane can be focused at the moment.
+ // (E.g. the search result window doesn't want to be focussed if the are no results.)
+ virtual bool canFocus() = 0;
+public slots:
+ void popup()
+ {
+ popup(true);
+ }
+ void popup(bool withFocus)
+ {
+ emit showPage(withFocus);
+ }
+
+ void hide()
+ {
+ emit hidePage();
+ }
+
+ void toggle()
+ {
+ toggle(true);
+ }
+
+ void toggle(bool withFocusIfShown)
+ {
+ emit togglePage(withFocusIfShown);
+ }
+
+signals:
+ void showPage(bool withFocus);
+ void hidePage();
+ void togglePage(bool withFocusIfShown);
+};
+
+} // namespace Core
+
+#endif // IOUTPUTPANE_H
diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h
new file mode 100644
index 0000000000..e2d3de1ec3
--- /dev/null
+++ b/src/plugins/coreplugin/iversioncontrol.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IVERSIONCONTROL_H
+#define IVERSIONCONTROL_H
+
+#include "core_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace Core {
+
+class CORE_EXPORT IVersionControl : public QObject
+{
+ Q_OBJECT
+public:
+ IVersionControl(QObject *parent = 0) : QObject(parent) {}
+ virtual ~IVersionControl() {}
+
+ // Returns wheter files in this directory should be managed with this
+ // version control.
+ 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;
+
+ // Called prior to save, if the file is read only.
+ // Should be implemented if the scc requires a operation before editing the file
+ // E.g. p4 edit
+ // Note: The EditorManager calls this for the editors
+ virtual bool vcsOpen(const QString &fileName) = 0;
+
+ // Called after a file has been added to a project
+ // If the version control needs to know which files it needs to track
+ // you should reimplement this function
+ // E.g. p4 add, cvs add, svn add
+ // Note: This function should be called from IProject subclasses after files
+ // are added to the project
+ virtual bool vcsAdd(const QString &filename) = 0;
+
+ // Called after a file has been removed from the project (if the user wants)
+ // E.g. p4 delete, svn delete
+ // You probably want to call SccManager::showDeleteDialog, which asks the user to
+ // confirm the deletion
+ virtual bool vcsDelete(const QString &filename) = 0;
+
+ // TODO: ADD A WAY TO DETECT WHETHER A FILE IS MANAGED, e.g
+ // virtual bool sccManaged(const QStryng &filename) = 0;
+
+ // TODO
+ // we probably want to have a function supports( enum Operation ) or
+ // something which describes which "kind" of revision control system it is.
+ // That is to check wheter a given operation is needed.
+ // But well I don't know yet how all different version control systems work
+};
+
+} // namespace Core
+
+#endif // IVERSIONCONTROL_H
diff --git a/src/plugins/coreplugin/iview.h b/src/plugins/coreplugin/iview.h
new file mode 100644
index 0000000000..dd0a222b59
--- /dev/null
+++ b/src/plugins/coreplugin/iview.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IVIEW_H
+#define IVIEW_H
+
+#include "core_global.h"
+
+#include <QtGui/QKeySequence>
+
+#include <coreplugin/icontext.h>
+
+namespace Core {
+
+class CORE_EXPORT IView
+ : public IContext
+{
+ Q_OBJECT
+public:
+ enum ViewPosition { First=0, Second=1, Third=2 };
+
+ IView(QObject *parent = 0) : IContext(parent) {}
+ virtual ~IView() {}
+
+ virtual const char *uniqueViewName() const = 0;
+ virtual ViewPosition defaultPosition() const = 0;
+};
+
+} // namespace Core
+
+#endif // IVIEW_H
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
new file mode 100644
index 0000000000..a90f1ff14e
--- /dev/null
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -0,0 +1,1102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "mainwindow.h"
+#include "actioncontainer.h"
+#include "actionmanager.h"
+#include "basemode.h"
+#include "coreimpl.h"
+#include "coreconstants.h"
+#include "editorgroup.h"
+#include "editormanager.h"
+#include "fancytabwidget.h"
+#include "filemanager.h"
+#include "generalsettings.h"
+#include "ifilefactory.h"
+#include "messagemanager.h"
+#include "modemanager.h"
+#include "mimedatabase.h"
+#include "newdialog.h"
+#include "outputpane.h"
+#include "plugindialog.h"
+#include "progressmanager.h"
+#include "progressview.h"
+#include "shortcutsettings.h"
+#include "vcsmanager.h"
+#include "scriptmanager.h"
+#include "settingsdialog.h"
+#include "stylehelper.h"
+#include "variablemanager.h"
+#include "versiondialog.h"
+#include "viewmanager.h"
+#include "uniqueidmanager.h"
+#include "manhattanstyle.h"
+#include "dialogs/iwizard.h"
+#include "navigationwidget.h"
+#include "rightpane.h"
+#include "editormanager/ieditorfactory.h"
+#include "baseview.h"
+#include "basefilewizard.h"
+
+#include <coreplugin/findplaceholder.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtCore/QTimer>
+#include <QtCore/QFileInfo>
+
+#include <QtGui/QMenu>
+#include <QtGui/QToolBar>
+#include <QtGui/QApplication>
+#include <QtGui/QPixmap>
+#include <QtGui/QCloseEvent>
+#include <QtGui/QShortcut>
+#include <QtGui/QPrinter>
+#include <QtGui/QWizard>
+#include <QtGui/QStatusBar>
+
+/*
+#ifdef Q_OS_UNIX
+#include <signal.h>
+extern "C" void handleSigInt(int sig)
+{
+ Q_UNUSED(sig);
+ Core::Internal::CoreImpl::instance()->exit();
+ qDebug() << "SIGINT caught. Shutting down.";
+}
+#endif
+*/
+
+using namespace Core;
+using namespace Core::Internal;
+
+namespace {
+ enum { debugMainWindow = 0 };
+}
+
+
+MainWindow::MainWindow() :
+ QMainWindow(),
+ m_coreImpl(new CoreImpl(this)),
+ m_uniqueIDManager(new UniqueIDManager()),
+ m_globalContext(QList<int>() << Constants::C_GLOBAL_ID),
+ m_additionalContexts(m_globalContext),
+ m_settings(new QSettings(QSettings::IniFormat, QSettings::UserScope, QLatin1String("Nokia"), QLatin1String("QtCreator"), this)),
+ m_printer(0),
+ m_actionManager(new ActionManager(this, m_uniqueIDManager)),
+ m_editorManager(0),
+ m_fileManager(new FileManager(m_coreImpl, this)),
+ m_progressManager(new ProgressManager()),
+ m_scriptManager(new ScriptManager(this, m_coreImpl)),
+ m_variableManager(new VariableManager(this)),
+ m_vcsManager(new VCSManager()),
+ m_viewManager(0),
+ m_modeManager(0),
+ m_mimeDatabase(new MimeDatabase),
+ m_navigationWidget(0),
+ m_rightPaneWidget(0),
+ m_activeContext(0),
+ m_pluginManager(0),
+ m_outputPane(new OutputPane(m_globalContext)),
+ m_outputMode(0),
+ m_generalSettings(new GeneralSettings),
+ m_shortcutSettings(new ShortcutSettings),
+ m_focusToEditor(0),
+ m_newAction(0),
+ m_openAction(0),
+ m_openWithAction(0),
+ m_saveAllAction(0),
+ m_exitAction(0),
+ m_optionsAction(0),
+ m_toggleSideBarAction(0),
+#ifdef Q_OS_MAC
+ m_minimizeAction(0),
+ m_zoomAction(0),
+#endif
+ m_toggleSideBarButton(new QToolButton)
+{
+ setWindowTitle(tr("Qt Creator"));
+ qApp->setWindowIcon(QIcon(":/qworkbench/images/qtcreator_logo_128.png"));
+ setDockNestingEnabled(true);
+
+ setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
+ setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
+
+ registerDefaultContainers();
+ registerDefaultActions();
+
+ m_navigationWidget = new NavigationWidget(m_toggleSideBarAction);
+ m_rightPaneWidget = new RightPaneWidget();
+
+ m_modeStack = new FancyTabWidget(this);
+ m_modeManager = new ModeManager(this, m_modeStack);
+ m_modeManager->addWidget(m_progressManager->progressView());
+ m_viewManager = new ViewManager(this);
+ m_messageManager = new MessageManager;
+ m_editorManager = new EditorManager(m_coreImpl, this);
+ m_editorManager->hide();
+ setCentralWidget(m_modeStack);
+
+ connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)),
+ this, SLOT(updateFocusWidget(QWidget*,QWidget*)));
+ // Add a small Toolbutton for toggling the navigation widget
+ m_toggleSideBarButton->setProperty("type", QLatin1String("dockbutton"));
+ statusBar()->insertPermanentWidget(0, m_toggleSideBarButton);
+
+// setUnifiedTitleAndToolBarOnMac(true);
+#ifdef Q_OS_UNIX
+ //signal(SIGINT, handleSigInt);
+#endif
+
+ QCoreApplication::setApplicationName(QLatin1String("QtCreator"));
+ QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG));
+ QCoreApplication::setOrganizationName(QLatin1String("Nokia"));
+ QSettings::setDefaultFormat(QSettings::IniFormat);
+ QString baseName = qApp->style()->objectName();
+ qApp->setStyle(new ManhattanStyle(baseName));
+ statusBar()->setProperty("p_styled", true);
+}
+
+void MainWindow::toggleNavigation()
+{
+ if (NavigationWidgetPlaceHolder::current()) {
+ if (m_navigationWidget->isSuppressed()) {
+ m_navigationWidget->setShown(true);
+ m_navigationWidget->setSuppressed(false);
+ } else {
+ m_navigationWidget->setShown(!m_navigationWidget->isShown());
+ }
+ }
+}
+
+void MainWindow::setSuppressNavigationWidget(bool suppress)
+{
+ if (NavigationWidgetPlaceHolder::current()) {
+ m_navigationWidget->setSuppressed(suppress);
+ }
+}
+
+MainWindow::~MainWindow()
+{
+ hide();
+ m_pluginManager->removeObject(m_shortcutSettings);
+ m_pluginManager->removeObject(m_generalSettings);
+ delete m_messageManager;
+ m_messageManager = 0;
+ delete m_shortcutSettings;
+ m_shortcutSettings = 0;
+ delete m_generalSettings;
+ m_generalSettings = 0;
+ delete m_settings;
+ m_settings = 0;
+ delete m_printer;
+ m_printer = 0;
+ delete m_uniqueIDManager;
+ m_uniqueIDManager = 0;
+ delete m_vcsManager;
+ m_vcsManager = 0;
+ m_pluginManager->removeObject(m_outputMode);
+ delete m_outputMode;
+ m_outputMode = 0;
+ //we need to delete editormanager and viewmanager explicitly before the end of the destructor,
+ //because they might trigger stuff that tries to access data from editorwindow, like removeContextWidget
+
+ // All modes are now gone
+ delete OutputPane::instance();
+
+ // Now that the OutputPane is gone, is a good time to delete the view
+ m_pluginManager->removeObject(m_outputView);
+ delete m_outputView;
+
+ delete m_editorManager;
+ m_editorManager = 0;
+ delete m_viewManager;
+ m_viewManager = 0;
+ delete m_progressManager;
+ m_progressManager = 0;
+ m_pluginManager->removeObject(m_coreImpl);
+ delete m_coreImpl;
+ m_coreImpl = 0;
+
+ delete m_rightPaneWidget;
+ m_rightPaneWidget = 0;
+
+ delete m_navigationWidget;
+ m_navigationWidget = 0;
+
+ delete m_modeManager;
+ m_modeManager = 0;
+ delete m_mimeDatabase;
+ m_mimeDatabase = 0;
+}
+
+bool MainWindow::init(ExtensionSystem::PluginManager *pm, QString *)
+{
+ m_pluginManager = pm;
+ m_pluginManager->addObject(m_coreImpl);
+ m_viewManager->init();
+ m_modeManager->init();
+ m_progressManager->init();
+ QWidget *outputModeWidget = new QWidget;
+ outputModeWidget->setLayout(new QVBoxLayout);
+ outputModeWidget->layout()->setMargin(0);
+ outputModeWidget->layout()->setSpacing(0);
+ m_outputMode = new BaseMode(tr("Output"),
+ Constants::MODE_OUTPUT,
+ QIcon(QLatin1String(":/fancyactionbar/images/mode_Output.png")),
+ Constants::P_MODE_OUTPUT,
+ outputModeWidget);
+ OutputPanePlaceHolder *oph = new OutputPanePlaceHolder(m_outputMode);
+ oph->setVisible(true);
+ oph->setCloseable(false);
+ outputModeWidget->layout()->addWidget(oph);
+ outputModeWidget->layout()->addWidget(new Core::FindToolBarPlaceHolder(m_outputMode));
+ outputModeWidget->setFocusProxy(oph);
+
+ m_outputMode->setContext(m_outputPane->context());
+ m_pluginManager->addObject(m_outputMode);
+ m_pluginManager->addObject(m_generalSettings);
+ m_pluginManager->addObject(m_shortcutSettings);
+
+ // Add widget to the bottom, we create the view here instead of inside the OutputPane, since
+ // the ViewManager needs to be initilized before
+ m_outputView = new Core::BaseView("OutputWindow.Buttons", m_outputPane->buttonsWidget(), QList<int>(), Core::IView::Second);
+ m_pluginManager->addObject(m_outputView);
+ return true;
+}
+
+void MainWindow::extensionsInitialized()
+{
+ m_editorManager->init();
+
+ m_viewManager->extensionsInitalized();
+
+ m_messageManager->init(m_pluginManager);
+ m_outputPane->init(m_coreImpl, m_pluginManager);
+
+ m_actionManager->initialize();
+ readSettings();
+ updateContext();
+ show();
+
+ emit m_coreImpl->coreOpened();
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ emit m_coreImpl->saveSettingsRequested();
+
+ // Save opened files
+ bool cancelled;
+ fileManager()->saveModifiedFiles(fileManager()->modifiedFiles(), &cancelled);
+ if (cancelled) {
+ event->ignore();
+ return;
+ }
+
+ const QList<ICoreListener *> listeners =
+ pluginManager()->getObjects<ICoreListener>();
+ foreach (ICoreListener *listener, listeners) {
+ if (!listener->coreAboutToClose()) {
+ event->ignore();
+ return;
+ }
+ }
+
+ emit m_coreImpl->coreAboutToClose();
+ writeSettings();
+ event->accept();
+}
+
+IContext *MainWindow::currentContextObject() const
+{
+ return m_activeContext;
+}
+
+QStatusBar *MainWindow::statusBar() const
+{
+ return m_modeStack->statusBar();
+}
+
+void MainWindow::registerDefaultContainers()
+{
+ ActionManager *am = m_actionManager;
+
+ IActionContainer *menubar = m_actionManager->createMenuBar(Constants::MENU_BAR);
+
+#ifndef Q_WS_MAC // System menu bar on Mac
+ setMenuBar(menubar->menuBar());
+#endif
+ menubar->appendGroup(Constants::G_FILE);
+ menubar->appendGroup(Constants::G_EDIT);
+ menubar->appendGroup(Constants::G_VIEW);
+ menubar->appendGroup(Constants::G_TOOLS);
+ menubar->appendGroup(Constants::G_WINDOW);
+ menubar->appendGroup(Constants::G_HELP);
+
+ //File Menu
+ IActionContainer *filemenu = am->createMenu(Constants::M_FILE);
+ menubar->addMenu(filemenu, Constants::G_FILE);
+ filemenu->menu()->setTitle(tr("&File"));
+ filemenu->appendGroup(Constants::G_FILE_NEW);
+ filemenu->appendGroup(Constants::G_FILE_OPEN);
+ filemenu->appendGroup(Constants::G_FILE_PROJECT);
+ filemenu->appendGroup(Constants::G_FILE_SAVE);
+ filemenu->appendGroup(Constants::G_FILE_CLOSE);
+ filemenu->appendGroup(Constants::G_FILE_PRINT);
+ filemenu->appendGroup(Constants::G_FILE_OTHER);
+ connect(filemenu->menu(), SIGNAL(aboutToShow()), this, SLOT(aboutToShowRecentFiles()));
+
+
+ //Edit Menu
+ IActionContainer *medit = am->createMenu(Constants::M_EDIT);
+ menubar->addMenu(medit, Constants::G_EDIT);
+ medit->menu()->setTitle(tr("&Edit"));
+ medit->appendGroup(Constants::G_EDIT_UNDOREDO);
+ medit->appendGroup(Constants::G_EDIT_COPYPASTE);
+ medit->appendGroup(Constants::G_EDIT_SELECTALL);
+ medit->appendGroup(Constants::G_EDIT_FORMAT);
+ medit->appendGroup(Constants::G_EDIT_FIND, true);
+ medit->appendGroup(Constants::G_EDIT_OTHER);
+
+ //Tools Menu
+ IActionContainer *ac = am->createMenu(Constants::M_TOOLS);
+ menubar->addMenu(ac, Constants::G_TOOLS);
+ ac->menu()->setTitle(tr("&Tools"));
+
+ //Window Menu
+ IActionContainer *mwindow = am->createMenu(Constants::M_WINDOW);
+ menubar->addMenu(mwindow, Constants::G_WINDOW);
+ mwindow->menu()->setTitle(tr("&Window"));
+ mwindow->appendGroup(Constants::G_WINDOW_SIZE);
+ mwindow->appendGroup(Constants::G_WINDOW_PANES);
+ mwindow->appendGroup(Constants::G_WINDOW_SPLIT);
+ mwindow->appendGroup(Constants::G_WINDOW_CLOSE);
+ mwindow->appendGroup(Constants::G_WINDOW_NAVIGATE);
+ mwindow->appendGroup(Constants::G_WINDOW_NAVIGATE_GROUPS);
+ mwindow->appendGroup(Constants::G_WINDOW_OTHER);
+ mwindow->appendGroup(Constants::G_WINDOW_LIST, true);
+
+ //Help Menu
+ ac = am->createMenu(Constants::M_HELP);
+ menubar->addMenu(ac, Constants::G_HELP);
+ ac->menu()->setTitle(tr("&Help"));
+ ac->appendGroup(Constants::G_HELP_HELP, true);
+ ac->appendGroup(Constants::G_HELP_ABOUT, true);
+}
+
+static ICommand *createSeparator(ActionManager *am, QObject *parent,
+ const QString &name,
+ const QList<int> &context)
+{
+ QAction *tmpaction = new QAction(parent);
+ tmpaction->setSeparator(true);
+ ICommand *cmd = am->registerAction(tmpaction, name, context);
+ return cmd;
+}
+
+void MainWindow::registerDefaultActions()
+{
+ ActionManager *am = m_actionManager;
+ IActionContainer *mfile = am->actionContainer(Constants::M_FILE);
+ IActionContainer *medit = am->actionContainer(Constants::M_EDIT);
+ IActionContainer *mtools = am->actionContainer(Constants::M_TOOLS);
+ IActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
+ Q_UNUSED(mwindow)
+ IActionContainer *mhelp = am->actionContainer(Constants::M_HELP);
+
+ // File menu separators
+ ICommand *cmd = createSeparator(am, this, QLatin1String("QtCreator.File.Sep.Save"), m_globalContext);
+ mfile->addAction(cmd, Constants::G_FILE_SAVE);
+
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.File.Sep.Print"), m_globalContext);
+ mfile->addAction(cmd, Constants::G_FILE_PRINT);
+
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.File.Sep.Close"), m_globalContext);
+ mfile->addAction(cmd, Constants::G_FILE_CLOSE);
+
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.File.Sep.Other"), m_globalContext);
+ mfile->addAction(cmd, Constants::G_FILE_OTHER);
+
+ // Edit menu separators
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.CopyPaste"), m_globalContext);
+ medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
+
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.SelectAll"), m_globalContext);
+ medit->addAction(cmd, Constants::G_EDIT_SELECTALL);
+
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Find"), m_globalContext);
+ medit->addAction(cmd, Constants::G_EDIT_FIND);
+
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Format"), m_globalContext);
+ medit->addAction(cmd, Constants::G_EDIT_FORMAT);
+
+ //Tools menu separators
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.Tools.Sep.Options"), m_globalContext);
+ mtools->addAction(cmd, Constants::G_DEFAULT_THREE);
+
+ //Return to editor shortcut: Note this requires Qt to fix up
+ // handling of shortcut overrides in menus, item views, combos....
+ m_focusToEditor = new QShortcut(this);
+ cmd = am->registerShortcut(m_focusToEditor, Constants::S_RETURNTOEDITOR, m_globalContext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::Key_Escape));
+ connect(m_focusToEditor, SIGNAL(activated()), this, SLOT(setFocusToEditor()));
+
+ //New File Action
+ m_newAction = new QAction(QIcon(Constants::ICON_NEWFILE), tr("&New..."), this);
+ cmd = am->registerAction(m_newAction, Constants::NEW, m_globalContext);
+ cmd->setDefaultKeySequence(QKeySequence::New);
+ mfile->addAction(cmd, Constants::G_FILE_NEW);
+ connect(m_newAction, SIGNAL(triggered()), this, SLOT(newFile()));
+
+ //Open Action
+ m_openAction = new QAction(QIcon(Constants::ICON_OPENFILE), tr("&Open..."), this);
+ cmd = am->registerAction(m_openAction, Constants::OPEN, m_globalContext);
+ cmd->setDefaultKeySequence(QKeySequence::Open);
+ mfile->addAction(cmd, Constants::G_FILE_OPEN);
+ connect(m_openAction, SIGNAL(triggered()), this, SLOT(openFile()));
+
+ //Open With Action
+ m_openWithAction = new QAction(tr("&Open With..."), this);
+ cmd = am->registerAction(m_openWithAction, Constants::OPEN_WITH, m_globalContext);
+ mfile->addAction(cmd, Constants::G_FILE_OPEN);
+ connect(m_openWithAction, SIGNAL(triggered()), this, SLOT(openFileWith()));
+
+ //File->Recent Files Menu
+ IActionContainer *ac = am->createMenu(Constants::M_FILE_RECENTFILES);
+ mfile->addMenu(ac, Constants::G_FILE_OPEN);
+ ac->menu()->setTitle(tr("Recent Files"));
+
+ //Save Action
+ QAction *tmpaction = new QAction(QIcon(Constants::ICON_SAVEFILE), tr("&Save"), this);
+ cmd = am->registerAction(tmpaction, Constants::SAVE);
+ cmd->setDefaultKeySequence(QKeySequence::Save);
+ cmd->setAttribute(ICommand::CA_UpdateText);
+ cmd->setDefaultText(tr("&Save"));
+ mfile->addAction(cmd, Constants::G_FILE_SAVE);
+
+ //Save As Action
+ tmpaction = new QAction(tr("Save &As..."), this);
+ cmd = am->registerAction(tmpaction, Constants::SAVEAS);
+#ifdef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+S")));
+#endif
+ cmd->setAttribute(ICommand::CA_UpdateText);
+ cmd->setDefaultText(tr("Save &As..."));
+ mfile->addAction(cmd, Constants::G_FILE_SAVE);
+
+ //SaveAll Action
+ m_saveAllAction = new QAction(tr("Save A&ll"), this);
+ cmd = am->registerAction(m_saveAllAction, Constants::SAVEALL, m_globalContext);
+#ifndef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+S")));
+#endif
+ mfile->addAction(cmd, Constants::G_FILE_SAVE);
+ connect(m_saveAllAction, SIGNAL(triggered()), this, SLOT(saveAll()));
+
+ //Print Action
+ tmpaction = new QAction(tr("&Print..."), this);
+ cmd = am->registerAction(tmpaction, Constants::PRINT);
+ mfile->addAction(cmd, Constants::G_FILE_PRINT);
+
+ //Exit Action
+ m_exitAction = new QAction(tr("E&xit"), this);
+ cmd = am->registerAction(m_exitAction, Constants::EXIT, m_globalContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Q")));
+ mfile->addAction(cmd, Constants::G_FILE_OTHER);
+ connect(m_exitAction, SIGNAL(triggered()), this, SLOT(exit()));
+
+ //Undo Action
+ tmpaction = new QAction(QIcon(Constants::ICON_UNDO), tr("&Undo"), this);
+ cmd = am->registerAction(tmpaction, Constants::UNDO);
+ cmd->setDefaultKeySequence(QKeySequence::Undo);
+ cmd->setAttribute(ICommand::CA_UpdateText);
+ cmd->setDefaultText(tr("&Undo"));
+ medit->addAction(cmd, Constants::G_EDIT_UNDOREDO);
+
+ //Redo Action
+ tmpaction = new QAction(QIcon(Constants::ICON_REDO), tr("&Redo"), this);
+ cmd = am->registerAction(tmpaction, Constants::REDO);
+ cmd->setDefaultKeySequence(QKeySequence::Redo);
+ cmd->setAttribute(ICommand::CA_UpdateText);
+ cmd->setDefaultText(tr("&Redo"));
+ medit->addAction(cmd, Constants::G_EDIT_UNDOREDO);
+
+ //Cut Action
+ tmpaction = new QAction(QIcon(Constants::ICON_CUT), tr("Cu&t"), this);
+ cmd = am->registerAction(tmpaction, Constants::CUT);
+ cmd->setDefaultKeySequence(QKeySequence::Cut);
+ medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
+
+ //Copy Action
+ tmpaction = new QAction(QIcon(Constants::ICON_COPY), tr("&Copy"), this);
+ cmd = am->registerAction(tmpaction, Constants::COPY);
+ cmd->setDefaultKeySequence(QKeySequence::Copy);
+ medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
+
+ //Paste Action
+ tmpaction = new QAction(QIcon(Constants::ICON_PASTE), tr("&Paste"), this);
+ cmd = am->registerAction(tmpaction, Constants::PASTE);
+ cmd->setDefaultKeySequence(QKeySequence::Paste);
+ medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
+
+ //Select All
+ tmpaction = new QAction(tr("&Select All"), this);
+ cmd = am->registerAction(tmpaction, Constants::SELECTALL);
+ cmd->setDefaultKeySequence(QKeySequence::SelectAll);
+ medit->addAction(cmd, Constants::G_EDIT_SELECTALL);
+
+ //Goto Action
+ tmpaction = new QAction(tr("&Go To Line..."), this);
+ cmd = am->registerAction(tmpaction, Constants::GOTO);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+L")));
+ medit->addAction(cmd, Constants::G_EDIT_OTHER);
+
+ //Options Action
+ m_optionsAction = new QAction(tr("&Options..."), this);
+ cmd = am->registerAction(m_optionsAction, Constants::OPTIONS, m_globalContext);
+#ifdef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence("Ctrl+,"));
+#endif
+ mtools->addAction(cmd, Constants::G_DEFAULT_THREE);
+ connect(m_optionsAction, SIGNAL(triggered()), this, SLOT(showOptionsDialog()));
+
+#ifdef Q_OS_MAC
+ //Minimize Action
+ m_minimizeAction = new QAction(tr("Minimize"), this);
+ cmd = am->registerAction(m_minimizeAction, Constants::MINIMIZE_WINDOW, m_globalContext);
+ cmd->setDefaultKeySequence(QKeySequence("Ctrl+M"));
+ mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
+ connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(showMinimized()));
+
+ //Zoom Action
+ m_zoomAction = new QAction(tr("Zoom"), this);
+ cmd = am->registerAction(m_zoomAction, Constants::ZOOM_WINDOW, m_globalContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
+ connect(m_zoomAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
+
+ //Window separator
+ cmd = createSeparator(am, this, QLatin1String("QtCreator.Window.Sep.Size"), m_globalContext);
+ mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
+#endif
+
+ // Toggle Sidebar Action
+ m_toggleSideBarAction = new QAction(QIcon(Constants::ICON_TOGGLE_SIDEBAR),
+ tr("Toggle Sidebar"), this);
+ cmd = am->registerAction(m_toggleSideBarAction, Constants::TOGGLE_SIDEBAR, m_globalContext);
+#ifdef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence("Ctrl+0"));
+#else
+ cmd->setDefaultKeySequence(QKeySequence("Alt+0"));
+#endif
+ connect(m_toggleSideBarAction, SIGNAL(triggered()), this, SLOT(toggleNavigation()));
+ m_toggleSideBarButton->setDefaultAction(cmd->action());
+ mwindow->addAction(cmd, Constants::G_WINDOW_PANES);
+ m_toggleSideBarAction->setEnabled(false);
+
+ //About IDE Action
+#ifdef Q_OS_MAC
+ tmpaction = new QAction(tr("About &Qt Creator"), this); // it's convention not to add dots to the about menu
+#else
+ tmpaction = new QAction(tr("About &Qt Creator..."), this);
+#endif
+ cmd = am->registerAction(tmpaction, Constants:: ABOUT_WORKBENCH, m_globalContext);
+ mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
+ tmpaction->setEnabled(true);
+ connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutQtCreator()));
+ //About Plugins Action
+ tmpaction = new QAction(tr("About &Plugins..."), this);
+ cmd = am->registerAction(tmpaction, Constants::ABOUT_PLUGINS, m_globalContext);
+ mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
+ tmpaction->setEnabled(true);
+#ifdef Q_OS_MAC
+ cmd->action()->setMenuRole(QAction::ApplicationSpecificRole);
+#endif
+ connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutPlugins()));
+ //About Qt Action
+// tmpaction = new QAction(tr("About &Qt..."), this);
+// cmd = am->registerAction(tmpaction, Constants:: ABOUT_QT, m_globalContext);
+// mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
+// tmpaction->setEnabled(true);
+// connect(tmpaction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
+ // About sep
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Help.Sep.About"), m_globalContext);
+ mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
+}
+
+void MainWindow::newFile()
+{
+ showNewItemDialog(tr("New", "Title of dialog"),BaseFileWizard::allWizards());
+}
+
+void MainWindow::openFile()
+{
+ openFiles(editorManager()->getOpenFileNames());
+}
+
+static QList<IFileFactory*> getNonEditorFileFactories()
+{
+ const ICore *core = CoreImpl::instance();
+ const QList<IFileFactory*> allFileFactories = core->pluginManager()->getObjects<IFileFactory>();
+ QList<IFileFactory*> nonEditorFileFactories;
+ foreach (IFileFactory *factory, allFileFactories) {
+ if (!qobject_cast<IEditorFactory *>(factory))
+ nonEditorFileFactories.append(factory);
+ }
+ return nonEditorFileFactories;
+}
+
+static IFileFactory *findFileFactory(const QList<IFileFactory*> &fileFactories,
+ const MimeDatabase *db,
+ const QFileInfo &fi)
+{
+ if (const MimeType mt = db->findByFile(fi)) {
+ const QString type = mt.type();
+ foreach (IFileFactory *factory, fileFactories) {
+ if (factory->mimeTypes().contains(type))
+ return factory;
+ }
+ }
+ return 0;
+}
+
+// opens either an editor or loads a project
+void MainWindow::openFiles(const QStringList &fileNames)
+{
+ bool needToSwitchToEditor = false;
+ QList<IFileFactory*> nonEditorFileFactories = getNonEditorFileFactories();
+
+ foreach (const QString &fileName, fileNames) {
+ const QFileInfo fi(fileName);
+ const QString absoluteFilePath = fi.absoluteFilePath();
+ if (IFileFactory *fileFactory = findFileFactory(nonEditorFileFactories, mimeDatabase(), fi)) {
+ fileFactory->open(absoluteFilePath);
+ } else {
+ IEditor *editor = editorManager()->openEditor(absoluteFilePath);
+ if (editor)
+ needToSwitchToEditor = true;
+ }
+ }
+ if (needToSwitchToEditor)
+ editorManager()->ensureEditorManagerVisible();
+}
+
+void MainWindow::setFocusToEditor()
+{
+ QWidget *focusWidget = qApp->focusWidget();
+ // ### Duplicated code from EditMode::makeSureEditorManagerVisible
+ IMode *currentMode = m_coreImpl->modeManager()->currentMode();
+ if (currentMode && currentMode->uniqueModeName() != QLatin1String(Constants::MODE_EDIT) &&
+ currentMode->uniqueModeName() != QLatin1String("GdbDebugger.Mode.Debug"))
+ {
+ m_coreImpl->modeManager()->activateMode(QLatin1String(Constants::MODE_EDIT));
+ }
+
+ EditorGroup *group = m_editorManager->currentEditorGroup();
+ if (group && group->widget())
+ group->widget()->setFocus();
+ if (focusWidget && focusWidget == qApp->focusWidget()) {
+ if (FindToolBarPlaceHolder::getCurrent())
+ FindToolBarPlaceHolder::getCurrent()->hide();
+ m_outputPane->slotHide();
+ RightPaneWidget::instance()->setShown(false);
+ }
+}
+
+QStringList MainWindow::showNewItemDialog(const QString &title,
+ const QList<IWizard *> &wizards,
+ const QString &defaultLocation)
+{
+ QString defaultDir = defaultLocation;
+ if (defaultDir.isEmpty()) {
+ if (!m_coreImpl->fileManager()->currentFile().isEmpty())
+ defaultDir = QFileInfo(m_coreImpl->fileManager()->currentFile()).absolutePath();
+ }
+
+ // Scan for wizards matching the filter and pick one. Don't show
+ // dialog if there is only one.
+ IWizard *wizard = 0;
+ switch (wizards.size()) {
+ case 0:
+ break;
+ case 1:
+ wizard = wizards.front();
+ break;
+ default: {
+ NewDialog dlg(this);
+ dlg.setWizards(wizards);
+ dlg.setWindowTitle(title);
+ wizard = dlg.showDialog();
+ }
+ break;
+ }
+
+ if (!wizard)
+ return QStringList();
+ return wizard->runWizard(defaultDir, this);
+}
+
+void MainWindow::showOptionsDialog(const QString &category, const QString &page)
+{
+ emit m_coreImpl->settingsDialogRequested();
+ SettingsDialog dlg(this, category, page);
+ dlg.exec();
+}
+
+void MainWindow::saveAll()
+{
+ m_fileManager->saveModifiedFiles(m_fileManager->modifiedFiles());
+ emit m_coreImpl->saveSettingsRequested();
+}
+
+void MainWindow::exit()
+{
+ // this function is most likely called from a user action
+ // that is from an event handler of an object
+ // since on close we are going to delete everything
+ // so to prevent the deleting of that object we
+ // just append it
+ QTimer::singleShot(0, this, SLOT(close()));
+}
+
+void MainWindow::openFileWith()
+{
+ QStringList fileNames = editorManager()->getOpenFileNames();
+ foreach (const QString &fileName, fileNames) {
+ const QString editorKind = editorManager()->getOpenWithEditorKind(fileName);
+ if (editorKind.isEmpty())
+ continue;
+ editorManager()->openEditor(fileName, editorKind);
+ }
+}
+
+ActionManagerInterface *MainWindow::actionManager() const
+{
+ return m_actionManager;
+}
+
+FileManager *MainWindow::fileManager() const
+{
+ return m_fileManager;
+}
+
+UniqueIDManager *MainWindow::uniqueIDManager() const
+{
+ return m_uniqueIDManager;
+}
+
+MessageManager *MainWindow::messageManager() const
+{
+ return m_messageManager;
+}
+
+VCSManager *MainWindow::vcsManager() const
+{
+ return m_vcsManager;
+}
+
+ViewManagerInterface *MainWindow::viewManager() const
+{
+ return m_viewManager;
+}
+
+EditorManager *MainWindow::editorManager() const
+{
+ return m_editorManager;
+}
+
+ProgressManagerInterface *MainWindow::progressManager() const
+{
+ return m_progressManager;
+}
+
+ScriptManagerInterface *MainWindow::scriptManager() const
+{
+ return m_scriptManager;
+}
+
+VariableManager *MainWindow::variableManager() const
+{
+ return m_variableManager;
+}
+
+ModeManager *MainWindow::modeManager() const
+{
+ return m_modeManager;
+}
+
+MimeDatabase *MainWindow::mimeDatabase() const
+{
+ return m_mimeDatabase;
+}
+
+ExtensionSystem::PluginManager *MainWindow::pluginManager() const
+{
+ return m_pluginManager;
+}
+
+IContext *MainWindow::contextObject(QWidget *widget)
+{
+ return m_contextWidgets.value(widget);
+}
+
+void MainWindow::addContextObject(IContext *context)
+{
+ if (!context)
+ return;
+ QWidget *widget = context->widget();
+ if (m_contextWidgets.contains(widget))
+ return;
+
+ m_contextWidgets.insert(widget, context);
+}
+
+void MainWindow::removeContextObject(IContext *context)
+{
+ if (!context)
+ return;
+
+ QWidget *widget = context->widget();
+ if (!m_contextWidgets.contains(widget))
+ return;
+
+ m_contextWidgets.remove(widget);
+ if(m_activeContext == context)
+ updateContextObject(0);
+}
+
+void MainWindow::changeEvent(QEvent *e)
+{
+ if (e->type() == QEvent::ActivationChange) {
+ if (isActiveWindow()) {
+ if (debugMainWindow)
+ qDebug() << "main window activated";
+ emit windowActivated();
+ }
+#ifdef Q_OS_MAC
+ } else if (e->type() == QEvent::WindowStateChange) {
+ bool minimized = isMinimized();
+ if (debugMainWindow)
+ qDebug() << "main window state changed to minimized=" << minimized;
+ m_minimizeAction->setEnabled(!minimized);
+ m_zoomAction->setEnabled(!minimized);
+#endif
+ }
+}
+
+void MainWindow::updateFocusWidget(QWidget *old, QWidget *now)
+{
+ Q_UNUSED(old)
+ Q_UNUSED(now)
+ if (focusWidget()) {
+ IContext *context = 0;
+ QWidget *p = focusWidget();
+ while (p) {
+ context = m_contextWidgets.value(p);
+ if (context) {
+ if (m_activeContext != context)
+ updateContextObject(context);
+ break;
+ }
+ p = p->parentWidget();
+ }
+ }
+}
+
+void MainWindow::updateContextObject(IContext *context)
+{
+ IContext *oldContext = m_activeContext;
+ m_activeContext = context;
+ if (!context || oldContext != m_activeContext) {
+ emit m_coreImpl->contextAboutToChange(context);
+ updateContext();
+ if (debugMainWindow)
+ qDebug() << "new context object =" << context << (context ? context->widget() : 0)
+ << (context ? context->widget()->metaObject()->className() : 0);
+ emit m_coreImpl->contextChanged(context);
+ }
+}
+
+void MainWindow::resetContext()
+{
+ updateContextObject(0);
+}
+
+QMenu *MainWindow::createPopupMenu() {
+ QMenu *menu = new QMenu(this);
+ QList<ActionContainer *> containers = m_actionManager->containers();
+ foreach(ActionContainer *c, containers) {
+ if (c->toolBar())
+ menu->addAction(c->toolBar()->toggleViewAction());
+ }
+ return menu;
+}
+
+static const char *settingsGroup = "MainWindow";
+static const char *geometryKey = "Geometry";
+static const char *colorKey = "Color";
+static const char *maxKey = "Maximized";
+
+void MainWindow::readSettings()
+{
+ m_settings->beginGroup(QLatin1String(settingsGroup));
+ StyleHelper::setBaseColor(m_settings->value(QLatin1String(colorKey)).value<QColor>());
+ const QVariant geom = m_settings->value(QLatin1String(geometryKey));
+ if (geom.isValid()) {
+ setGeometry(geom.toRect());
+ } else {
+ resize(1024, 700);
+ }
+ if (m_settings->value(QLatin1String(maxKey), false).toBool())
+ setWindowState(Qt::WindowMaximized);
+
+ m_settings->endGroup();
+ m_editorManager->readSettings(m_settings);
+ m_navigationWidget->readSettings(m_settings);
+ m_rightPaneWidget->readSettings(m_settings);
+}
+
+void MainWindow::writeSettings()
+{
+ m_settings->beginGroup(QLatin1String(settingsGroup));
+ m_settings->setValue(colorKey, StyleHelper::baseColor());
+ const QString maxSettingsKey = QLatin1String(maxKey);
+ if (windowState() & Qt::WindowMaximized) {
+ m_settings->setValue(maxSettingsKey, true);
+ } else {
+ m_settings->setValue(maxSettingsKey, false);
+ m_settings->setValue(QLatin1String(geometryKey), geometry());
+ }
+ m_settings->endGroup();
+
+ m_fileManager->saveRecentFiles();
+ m_viewManager->saveSettings(m_settings);
+ m_actionManager->saveSettings(m_settings);
+ m_editorManager->saveSettings(m_settings);
+ m_navigationWidget->saveSettings(m_settings);
+}
+
+void MainWindow::addAdditionalContext(int context)
+{
+ if (context == 0)
+ return;
+
+ if (!m_additionalContexts.contains(context))
+ m_additionalContexts.prepend(context);
+}
+
+void MainWindow::removeAdditionalContext(int context)
+{
+ if (context == 0)
+ return;
+
+ int index = m_additionalContexts.indexOf(context);
+ if (index != -1)
+ m_additionalContexts.removeAt(index);
+}
+
+bool MainWindow::hasContext(int context) const
+{
+ return m_actionManager->hasContext(context);
+}
+
+void MainWindow::updateContext()
+{
+ QList<int> contexts;
+
+ if (m_activeContext)
+ contexts += m_activeContext->context();
+ IEditor *editor = m_editorManager->currentEditor();
+ if (editor && (EditorManagerPlaceHolder::current() != 0)) {
+ contexts += editor->context();
+ }
+
+ contexts += m_additionalContexts;
+
+ QList<int> uniquecontexts;
+ for (int i = 0; i < contexts.size(); ++i) {
+ const int c = contexts.at(i);
+ if (!uniquecontexts.contains(c))
+ uniquecontexts << c;
+ }
+
+ m_actionManager->setContext(uniquecontexts);
+}
+
+void MainWindow::aboutToShowRecentFiles()
+{
+ IActionContainer *aci =
+ m_actionManager->actionContainer(Constants::M_FILE_RECENTFILES);
+ aci->menu()->clear();
+ m_recentFilesActions.clear();
+
+ bool hasRecentFiles = false;
+ foreach (QString s, m_fileManager->recentFiles()) {
+ hasRecentFiles = true;
+ QAction *action = aci->menu()->addAction(s);
+ m_recentFilesActions.insert(action, s);
+ connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
+ }
+ aci->menu()->setEnabled(hasRecentFiles);
+}
+
+void MainWindow::openRecentFile()
+{
+ QAction *a = qobject_cast<QAction*>(sender());
+ if (m_recentFilesActions.contains(a)) {
+ editorManager()->openEditor(m_recentFilesActions.value(a));
+ editorManager()->ensureEditorManagerVisible();
+ }
+}
+
+void MainWindow::aboutQtCreator()
+{
+ VersionDialog versionDialog(this);
+ versionDialog.exec();
+}
+
+void MainWindow::aboutPlugins()
+{
+ PluginDialog dialog(ExtensionSystem::PluginManager::instance(), this);
+ dialog.exec();
+}
+
+QPrinter *MainWindow::printer() const
+{
+ if (!m_printer)
+ m_printer = new QPrinter(QPrinter::HighResolution);
+ return m_printer;
+}
diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h
new file mode 100644
index 0000000000..00721a1662
--- /dev/null
+++ b/src/plugins/coreplugin/mainwindow.h
@@ -0,0 +1,227 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "icore.h"
+
+#include <QtGui/QMainWindow>
+#include <QtCore/QMap>
+#include <QtCore/QList>
+#include <QtCore/QSet>
+#include <QtCore/QPointer>
+#include <QtGui/QPrinter>
+#include <QtGui/QToolButton>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+class QShortcut;
+QT_END_NAMESPACE
+
+namespace ExtensionSystem {
+class PluginManager;
+}
+
+namespace Core {
+
+class ActionManagerInterface;
+class BaseMode;
+class EditorManager;
+class FileManager;
+class IContext;
+class MessageManager;
+class ModeManager;
+class MimeDatabase;
+class ProgressManagerInterface;
+class VCSManager;
+class ScriptManagerInterface;
+class UniqueIDManager;
+class VariableManager;
+class ViewManagerInterface;
+class BaseView;
+class RightPaneWidget;
+
+namespace Internal {
+
+class CoreImpl;
+class ActionManager;
+class ProgressManager;
+class OutputPane;
+class ViewManager;
+class GeneralSettings;
+class ShortcutSettings;
+class FancyTabWidget;
+class NavigationWidget;
+
+class CORE_EXPORT MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+ ~MainWindow();
+
+ bool init(ExtensionSystem::PluginManager *pm, QString *error_message);
+ void extensionsInitialized();
+
+ IContext *contextObject(QWidget *widget);
+ void addContextObject(IContext *contex);
+ void removeContextObject(IContext *contex);
+ void resetContext();
+
+ void openFiles(const QStringList &fileNames);
+
+ //ICore
+ inline ExtensionSystem::PluginManager *pluginManager() { return m_pluginManager; }
+ Core::ActionManagerInterface *actionManager() const;
+ Core::FileManager *fileManager() const;
+ Core::UniqueIDManager *uniqueIDManager() const;
+ Core::MessageManager *messageManager() const;
+ Core::ViewManagerInterface *viewManager() const;
+ ExtensionSystem::PluginManager *pluginManager() const;
+ Core::EditorManager *editorManager() const;
+ Core::ProgressManagerInterface *progressManager() const;
+ Core::ScriptManagerInterface *scriptManager() const;
+ Core::VariableManager *variableManager() const;
+ Core::ModeManager *modeManager() const;
+ Core::MimeDatabase *mimeDatabase() const;
+
+ VCSManager *vcsManager() const;
+ inline QSettings *settings() const { return m_settings; }
+ virtual QPrinter *printer() const;
+ IContext * currentContextObject() const;
+ QStatusBar *statusBar() const;
+ void addAdditionalContext(int context);
+ void removeAdditionalContext(int context);
+ bool hasContext(int context) const;
+
+ void updateContext();
+
+ QMenu *createPopupMenu();
+
+
+ void setSuppressNavigationWidget(bool suppress);
+
+signals:
+ void windowActivated();
+
+public slots:
+ void newFile();
+ void openFileWith();
+ void exit();
+
+ QStringList showNewItemDialog(const QString &title,
+ const QList<IWizard *> &wizards,
+ const QString &defaultLocation = QString());
+
+ void showOptionsDialog(const QString &category = QString(), const QString &page = QString());
+
+protected:
+ void changeEvent(QEvent *e);
+ void closeEvent(QCloseEvent *event);
+
+private slots:
+ void openFile();
+ void aboutToShowRecentFiles();
+ void openRecentFile();
+ void setFocusToEditor();
+ void saveAll();
+ void aboutQtCreator();
+ void aboutPlugins();
+ void updateFocusWidget(QWidget *old, QWidget *now);
+ void toggleNavigation();
+
+private:
+ void updateContextObject(IContext *context);
+ void registerDefaultContainers();
+ void registerDefaultActions();
+
+ void readSettings();
+ void writeSettings();
+
+ CoreImpl *m_coreImpl;
+ UniqueIDManager *m_uniqueIDManager;
+ QList<int> m_globalContext;
+ QList<int> m_additionalContexts;
+ QSettings *m_settings;
+ mutable QPrinter *m_printer;
+ ActionManager *m_actionManager;
+ EditorManager *m_editorManager;
+ FileManager *m_fileManager;
+ MessageManager *m_messageManager;
+ ProgressManager *m_progressManager;
+ ScriptManagerInterface *m_scriptManager;
+ VariableManager *m_variableManager;
+ VCSManager *m_vcsManager;
+ ViewManager *m_viewManager;
+ ModeManager *m_modeManager;
+ MimeDatabase *m_mimeDatabase;
+ FancyTabWidget *m_modeStack;
+ NavigationWidget *m_navigationWidget;
+ RightPaneWidget *m_rightPaneWidget;
+ Core::BaseView *m_outputView;
+
+ IContext * m_activeContext;
+
+ QMap<QWidget *, IContext *> m_contextWidgets;
+
+ ExtensionSystem::PluginManager *m_pluginManager;
+
+ OutputPane *m_outputPane;
+ BaseMode *m_outputMode;
+ GeneralSettings *m_generalSettings;
+ ShortcutSettings *m_shortcutSettings;
+
+ QMap<QAction*, QString> m_recentFilesActions;
+
+ // actions
+ QShortcut *m_focusToEditor;
+ QAction *m_newAction;
+ QAction *m_openAction;
+ QAction *m_openWithAction;
+ QAction *m_saveAllAction;
+ QAction *m_exitAction;
+ QAction *m_optionsAction;
+ QAction *m_toggleSideBarAction;
+#ifdef Q_OS_MAC
+ QAction *m_minimizeAction;
+ QAction *m_zoomAction;
+#endif
+
+ QToolButton *m_toggleSideBarButton;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // MAINWINDOW_H
diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp
new file mode 100644
index 0000000000..d82059f00d
--- /dev/null
+++ b/src/plugins/coreplugin/manhattanstyle.cpp
@@ -0,0 +1,942 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2007-$THISYEAR$ $TROLLTECH$. All rights reserved.
+**
+** This file is part of the Manhattan Style project
+**
+** $TROLLTECH_GPL_LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "manhattanstyle.h"
+#include <QStyleOption>
+#include <QPainter>
+#include <QScrollArea>
+#include <QMainWindow>
+#include <QDockWidget>
+#include <QPixmapCache>
+#include <QDialogButtonBox>
+#include <QPixmap>
+#include <QToolBar>
+#include <QDialog>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QLibrary>
+#include <QStatusBar>
+#include <QApplication>
+#include <QStyleFactory>
+#include <QToolButton>
+#include <QLabel>
+#include <QPushButton>
+#include <QSplitter>
+#include <QMenuBar>
+#include "stylehelper.h"
+#include "styleanimator.h"
+#include <qdebug.h>
+
+// We define a currently unused state for indicating animations
+#define State_Animating 0x00000040
+
+// Because designer needs to disable this for widget previews
+// we have a custom property that is inherited
+bool styleEnabled(const QWidget *widget)
+{
+ const QWidget *p = widget;
+ while (p) {
+ if (p->property("_q_custom_style_disabled").toBool())
+ return false;
+ p = p->parentWidget();
+ }
+ return true;
+}
+
+// Consider making this a QStyle state
+bool panelWidget(const QWidget *widget)
+{
+ const QWidget *p = widget;
+
+ while (p) {
+ if (qobject_cast<const QToolBar *>(p) && styleEnabled(p))
+ return true;
+ else if (qobject_cast<const QStatusBar *>(p) && styleEnabled(p))
+ return true;
+ else if (qobject_cast<const QMenuBar *>(p) && styleEnabled(p))
+ return true;
+ p = p->parentWidget();
+ }
+ return false;
+}
+
+class ManhattanStylePrivate
+{
+public:
+ ManhattanStylePrivate(const QString &baseStyleName)
+ {
+ style = QStyleFactory::create(baseStyleName);
+ Q_ASSERT(style);
+ buttonImage_pressed = QImage(":/qworkbench/images/pushbutton_pressed.png");
+ buttonImage = QImage(":/qworkbench/images/pushbutton.png");
+
+ lineeditImage = QImage(":/qworkbench/images/inputfield.png");
+ lineeditImage_disabled = QImage(":/qworkbench/images/inputfield_disabled.png");
+ }
+
+ ~ManhattanStylePrivate() {
+ delete style;
+ style = 0;
+ }
+
+ void init();
+ QStyle *style;
+ QImage buttonImage;
+ QImage buttonImage_pressed;
+ QImage lineeditImage;
+ QImage lineeditImage_disabled;
+
+ StyleAnimator animator;
+};
+
+ManhattanStyle::ManhattanStyle(const QString &baseStyleName)
+ : QWindowsStyle(), d(new ManhattanStylePrivate(baseStyleName))
+{
+}
+
+ManhattanStyle::~ManhattanStyle()
+{
+ delete d;
+ d = 0;
+}
+
+// Draws a CSS-like border image where the defined borders are not stretched
+void drawCornerImage(const QImage &img, QPainter *painter, QRect rect,
+ int left = 0, int top = 0, int right = 0,
+ int bottom = 0)
+{
+ QSize size = img.size();
+ if (top > 0) { //top
+ painter->drawImage(QRect(rect.left() + left, rect.top(), rect.width() -right - left, top), img,
+ QRect(left, 0, size.width() -right - left, top));
+ if(left > 0) //top-left
+ painter->drawImage(QRect(rect.left(), rect.top(), left, top), img,
+ QRect(0, 0, left, top));
+ if (right > 0) //top-right
+ painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top(), right, top), img,
+ QRect(size.width() - right, 0, right, top));
+ }
+ //left
+ if (left > 0)
+ painter->drawImage(QRect(rect.left(), rect.top()+top, left, rect.height() - top - bottom), img,
+ QRect(0, top, left, size.height() - bottom - top));
+ //center
+ painter->drawImage(QRect(rect.left() + left, rect.top()+top, rect.width() -right - left,
+ rect.height() - bottom - top), img,
+ QRect(left, top, size.width() -right -left,
+ size.height() - bottom - top));
+ if (right > 0) //right
+ painter->drawImage(QRect(rect.left() +rect.width() - right, rect.top()+top, right, rect.height() - top - bottom), img,
+ QRect(size.width() - right, top, right, size.height() - bottom - top));
+ if (bottom > 0) { //bottom
+ painter->drawImage(QRect(rect.left() +left, rect.top() + rect.height() - bottom,
+ rect.width() - right - left, bottom), img,
+ QRect(left, size.height() - bottom,
+ size.width() - right - left, bottom));
+ if (left > 0) //bottom-left
+ painter->drawImage(QRect(rect.left(), rect.top() + rect.height() - bottom, left, bottom), img,
+ QRect(0, size.height() - bottom, left, bottom));
+ if (right > 0) //bottom-right
+ painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top() + rect.height() - bottom, right, bottom), img,
+ QRect(size.width() - right, size.height() - bottom, right, bottom));
+ }
+}
+
+QPixmap ManhattanStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const
+{
+ QPixmap result;
+ result = d->style->generatedIconPixmap(iconMode, pixmap, opt);
+ return result;
+}
+
+int ManhattanStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1,
+ QSizePolicy::ControlType control2,
+ Qt::Orientation orientation,
+ const QStyleOption * option ,
+ const QWidget * widget ) const
+{
+ return d->style->layoutSpacing(control1, control2, orientation, option, widget);
+
+}
+
+QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const
+{
+ if (type == CT_Splitter && widget && widget->property("minisplitter").toBool())
+ return QSize(1, 1);
+ return d->style->sizeFromContents(type, option, size, widget);
+}
+
+QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
+{
+ QRect rect;
+ rect = d->style->subElementRect(element, option, widget);
+ return rect;
+}
+
+QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const
+{
+ QRect rect;
+ rect = d->style->subControlRect(control, option, subControl, widget);
+ return rect;
+}
+
+QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ const QPoint &pos, const QWidget *widget) const
+{
+ SubControl result = QStyle::SC_None;
+ result = d->style->hitTestComplexControl(control, option, pos, widget);
+ return result;
+}
+
+int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
+{
+ int retval = 0;
+ retval = d->style->pixelMetric(metric, option, widget);
+ switch (metric) {
+ case PM_SplitterWidth:
+ if (widget && widget->property("minisplitter").toBool())
+ retval = 1;
+ break;
+ case PM_ToolBarIconSize:
+ if (panelWidget(widget))
+ retval = 16;
+ break;
+ case PM_MenuPanelWidth:
+ case PM_MenuBarHMargin:
+ case PM_MenuBarVMargin:
+ case PM_ToolBarFrameWidth:
+ if (panelWidget(widget))
+ retval = 1;
+ break;
+ case PM_ButtonShiftVertical:
+ case PM_ButtonShiftHorizontal:
+ case PM_MenuBarPanelWidth:
+ case PM_ToolBarItemMargin:
+ case PM_ToolBarItemSpacing:
+ if (panelWidget(widget))
+ retval = 0;
+ break;
+ case PM_DefaultFrameWidth:
+ if (qobject_cast<const QLineEdit*>(widget) && panelWidget(widget))
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+QPalette ManhattanStyle::standardPalette() const
+{
+ QPalette result;
+ result = d->style->standardPalette();
+ return result;
+}
+
+void ManhattanStyle::polish(QApplication *app)
+{
+ d->style->polish(app);
+}
+
+void ManhattanStyle::unpolish(QApplication *app)
+{
+ d->style->unpolish(app);
+}
+
+QPalette panelPalette(const QPalette &oldPalette)
+{
+ QColor color = StyleHelper::panelTextColor();
+ QPalette pal = oldPalette;
+ pal.setBrush(QPalette::All, QPalette::WindowText, color);
+ pal.setBrush(QPalette::All, QPalette::ButtonText, color);
+ pal.setBrush(QPalette::All, QPalette::Foreground, color);
+ color.setAlpha(100);
+ pal.setBrush(QPalette::Disabled, QPalette::WindowText, color);
+ pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color);
+ pal.setBrush(QPalette::Disabled, QPalette::Foreground, color);
+ return pal;
+}
+
+void ManhattanStyle::polish(QWidget *widget)
+{
+ d->style->polish(widget);
+
+ // OxygenStyle forces a rounded widget mask on toolbars
+ if (d->style->inherits("OxygenStyle")) {
+ if (qobject_cast<QToolBar*>(widget))
+ widget->removeEventFilter(d->style);
+ }
+ if (panelWidget(widget)) {
+ if (qobject_cast<QToolButton*>(widget)) {
+ widget->setAttribute(Qt::WA_Hover);
+ widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2);
+ }
+ else if (qobject_cast<QLineEdit*>(widget)) {
+ widget->setAttribute(Qt::WA_Hover);
+ widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2);
+ }
+ else if (qobject_cast<QLabel*>(widget))
+ widget->setPalette(panelPalette(widget->palette()));
+ else if (qobject_cast<QToolBar*>(widget))
+ widget->setMinimumHeight(StyleHelper::navigationWidgetHeight());
+ else if (qobject_cast<QStatusBar*>(widget))
+ widget->setFixedHeight(StyleHelper::navigationWidgetHeight() + 2);
+ else if (qobject_cast<QComboBox*>(widget))
+ widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2);
+ }
+}
+
+void ManhattanStyle::unpolish(QWidget *widget)
+{
+ d->style->unpolish(widget);
+ if (panelWidget(widget)) {
+ if (qobject_cast<QTabBar*>(widget))
+ widget->setAttribute(Qt::WA_Hover, false);
+ else if (qobject_cast<QToolBar*>(widget))
+ widget->setAttribute(Qt::WA_Hover, false);
+ }
+}
+
+void ManhattanStyle::polish(QPalette &pal)
+{
+ d->style->polish(pal);
+}
+
+QIcon ManhattanStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ static const QIcon closeButton(":/qworkbench/images/closebutton.png");
+ QIcon icon;
+ switch (standardIcon) {
+ case QStyle::SP_TitleBarCloseButton:
+ icon = closeButton;
+ break;
+ default:
+ icon = d->style->standardIcon(standardIcon, option, widget);
+ }
+ return icon;
+}
+
+QPixmap ManhattanStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
+ const QWidget *widget) const
+{
+ static const QPixmap closeButton(":/qworkbench/images/closebutton.png");
+ QPixmap pixmap;
+ switch (standardPixmap) {
+ case QStyle::SP_TitleBarCloseButton:
+ pixmap = closeButton;
+ break;
+ default:
+ pixmap = d->style->standardPixmap(standardPixmap, opt, widget);
+ }
+ return pixmap;
+}
+
+
+int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
+ QStyleHintReturn *returnData) const
+{
+ int ret = 0;
+ switch (hint) {
+ case QStyle::SH_EtchDisabledText:
+ ret = false; // We really should only enforce this for panel widgets
+ break;
+ default:
+ ret = d->style->styleHint(hint, option, widget, returnData);
+ }
+
+ return ret;
+}
+
+void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (!panelWidget(widget))
+ return d->style->drawPrimitive(element, option, painter, widget);
+
+ bool animating = (option->state & State_Animating);
+ int state = option->state;
+ QRect rect = option->rect;
+ QRect oldRect;
+ QRect newRect;
+ if (widget && (element == PE_PanelButtonTool) && !animating) {
+ QWidget *w = const_cast<QWidget *> (widget);
+ int oldState = w->property("_q_stylestate").toInt();
+ oldRect = w->property("_q_stylerect").toRect();
+ newRect = w->rect();
+ w->setProperty("_q_stylestate", (int)option->state);
+ w->setProperty("_q_stylerect", w->rect());
+
+ // Determine the animated transition
+ bool doTransition = ((state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver));
+ if (oldRect != newRect)
+ {
+ doTransition = false;
+ d->animator.stopAnimation(widget);
+ }
+
+ if (doTransition) {
+ QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
+ QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
+ Animation *anim = d->animator.widgetAnimation(widget);
+ QStyleOption opt = *option;
+ opt.state = (QStyle::State)oldState;
+ opt.state |= (State)State_Animating;
+ startImage.fill(0);
+ Transition *t = new Transition;
+ t->setWidget(w);
+ QPainter startPainter(&startImage);
+ if (!anim) {
+ drawPrimitive(element, &opt, &startPainter, widget);
+ } else {
+ anim->paint(&startPainter, &opt);
+ d->animator.stopAnimation(widget);
+ }
+ QStyleOption endOpt = *option;
+ endOpt.state |= (State)State_Animating;
+ t->setStartImage(startImage);
+ d->animator.startAnimation(t);
+ endImage.fill(0);
+ QPainter endPainter(&endImage);
+ drawPrimitive(element, &endOpt, &endPainter, widget);
+ t->setEndImage(endImage);
+ t->setDuration(130);
+ t->setStartTime(QTime::currentTime());
+ }
+ }
+
+ switch (element) {
+ case PE_PanelLineEdit:
+ {
+ painter->save();
+ if (option->state & State_Enabled)
+ drawCornerImage(d->lineeditImage, painter, option->rect, 2, 2, 2, 2);
+ else
+ drawCornerImage(d->lineeditImage_disabled, painter, option->rect, 2, 2, 2, 2);
+
+ if (option->state & State_HasFocus || option->state & State_MouseOver) {
+ QColor hover = StyleHelper::baseColor();
+ if (state & State_HasFocus)
+ hover.setAlpha(100);
+ else
+ hover.setAlpha(50);
+
+ painter->setPen(QPen(hover, 1));
+ painter->drawRect(option->rect.adjusted(1, 1, -2 ,-2));
+ }
+ painter->restore();
+ }
+ break;
+
+ case PE_FrameStatusBarItem:
+ break;
+
+ case PE_PanelButtonTool: {
+ Animation *anim = d->animator.widgetAnimation(widget);
+ if (!animating && anim) {
+ anim->paint(painter, option);
+ } else {
+ bool pressed = option->state & State_Sunken || option->state & State_On;
+ QColor shadow(0, 0, 0, 30);
+ painter->setPen(shadow);
+ if (pressed) {
+ QColor shade(0, 0, 0, 50);
+ if (option->state & State_Sunken)
+ shade = QColor(0, 0, 0, 70);
+#ifndef Q_WS_MAC
+ else if (option->state & State_MouseOver)
+ shade = QColor(255, 255, 255, 40);
+#endif
+ else if (option->state & State_On)
+ shade = QColor(0, 0, 0, 50);
+ else
+ shade = QColor(0, 0, 0, 0);
+ painter->fillRect(rect.adjusted(1, 1, -1, -1), shade);
+ painter->drawLine(rect.topLeft(), rect.topRight());
+ painter->drawLine(rect.topLeft(), rect.bottomLeft());
+ QColor highlight(255, 255, 255, 30);
+ painter->setPen(highlight);
+ painter->drawLine(rect.topRight(), rect.bottomRight());
+ painter->drawLine(rect.bottomLeft(), rect.bottomRight());
+ }
+ #ifndef Q_WS_MAC
+ else if (option->state & State_MouseOver) {
+ QColor lighter(255, 255, 255, 100);
+ painter->fillRect(rect, lighter);
+ painter->drawLine(rect.topRight(), rect.bottomRight());
+ }
+#endif
+ }
+ }
+ break;
+
+ case PE_PanelStatusBar:
+ {
+ painter->save();
+ QLinearGradient grad(option->rect.topLeft(), QPoint(rect.center().x(), rect.bottom()));
+ QColor startColor = StyleHelper::shadowColor().darker(164);
+ QColor endColor = StyleHelper::baseColor().darker(130);
+ grad.setColorAt(0, startColor);
+ grad.setColorAt(1, endColor);
+ painter->fillRect(option->rect, grad);
+ painter->setPen(QColor(255, 255, 255, 60));
+ painter->drawLine(rect.topLeft() + QPoint(0,1),
+ rect.topRight()+ QPoint(0,1));
+ painter->setPen(StyleHelper::borderColor().darker(110));
+ painter->drawLine(rect.topLeft(), rect.topRight());
+ painter->restore();
+ }
+ break;
+
+ case PE_IndicatorToolBarSeparator:
+ {
+ QColor separatorColor = StyleHelper::borderColor();
+ separatorColor.setAlpha(100);
+ painter->setPen(separatorColor);
+ const int margin = 6;
+ if (option->state & State_Horizontal) {
+ const int offset = rect.width()/2;
+ painter->drawLine(rect.bottomLeft().x() + offset,
+ rect.bottomLeft().y() - margin,
+ rect.topLeft().x() + offset,
+ rect.topLeft().y() + margin);
+ } else { //Draw vertical separator
+ const int offset = rect.height()/2;
+ painter->setPen(QPen(option->palette.background().color().darker(110)));
+ painter->drawLine(rect.topLeft().x() + margin ,
+ rect.topLeft().y() + offset,
+ rect.topRight().x() - margin,
+ rect.topRight().y() + offset);
+ }
+ }
+ break;
+
+ case PE_IndicatorToolBarHandle:
+ {
+ bool horizontal = option->state & State_Horizontal;
+ painter->save();
+ QPainterPath path;
+ int x = option->rect.x() + horizontal ? 2 : 6;
+ int y = option->rect.y() + horizontal ? 6 : 2;
+ static const int RectHeight = 2;
+ if (horizontal) {
+ while (y < option->rect.height() - RectHeight - 6) {
+ path.moveTo(x, y);
+ path.addRect(x, y, RectHeight, RectHeight);
+ y += 6;
+ }
+ } else {
+ while (x < option->rect.width() - RectHeight - 6) {
+ path.moveTo(x, y);
+ path.addRect(x, y, RectHeight, RectHeight);
+ x += 6;
+ }
+ }
+
+ painter->setPen(Qt::NoPen);
+ QColor dark = StyleHelper::borderColor();
+ dark.setAlphaF(0.4);
+
+ QColor light = StyleHelper::baseColor();
+ light.setAlphaF(0.4);
+
+ painter->fillPath(path, light);
+ painter->save();
+ painter->translate(1, 1);
+ painter->fillPath(path, dark);
+ painter->restore();
+ painter->translate(3, 3);
+ painter->fillPath(path, light);
+ painter->translate(1, 1);
+ painter->fillPath(path, dark);
+ painter->restore();
+ }
+ break;
+
+ default:
+ d->style->drawPrimitive(element, option, painter, widget);
+ break;
+ }
+}
+
+void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (!panelWidget(widget))
+ return d->style->drawControl(element, option, painter, widget);
+
+ switch (element) {
+ case CE_MenuBarItem:
+ painter->save();
+ if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ QColor highlightOutline = StyleHelper::borderColor().lighter(120);
+ bool act = mbi->state & State_Selected && mbi->state & State_Sunken;
+ bool dis = !(mbi->state & State_Enabled);
+ StyleHelper::menuGradient(painter, option->rect, option->rect);
+ QStyleOptionMenuItem item = *mbi;
+ item.rect = mbi->rect;
+ QPalette pal = mbi->palette;
+ pal.setBrush(QPalette::ButtonText, dis ? Qt::gray : Qt::black);
+ item.palette = pal;
+ QCommonStyle::drawControl(element, &item, painter, widget);
+ QRect r = option->rect;
+
+ if (act) {
+ // Fill|
+ QColor baseColor = StyleHelper::baseColor();
+ QLinearGradient grad(option->rect.topLeft(), option->rect.bottomLeft());
+ grad.setColorAt(0, baseColor.lighter(120));
+ grad.setColorAt(1, baseColor.lighter(130));
+ painter->fillRect(option->rect.adjusted(1, 1, -1, 0), grad);
+
+ // Outline
+ painter->setPen(QPen(highlightOutline, 0));
+ painter->drawLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom()));
+ painter->drawLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom()));
+ painter->drawLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top()));
+ highlightOutline.setAlpha(60);
+ painter->setPen(QPen(highlightOutline, 0));
+ painter->drawPoint(r.topLeft());
+ painter->drawPoint(r.topRight());
+
+ QPalette pal = mbi->palette;
+ uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!styleHint(SH_UnderlineShortcut, mbi, widget))
+ alignment |= Qt::TextHideMnemonic;
+ pal.setBrush(QPalette::Text, dis ? Qt::gray : QColor(0, 0, 0, 60));
+ drawItemText(painter, item.rect.translated(0, 1), alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text);
+ pal.setBrush(QPalette::Text, dis ? Qt::gray : Qt::white);
+ drawItemText(painter, item.rect, alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text);
+ }
+ }
+ painter->restore();
+ break;
+
+ case CE_ComboBoxLabel:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ if (panelWidget(widget)) {
+ QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget);
+ QPalette customPal = cb->palette;
+
+ if (!cb->currentIcon.isNull()) {
+ QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
+ : QIcon::Disabled;
+ QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
+ QRect iconRect(editRect);
+ iconRect.setWidth(cb->iconSize.width() + 4);
+ iconRect = alignedRect(cb->direction,
+ Qt::AlignLeft | Qt::AlignVCenter,
+ iconRect.size(), editRect);
+ if (cb->editable)
+ painter->fillRect(iconRect, customPal.brush(QPalette::Base));
+ drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap);
+
+ if (cb->direction == Qt::RightToLeft)
+ editRect.translate(-4 - cb->iconSize.width(), 0);
+ else
+ editRect.translate(cb->iconSize.width() + 4, 0);
+ }
+
+ customPal.setBrush(QPalette::All, QPalette::ButtonText, QColor(0, 0, 0, 70));
+
+ QRect rect = editRect.adjusted(1, 0, -8, 0);
+ QString text = option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, rect.width());
+ drawItemText(painter, rect.translated(0, 1),
+ visualAlignment(option->direction, Qt::AlignLeft | Qt::AlignVCenter),
+ customPal, cb->state & State_Enabled, text, QPalette::ButtonText);
+ customPal.setBrush(QPalette::All, QPalette::ButtonText, StyleHelper::panelTextColor());
+ drawItemText(painter, rect,
+ visualAlignment(option->direction, Qt::AlignLeft | Qt::AlignVCenter),
+ customPal, cb->state & State_Enabled, text, QPalette::ButtonText);
+ } else {
+ d->style->drawControl(element, option, painter, widget);
+ }
+ }
+ break;
+
+ case CE_SizeGrip: {
+ painter->save();
+ QColor dark = Qt::white;
+ dark.setAlphaF(0.1);
+ int x, y, w, h;
+ option->rect.getRect(&x, &y, &w, &h);
+ int sw = qMin(h, w);
+ if (h > w)
+ painter->translate(0, h - w);
+ else
+ painter->translate(w - h, 0);
+ int sx = x;
+ int sy = y;
+ int s = 4;
+ painter->setPen(dark);
+ if (option->direction == Qt::RightToLeft) {
+ sx = x + sw;
+ for (int i = 0; i < 4; ++i) {
+ painter->drawLine(x, sy, sx, sw);
+ sx -= s;
+ sy += s;
+ }
+ } else {
+ for (int i = 0; i < 4; ++i) {
+ painter->drawLine(sx, sw, sw, sy);
+ sx += s;
+ sy += s;
+ }
+ }
+ painter->restore();
+ }
+ break;
+
+ case CE_MenuBarEmptyArea: {
+ StyleHelper::menuGradient(painter, option->rect, option->rect);
+ painter->save();
+ painter->setPen(StyleHelper::borderColor());
+ painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight());
+ painter->restore();
+ }
+ break;
+
+ case CE_ToolBar:
+ {
+ QString key;
+ key.sprintf("mh_toolbar %d %d %d", option->rect.width(), option->rect.height(), StyleHelper::baseColor().rgb());;
+
+ QPixmap pixmap;
+ QPainter *p = painter;
+ QRect rect = option->rect;
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ pixmap = QPixmap(option->rect.size());
+ p = new QPainter(&pixmap);
+ rect = QRect(0, 0, option->rect.width(), option->rect.height());
+ }
+
+ bool horizontal = option->state & State_Horizontal;
+ // Map offset for global window gradient
+ QPoint offset = widget->window()->mapToGlobal(option->rect.topLeft()) -
+ widget->mapToGlobal(option->rect.topLeft());
+ QRect gradientSpan;
+ if (widget) {
+ gradientSpan = QRect(offset, widget->window()->size());
+ }
+ if (horizontal)
+ StyleHelper::horizontalGradient(p, gradientSpan, rect);
+ else
+ StyleHelper::verticalGradient(p, gradientSpan, rect);
+
+ painter->setPen(StyleHelper::borderColor());
+
+ if (horizontal) {
+ // Note: This is a hack to determine if we are the topmost
+ // toolbar and menu bar should draw the outline
+ QColor lighter(255, 255, 255, 40);
+ if (widget->mapToParent(rect.topLeft()).y()) {
+ p->drawLine(rect.topLeft(), rect.topRight());
+ p->setPen(lighter);
+ p->drawLine(rect.topLeft() + QPoint(0, 1), rect.topRight() + QPoint(0, 1));
+ } else {
+ p->drawLine(rect.bottomLeft(), rect.bottomRight());
+ p->setPen(lighter);
+ p->drawLine(rect.topLeft(), rect.topRight());
+ }
+ } else {
+ p->drawLine(rect.topLeft(), rect.bottomLeft());
+ p->drawLine(rect.topRight(), rect.bottomRight());
+ }
+
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ painter->drawPixmap(rect.topLeft(), pixmap);
+ p->end();
+ delete p;
+ QPixmapCache::insert(key, pixmap);
+ }
+ }
+ break;
+
+ default:
+ d->style->drawControl(element, option, painter, widget);
+ break;
+ }
+}
+
+void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (!panelWidget(widget))
+ return d->style->drawComplexControl(control, option, painter, widget);
+
+ QRect rect = option->rect;
+ switch (control) {
+ case CC_ToolButton:
+ if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
+ QString buttonType = widget->property("type").toString();
+ QRect button, menuarea;
+ button = subControlRect(control, toolbutton, SC_ToolButton, widget);
+ menuarea = subControlRect(control, toolbutton, SC_ToolButtonMenu, widget);
+
+ State bflags = toolbutton->state;
+ if (bflags & State_AutoRaise) {
+ if (!(bflags & State_MouseOver)) {
+ bflags &= ~State_Raised;
+ }
+ }
+
+ State mflags = bflags;
+ if (toolbutton->activeSubControls & SC_ToolButton)
+ bflags |= State_Sunken;
+ if (toolbutton->activeSubControls & SC_ToolButtonMenu)
+ mflags |= State_Sunken;
+
+ QStyleOption tool(0);
+ tool.palette = toolbutton->palette;
+ if (toolbutton->subControls & SC_ToolButton) {
+ if (buttonType == "dockbutton") {
+ tool.rect = button;
+ tool.state = bflags;
+ drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
+ } else { // paint status bar button style
+ if (bflags & State_Sunken || bflags & State_On)
+ drawCornerImage(d->buttonImage_pressed, painter, option->rect, 2, 2, 2, 2);
+ else if (bflags & State_Enabled) {
+#ifndef Q_WS_MAC
+ if (bflags & State_MouseOver) {
+ drawCornerImage(d->buttonImage, painter, option->rect, 2, 2, 2, 2);
+ QColor shade(255, 255, 255, 50);
+ painter->fillRect(button.adjusted(1, 1, -1, -1), shade);
+ }
+#endif
+ }
+
+ }
+ }
+
+ if (toolbutton->state & State_HasFocus) {
+ QStyleOptionFocusRect fr;
+ fr.QStyleOption::operator=(*toolbutton);
+ fr.rect.adjust(3, 3, -3, -3);
+ if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
+ fr.rect.adjust(0, 0, -pixelMetric(QStyle::PM_MenuButtonIndicator,
+ toolbutton, widget), 0);
+ QPen oldPen = painter->pen();
+ QColor focusColor = StyleHelper::panelTextColor();
+ focusColor.setAlpha(120);
+ QPen outline(focusColor, 1);
+ outline.setStyle(Qt::DotLine);
+ painter->setPen(outline);
+ QRect r = option->rect.adjusted(2, 2, -2, -2);
+ painter->drawRect(r);
+ painter->setPen(oldPen);
+ }
+
+ QStyleOptionToolButton label = *toolbutton;
+ label.palette = panelPalette(option->palette);
+ int fw = pixelMetric(PM_DefaultFrameWidth, option, widget);
+ label.rect = button.adjusted(fw, fw, -fw, -fw);
+ drawControl(CE_ToolButtonLabel, &label, painter, widget);
+
+ if (toolbutton->subControls & SC_ToolButtonMenu) {
+ tool.state = mflags;
+ tool.rect = menuarea.adjusted(1, 1, -1, -1);
+ if (mflags & (State_Sunken | State_On | State_Raised)) {
+ painter->setPen(Qt::gray);
+ painter->drawLine(tool.rect.topLeft(), tool.rect.bottomLeft());
+ if (mflags & (State_Sunken)) {
+ QColor shade(0, 0, 0, 50);
+ painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade);
+ }
+#ifndef Q_WS_MAC
+ else if (mflags & (State_MouseOver)) {
+ QColor shade(255, 255, 255, 50);
+ painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade);
+ }
+#endif
+ }
+ tool.rect = tool.rect.adjusted(2, 2, -2, -2);
+ drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget);
+ } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
+ int mbi = pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
+ QRect ir = toolbutton->rect.adjusted(1, 1, -1, -1);
+ QStyleOptionToolButton newBtn = *toolbutton;
+ newBtn.palette = panelPalette(option->palette);
+ newBtn.rect = QRect(ir.right() + 5 - mbi, ir.height() - mbi + 4, mbi - 6, mbi - 6);
+ QWindowsStyle::drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
+ }
+ }
+ break;
+
+ case CC_ComboBox:
+ {
+ painter->save();
+
+ // Draw tool button
+ drawPrimitive(PE_PanelButtonTool, option, painter, widget);
+
+ // Draw arrow
+ int menuButtonWidth = 16;
+ bool reverse = option->direction == Qt::RightToLeft;
+ int left = !reverse ? rect.right() - menuButtonWidth : rect.left();
+ int right = !reverse ? rect.right() : rect.left() + menuButtonWidth;
+ QRect arrowRect((left + right) / 2 - 5, rect.center().y() - 3, 9, 9);
+ if (option->state & State_On)
+ arrowRect.translate(d->style->pixelMetric(PM_ButtonShiftHorizontal, option, widget),
+ d->style->pixelMetric(PM_ButtonShiftVertical, option, widget));
+ QStyleOption arrowOpt = *option;
+ arrowOpt.rect = arrowRect;
+ QPalette pal = option->palette;
+ pal.setBrush(QPalette::All, QPalette::ButtonText, StyleHelper::panelTextColor());
+ arrowOpt.palette = pal;
+
+ QWindowsStyle::drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget);
+
+ painter->restore();
+ }
+ break;
+ default:
+ d->style->drawComplexControl(control, option, painter, widget);
+ break;
+ }
+}
diff --git a/src/plugins/coreplugin/manhattanstyle.h b/src/plugins/coreplugin/manhattanstyle.h
new file mode 100644
index 0000000000..685a35da66
--- /dev/null
+++ b/src/plugins/coreplugin/manhattanstyle.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2007-$THISYEAR$ $TROLLTECH$. All rights reserved.
+**
+** This file is part of the ManhattanStyle project on Trolltech Labs.
+**
+** $TROLLTECH_GPL_LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef MANHATTANSTYLE_H
+#define MANHATTANSTYLE_H
+
+#include <QStyle>
+#include <QWindowsStyle>
+
+QT_BEGIN_NAMESPACE
+class QLinearGradient;
+class QBrush;
+QT_END_NAMESPACE
+
+class ManhattanStylePrivate;
+
+class ManhattanStyle : public QWindowsStyle
+{
+ Q_OBJECT;
+
+public:
+ ManhattanStyle(const QString &);
+
+ ~ManhattanStyle();
+
+ void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const;
+ void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const;
+ void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const;
+
+ QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const;
+ QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const;
+ QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const;
+
+ SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget = 0) const;
+ QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = 0) const;
+ int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const;
+ QRect itemRect(QPainter *p, const QRect &r, int flags, bool enabled, const QPixmap *pixmap, const QString &text, int len = -1) const;
+ QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const;
+
+ int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const;
+
+ QPalette standardPalette() const;
+
+ void polish(QWidget *widget);
+ void polish(QPalette &pal);
+ void polish(QApplication *app);
+
+ void unpolish(QWidget *widget);
+ void unpolish(QApplication *app);
+
+protected Q_SLOTS:
+ QIcon standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const;
+ int layoutSpacingImplementation(QSizePolicy::ControlType control1,
+ QSizePolicy::ControlType control2,
+ Qt::Orientation orientation,
+ const QStyleOption *option = 0,
+ const QWidget *widget = 0) const;
+
+private:
+ ManhattanStylePrivate *d;
+ Q_DISABLE_COPY(ManhattanStyle)
+};
+
+#endif // MANHATTANSTYLE_H
diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp
new file mode 100644
index 0000000000..a6268fbd25
--- /dev/null
+++ b/src/plugins/coreplugin/messagemanager.cpp
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "messagemanager.h"
+#include "messageoutputwindow.h"
+
+#include <QtGui/QStatusBar>
+#include <QtGui/QApplication>
+
+#include <extensionsystem/pluginmanager.h>
+
+using namespace Core;
+
+MessageManager *MessageManager::m_instance = 0;
+
+MessageManager::MessageManager():
+ m_pm(0),
+ m_messageOutputWindow(0)
+{
+ m_instance = this;
+}
+
+MessageManager::~MessageManager()
+{
+ if (m_pm && m_messageOutputWindow) {
+ m_pm->removeObject(m_messageOutputWindow);
+ delete m_messageOutputWindow;
+ }
+
+ m_instance = 0;
+}
+
+void MessageManager::init(ExtensionSystem::PluginManager *pm)
+{
+ m_pm = pm;
+ m_messageOutputWindow = new Internal::MessageOutputWindow;
+ pm->addObject(m_messageOutputWindow);
+}
+
+void MessageManager::showOutputPane()
+{
+ if (m_messageOutputWindow)
+ m_messageOutputWindow->popup(false);
+}
+
+void MessageManager::displayStatusBarMessage(const QString & /*text*/, int /*ms*/)
+{
+ // TODO: Currently broken, but noone really notices, so...
+ //m_mainWindow->statusBar()->showMessage(text, ms);
+}
+
+void MessageManager::printToOutputPane(const QString &text, bool bringToForeground)
+{
+ if (!m_messageOutputWindow)
+ return;
+ if (bringToForeground)
+ m_messageOutputWindow->popup(false);
+ m_messageOutputWindow->append(text);
+}
diff --git a/src/plugins/coreplugin/messagemanager.h b/src/plugins/coreplugin/messagemanager.h
new file mode 100644
index 0000000000..f2854108d6
--- /dev/null
+++ b/src/plugins/coreplugin/messagemanager.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MESSAGEMANAGER_H
+#define MESSAGEMANAGER_H
+
+#include "core_global.h"
+#include <QtCore/QObject>
+
+namespace ExtensionSystem { class PluginManager; }
+
+namespace Core {
+
+namespace Internal {
+class MessageOutputWindow;
+}
+
+class CORE_EXPORT MessageManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ MessageManager();
+ ~MessageManager();
+
+ void init(ExtensionSystem::PluginManager *pm);
+
+ static MessageManager *instance() { return m_instance; }
+
+ void displayStatusBarMessage(const QString &text, int ms = 0);
+ void showOutputPane();
+
+public slots:
+ void printToOutputPane(const QString &text, bool bringToForeground = true);
+
+private:
+ ExtensionSystem::PluginManager *m_pm;
+ Internal::MessageOutputWindow *m_messageOutputWindow;
+
+ static MessageManager *m_instance;
+};
+
+} // namespace Core
+
+#endif // MESSAGEMANAGER_H
diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp
new file mode 100644
index 0000000000..2ffe82e9df
--- /dev/null
+++ b/src/plugins/coreplugin/messageoutputwindow.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "messageoutputwindow.h"
+
+#include <QtGui/QTextEdit>
+
+using namespace Core::Internal;
+
+MessageOutputWindow::MessageOutputWindow()
+{
+ m_widget = new QTextEdit;
+ m_widget->setReadOnly(true);
+ m_widget->setFrameStyle(QFrame::NoFrame);
+}
+
+MessageOutputWindow::~MessageOutputWindow()
+{
+ delete m_widget;
+}
+
+bool MessageOutputWindow::hasFocus()
+{
+ return m_widget->hasFocus();
+}
+
+bool MessageOutputWindow::canFocus()
+{
+ return true;
+}
+
+void MessageOutputWindow::setFocus()
+{
+ m_widget->setFocus();
+}
+
+void MessageOutputWindow::clearContents()
+{
+ m_widget->clear();
+}
+
+QWidget *MessageOutputWindow::outputWidget(QWidget *parent)
+{
+ m_widget->setParent(parent);
+ return m_widget;
+}
+
+QString MessageOutputWindow::name() const
+{
+ return tr("General");
+}
+
+void MessageOutputWindow::visibilityChanged(bool /*b*/)
+{
+}
+
+void MessageOutputWindow::append(const QString &text)
+{
+ m_widget->append(text);
+}
+
+int MessageOutputWindow::priorityInStatusBar() const
+{
+ return -1;
+}
diff --git a/src/plugins/coreplugin/messageoutputwindow.h b/src/plugins/coreplugin/messageoutputwindow.h
new file mode 100644
index 0000000000..1373ea363d
--- /dev/null
+++ b/src/plugins/coreplugin/messageoutputwindow.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MESSAGEOUTPUTWINDOW_H
+#define MESSAGEOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+QT_BEGIN_NAMESPACE
+class QTextEdit;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Internal {
+
+class MessageOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ MessageOutputWindow();
+ ~MessageOutputWindow();
+
+ QWidget *outputWidget(QWidget *parent);
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+
+ QString name() const;
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool visible);
+
+ void append(const QString &text);
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+private:
+ QTextEdit *m_widget;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // MESSAGEOUTPUTWINDOW_H
diff --git a/src/plugins/coreplugin/mimedatabase.cpp b/src/plugins/coreplugin/mimedatabase.cpp
new file mode 100644
index 0000000000..d49d4728e6
--- /dev/null
+++ b/src/plugins/coreplugin/mimedatabase.cpp
@@ -0,0 +1,1178 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "mimedatabase.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QFile>
+#include <QtCore/QMap>
+#include <QtCore/QMultiHash>
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFileInfo>
+#include <QtCore/QByteArray>
+#include <QtCore/QSharedData>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QTextStream>
+#include <QtCore/QLocale>
+#include <QtXml/QXmlStreamReader>
+
+enum { debugMimeDB = 0 };
+
+// XML tags in mime files
+static const char *mimeInfoTagC = "mime-info";
+static const char *mimeTypeTagC = "mime-type";
+static const char *mimeTypeAttributeC = "type";
+static const char *subClassTagC = "sub-class-of";
+static const char *commentTagC = "comment";
+static const char *globTagC = "glob";
+static const char *aliasTagC = "alias";
+static const char *patternAttributeC = "pattern";
+static const char *localeAttributeC = "xml:lang";
+
+static const char *magicTagC = "magic";
+static const char *priorityAttributeC = "priority";
+static const char *matchTagC = "match";
+static const char *matchValueAttributeC = "value";
+static const char *matchTypeAttributeC = "type";
+static const char *matchStringTypeValueC = "string";
+static const char *matchOffsetAttributeC = "offset";
+
+// Types
+static const char *textTypeC = "text/plain";
+static const char *binaryTypeC = "application/octet-stream";
+
+// UTF16 byte order marks
+static const char bigEndianByteOrderMarkC[] = "\xFE\xFF";
+static const char littleEndianByteOrderMarkC[] = "\xFF\xFE";
+
+// Fallback priorities, must be low.
+enum { BinaryMatchPriority = 1, TextMatchPriority = 2};
+
+/* Parse sth like (<mime-info> being optional):
+ *\code
+?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <!-- Mime types must match the desktop file associations -->
+ <mime-type type="application/vnd.nokia.qt.qmakeprofile">
+ <comment xml:lang="en">Qt QMake Profile</comment>
+ <glob pattern="*.pro"/>
+ </mime-type>
+</mime-info>
+ *\endcode
+*/
+
+namespace Core {
+
+namespace Internal {
+
+// FileMatchContext: Passed on to the mimetypes from the database
+// when looking for a file match. It exists to enable reading the file
+// contents "on demand" (as opposed to each mime type trying to open
+// and read while checking).
+
+class FileMatchContext {
+ Q_DISABLE_COPY(FileMatchContext);
+public:
+ // Max data to be read from a file
+ enum { MaxData = 2048 };
+
+ explicit FileMatchContext(const QFileInfo &fi);
+
+ inline QString fileName() const { return m_fileName; }
+ // Return (cached) first MaxData bytes of file
+ QByteArray data();
+
+private:
+ enum State {
+ // File cannot be read/does not exist
+ NoDataAvailable,
+ // Not read yet
+ DataNotRead,
+ // Available
+ DataRead };
+ const QFileInfo m_fileInfo;
+ const QString m_fileName;
+ State m_state;
+ QByteArray m_data;
+};
+
+FileMatchContext::FileMatchContext(const QFileInfo &fi) :
+ m_fileInfo(fi),
+ m_fileName(fi.fileName()),
+ m_state(fi.isFile() && fi.isReadable() && fi.size() > 0 ? DataNotRead : NoDataAvailable)
+{
+}
+
+QByteArray FileMatchContext::data()
+{
+ // Do we need to read?
+ if (m_state == DataNotRead) {
+ const QString fullName = m_fileInfo.absoluteFilePath();
+ QFile file(fullName);
+ if (file.open(QIODevice::ReadOnly)) {
+ m_data = file.read(MaxData);
+ m_state = DataRead;
+ } else {
+ qWarning("%s failed to open %s: %s\n", Q_FUNC_INFO, fullName.toUtf8().constData(), file.errorString().toUtf8().constData());
+ m_state = NoDataAvailable;
+ }
+ }
+ return m_data;
+}
+
+// The binary fallback matcher for "application/octet-stream".
+class BinaryMatcher : public IMagicMatcher {
+ Q_DISABLE_COPY(BinaryMatcher);
+public:
+ BinaryMatcher() {}
+ virtual bool matches(const QByteArray & /*data*/) const { return true; }
+ virtual int priority() const { return BinaryMatchPriority; }
+};
+
+// A heuristic text file matcher: If the data do not contain any character
+// below tab (9), detect as text.
+class HeuristicTextMagicMatcher : public IMagicMatcher {
+ Q_DISABLE_COPY(HeuristicTextMagicMatcher);
+public:
+ HeuristicTextMagicMatcher() {}
+ virtual bool matches(const QByteArray &data) const;
+ virtual int priority() const { return TextMatchPriority; }
+
+ static bool isTextFile(const QByteArray &data);
+};
+
+bool HeuristicTextMagicMatcher::isTextFile(const QByteArray &data)
+{
+ const int size = data.size();
+ for (int i = 0; i < size; i++) {
+ const char c = data.at(i);
+ if (c >= 0x01 && c < 0x09) // Sure-fire binary
+ return false;
+ if (c == 0) // Check for UTF16
+ return data.startsWith(bigEndianByteOrderMarkC) || data.startsWith(littleEndianByteOrderMarkC);
+ }
+ return true;
+}
+
+bool HeuristicTextMagicMatcher::matches(const QByteArray &data) const
+{
+ const bool rc = isTextFile(data);
+ if (debugMimeDB)
+ qDebug() << Q_FUNC_INFO << " on " << data.size() << " returns " << rc;
+ return rc;
+}
+
+} // namespace Internal
+
+// MagicRule
+MagicRule::MagicRule(const QByteArray &pattern, int startPos, int endPos) :
+ m_pattern(pattern),
+ m_startPos(startPos),
+ m_endPos(endPos)
+{
+}
+
+bool MagicRule::matches(const QByteArray &data) const
+{
+ // Quick check
+ const int dataSize = data.size();
+ if ((m_startPos + m_pattern.size()) >= dataSize)
+ return false;
+ // Most common: some string at position 0:
+ if (m_startPos == 0 && m_startPos == m_endPos)
+ return data.startsWith(m_pattern);
+ // Range
+ const int index = data.indexOf(m_pattern, m_startPos);
+ return index != -1 && index < m_endPos;
+}
+
+MagicRule *MagicRule::createStringRule(const QString &c, int startPos, int endPos)
+{
+ return new MagicRule(c.toUtf8(), startPos, endPos);
+}
+
+// List matcher
+MagicRuleMatcher::MagicRuleMatcher() :
+ m_priority(65535)
+{
+}
+
+void MagicRuleMatcher::add(const MagicRuleSharedPointer &rule)
+{
+ m_list.push_back(rule);
+}
+
+bool MagicRuleMatcher::matches(const QByteArray &data) const
+{
+ const MagicRuleList::const_iterator cend = m_list.constEnd();
+ for (MagicRuleList::const_iterator it = m_list.constBegin(); it != cend; ++it)
+ if ( (*it)->matches(data))
+ return true;
+ return false;
+}
+
+int MagicRuleMatcher::priority() const
+{
+ return m_priority;
+}
+
+void MagicRuleMatcher::setPriority(int p)
+{
+ m_priority = p;
+}
+
+// ---------- MimeTypeData
+class MimeTypeData : public QSharedData {
+public:
+ typedef QHash<QString,QString> LocaleHash;
+ void clear();
+ void debug(QTextStream &str, int indent = 0) const;
+
+ QString type;
+ QString comment;
+
+ LocaleHash localeComments;
+ QStringList aliases;
+ QList<QRegExp> globPatterns;
+ QStringList subClassesOf;
+ QString preferredSuffix;
+ QStringList suffixes;
+
+ typedef QSharedPointer<IMagicMatcher> IMagicMatcherSharedPointer;
+ typedef QList<IMagicMatcherSharedPointer> IMagicMatcherList;
+ IMagicMatcherList magicMatchers;
+};
+
+void MimeTypeData::clear()
+{
+ type.clear();
+ comment.clear();
+ aliases.clear();
+ globPatterns.clear();
+ subClassesOf.clear();
+ preferredSuffix.clear();
+ suffixes.clear();
+ magicMatchers.clear();
+}
+
+void MimeTypeData::debug(QTextStream &str, int indent) const
+{
+ const QString indentS = QString(indent, QLatin1Char(' '));
+ const QString comma = QString(1, QLatin1Char(','));
+ str << indentS << "Type: " << type;
+ if (!aliases.empty())
+ str << " Aliases: " << aliases.join(comma);
+ str << ", magic: " << magicMatchers.size() << '\n';
+ str << indentS << "Comment: " << comment << '\n';
+ if (!subClassesOf.empty())
+ str << indentS << "SubClassesOf: " << subClassesOf.join(comma) << '\n';
+ if (!globPatterns.empty()) {
+ str << indentS << "Glob: ";
+ foreach(const QRegExp &r, globPatterns)
+ str << r.pattern() << ' ';
+ str << '\n';
+ if (!suffixes.empty()) {
+ str << indentS << "Suffixes: " << suffixes.join(comma)
+ << " preferred: " << preferredSuffix << '\n';
+ }
+ }
+ str << '\n';
+}
+
+// ---------------- MimeType
+MimeType::MimeType() :
+ m_d(new MimeTypeData)
+{
+}
+
+MimeType::MimeType(const MimeType &rhs) :
+ m_d(rhs.m_d)
+{
+}
+
+MimeType &MimeType::operator=(const MimeType &rhs)
+{
+ if (this != &rhs)
+ m_d = rhs.m_d;
+ return *this;
+}
+
+MimeType::MimeType(const MimeTypeData &d) :
+ m_d(new MimeTypeData(d))
+{
+}
+
+MimeType::~MimeType()
+{
+}
+
+void MimeType::clear()
+{
+ m_d->clear();
+}
+
+bool MimeType::isNull() const
+{
+ return m_d->type.isEmpty();
+}
+
+MimeType::operator bool() const
+{
+ return !isNull();
+}
+
+bool MimeType::isTopLevel() const
+{
+ return m_d->subClassesOf.empty();
+}
+
+QString MimeType::type() const
+{
+ return m_d->type;
+}
+
+void MimeType::setType(const QString &type)
+{
+ m_d->type = type;
+}
+
+QString MimeType::comment() const
+{
+ return m_d->comment;
+}
+
+void MimeType::setComment(const QString &comment)
+{
+ m_d->comment = comment;
+}
+
+// Return "en", "de", etc. derived from "en_US", de_DE".
+static inline QString systemLanguage()
+{
+ QString name = QLocale::system().name();
+ const int underScorePos = name.indexOf(QLatin1Char('_'));
+ if (underScorePos != -1)
+ name.truncate(underScorePos);
+ return name;
+}
+
+QString MimeType::localeComment(const QString &localeArg) const
+{
+ const QString locale = localeArg.isEmpty() ? systemLanguage() : localeArg;
+ const MimeTypeData::LocaleHash::const_iterator it = m_d->localeComments.constFind(locale);
+ if (it == m_d->localeComments.constEnd())
+ return m_d->comment;
+ return it.value();
+}
+
+void MimeType::setLocaleComment(const QString &locale, const QString &comment)
+{
+ m_d->localeComments[locale] = comment;
+}
+
+QStringList MimeType::aliases() const
+{
+ return m_d->aliases;
+}
+
+void MimeType::setAliases(const QStringList &a)
+{
+ m_d->aliases = a;
+}
+
+QList<QRegExp> MimeType::globPatterns() const
+{
+ return m_d->globPatterns;
+}
+
+void MimeType::setGlobPatterns(const QList<QRegExp> &g)
+{
+ m_d->globPatterns = g;
+}
+
+QStringList MimeType::subClassesOf() const
+{
+ return m_d->subClassesOf;
+}
+
+void MimeType::setSubClassesOf(const QStringList &s)
+{
+ m_d->subClassesOf = s;
+}
+
+QString MimeType::preferredSuffix() const
+{
+ return m_d->preferredSuffix;
+}
+
+bool MimeType::setPreferredSuffix(const QString &s)
+{
+ if (!m_d->suffixes.contains(s)) {
+ qWarning("%s: Attempt to set preferred suffix to '%s', which is not in the list of suffixes: %s.",
+ m_d->type.toUtf8().constData(),
+ s.toUtf8().constData(),
+ m_d->suffixes.join(QLatin1String(",")).toUtf8().constData());
+ return false;
+ }
+ m_d->preferredSuffix = s;
+ return true;
+}
+
+static QString formatFilterString(const QString &description, const QList<QRegExp> &globs)
+{
+ QString rc;
+ if (globs.empty()) // Binary files
+ return rc;
+ {
+ QTextStream str(&rc);
+ str << description;
+ if (!globs.empty()) {
+ str << " (";
+ const int size = globs.size();
+ for (int i = 0; i < size; i++) {
+ if (i)
+ str << ' ';
+ str << globs.at(i).pattern();
+ }
+ str << ')';
+ }
+ }
+ return rc;
+}
+
+QString MimeType::filterString() const
+{
+ // @todo: Use localeComment() once creator is shipped with translations
+ return formatFilterString(comment(), m_d->globPatterns);
+}
+
+bool MimeType::matchesType(const QString &type) const
+{
+ return m_d->type == type || m_d->aliases.contains(type);
+}
+
+unsigned MimeType::matchesFile(const QFileInfo &file) const
+{
+ Internal::FileMatchContext context(file);
+ return matchesFile(context);
+}
+
+unsigned MimeType::matchesFile(Internal::FileMatchContext &c) const
+{
+ // check globs
+ const QList<QRegExp>::const_iterator cend = m_d->globPatterns.constEnd();
+ for (QList<QRegExp>::const_iterator it = m_d->globPatterns.constBegin(); it != cend; ++it)
+ if (it->exactMatch(c.fileName()))
+ return GlobMatchPriority;
+ // Nope, try magic matchers on context data
+ if (m_d->magicMatchers.empty())
+ return 0;
+ const QByteArray data = c.data();
+ if (!data.isEmpty()) {
+ const MimeTypeData::IMagicMatcherList::const_iterator cend = m_d->magicMatchers.constEnd();
+ for (MimeTypeData::IMagicMatcherList::const_iterator it = m_d->magicMatchers.constBegin(); it != cend; ++it)
+ if ((*it)->matches(data))
+ return (*it)->priority();
+ }
+ return 0;
+}
+
+QStringList MimeType::suffixes() const
+{
+ return m_d->suffixes;
+}
+
+void MimeType::setSuffixes(const QStringList &s)
+{
+ m_d->suffixes = s;
+}
+
+void MimeType::addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher)
+{
+ m_d->magicMatchers.push_back(matcher);
+}
+
+QDebug operator<<(QDebug d, const MimeType &mt)
+{
+ QString s;
+ {
+ QTextStream str(&s);
+ mt.m_d->debug(str);
+ }
+ d << s;
+ return d;
+}
+
+namespace Internal {
+
+// MimeDatabase helpers: Generic parser for a sequence of <mime-type>.
+// Calls abstract handler function process for MimeType it finds.
+class BaseMimeTypeParser {
+ Q_DISABLE_COPY(BaseMimeTypeParser);
+public:
+ BaseMimeTypeParser();
+ virtual ~BaseMimeTypeParser() {}
+
+ bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage);
+
+private:
+ // Overwrite to process the sequence of parsed data
+ virtual bool process(const MimeType &t, QString *errorMessage) = 0;
+
+ void addGlobPattern(const QString &pattern, MimeTypeData *d) const;
+
+ enum ParseStage { ParseBeginning,
+ ParseMimeInfo,
+ ParseMimeType,
+ ParseComment,
+ ParseGlobPattern,
+ ParseSubClass,
+ ParseAlias,
+ ParseMagic,
+ ParseMagicMatchRule,
+ ParseOtherMimeTypeSubTag,
+ ParseError };
+
+ static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement);
+
+ const QRegExp m_suffixPattern;
+};
+
+BaseMimeTypeParser:: BaseMimeTypeParser() :
+ // RE to match a suffix glob pattern: "*.ext" (and not sth like "Makefile" or
+ // "*.log[1-9]"
+ m_suffixPattern(QLatin1String("^\\*\\.[\\w]+$"))
+{
+ Q_ASSERT(m_suffixPattern.isValid());
+}
+
+void BaseMimeTypeParser::addGlobPattern(const QString &pattern, MimeTypeData *d) const
+{
+ if (pattern.isEmpty())
+ return;
+ // Collect patterns as a QRegExp list and filter out the plain
+ // suffix ones for our suffix list. Use first one as preferred
+ const QRegExp wildCard(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
+ if (!wildCard.isValid()) {
+ qWarning("%s: Invalid wildcard '%s'.",
+ Q_FUNC_INFO, pattern.toUtf8().constData());
+ return;
+ }
+
+ d->globPatterns.push_back(wildCard);
+ if (m_suffixPattern.exactMatch(pattern)) {
+ const QString suffix = pattern.right(pattern.size() - 2);
+ d->suffixes.push_back(suffix);
+ if (d->preferredSuffix.isEmpty())
+ d->preferredSuffix = suffix;
+ }
+}
+
+BaseMimeTypeParser::ParseStage BaseMimeTypeParser::nextStage(ParseStage currentStage, const QStringRef &startElement)
+{
+ switch (currentStage) {
+ case ParseBeginning:
+ if (startElement == QLatin1String(mimeInfoTagC))
+ return ParseMimeInfo;
+ if (startElement == QLatin1String(mimeTypeTagC))
+ return ParseMimeType;
+ return ParseError;
+ case ParseMimeInfo:
+ return startElement == QLatin1String(mimeTypeTagC) ? ParseMimeType : ParseError;
+ case ParseMimeType:
+ case ParseComment:
+ case ParseGlobPattern:
+ case ParseSubClass:
+ case ParseAlias:
+ case ParseOtherMimeTypeSubTag:
+ case ParseMagicMatchRule:
+ if (startElement == QLatin1String(mimeTypeTagC)) // Sequence of <mime-type>
+ return ParseMimeType;
+ if (startElement == QLatin1String(commentTagC ))
+ return ParseComment;
+ if (startElement == QLatin1String(globTagC))
+ return ParseGlobPattern;
+ if (startElement == QLatin1String(subClassTagC))
+ return ParseSubClass;
+ if (startElement == QLatin1String(aliasTagC))
+ return ParseAlias;
+ if (startElement == QLatin1String(magicTagC))
+ return ParseMagic;
+ return ParseOtherMimeTypeSubTag;
+ case ParseMagic:
+ if (startElement == QLatin1String(matchTagC))
+ return ParseMagicMatchRule;
+ break;
+ case ParseError:
+ break;
+ }
+ return ParseError;
+}
+
+// Parse int number from an (attribute) string)
+static bool parseNumber(const QString &n, int *target, QString *errorMessage)
+{
+ bool ok;
+ *target = n.toInt(&ok);
+ if (!ok) {
+ *errorMessage = QCoreApplication::translate("MimeDatabase", "Not a number '%1'.").arg(n);
+ return false;
+ }
+ return true;
+}
+
+// Evaluate a magic match rule like
+// <match value="must be converted with BinHex" type="string" offset="11"/>
+// <match value="0x9501" type="big16" offset="0:64"/>
+static bool addMagicMatchRule(const QXmlStreamAttributes &atts,
+ MagicRuleMatcher *ruleMatcher,
+ QString *errorMessage)
+{
+ const QString type = atts.value(QLatin1String(matchTypeAttributeC)).toString();
+ if (type != QLatin1String(matchStringTypeValueC)) {
+ qWarning("%s: match type %s is not supported.", Q_FUNC_INFO, type.toUtf8().constData());
+ return true;
+ }
+ const QString value = atts.value(QLatin1String(matchValueAttributeC)).toString();
+ if (value.isEmpty()) {
+ *errorMessage = QCoreApplication::translate("MimeDatabase", "Empty match value detected.");
+ return false;
+ }
+ // Parse for offset as "1" or "1:10"
+ int startPos, endPos;
+ const QString offsetS = atts.value(QLatin1String(matchOffsetAttributeC)).toString();
+ const int colonIndex = offsetS.indexOf(QLatin1Char(':'));
+ const QString startPosS = colonIndex == -1 ? offsetS : offsetS.mid(0, colonIndex);
+ const QString endPosS = colonIndex == -1 ? offsetS : offsetS.mid(colonIndex + 1);
+ if (!parseNumber(startPosS, &startPos, errorMessage) || !parseNumber(endPosS, &endPos, errorMessage))
+ return false;
+ if (debugMimeDB)
+ qDebug() << Q_FUNC_INFO << value << startPos << endPos;
+ ruleMatcher->add(QSharedPointer<MagicRule>(MagicRule::createStringRule(value, startPos, endPos)));
+ return true;
+}
+
+bool BaseMimeTypeParser::parse(QIODevice *dev, const QString &fileName, QString *errorMessage)
+{
+ MimeTypeData data;
+ MagicRuleMatcher *ruleMatcher = 0;
+
+ QXmlStreamReader reader(dev);
+ ParseStage ps = ParseBeginning;
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::StartElement:
+ ps = nextStage(ps, reader.name());
+ switch (ps) {
+ case ParseMimeType: { // start parsing a type
+ const QString type = reader.attributes().value(QLatin1String(mimeTypeAttributeC)).toString();
+ if (type.isEmpty()) {
+ reader.raiseError(QCoreApplication::translate("MimeDatabase", "Missing 'type'-attribute"));
+ } else {
+ data.type = type;
+ }
+ }
+ break;
+ case ParseGlobPattern:
+ addGlobPattern(reader.attributes().value(QLatin1String(patternAttributeC)).toString(), &data);
+ break;
+ case ParseSubClass: {
+ const QString inheritsFrom = reader.attributes().value(QLatin1String(mimeTypeAttributeC)).toString();
+ if (!inheritsFrom.isEmpty())
+ data.subClassesOf.push_back(inheritsFrom);
+ }
+ break;
+ case ParseComment: {
+ // comments have locale attributes. We want the default, English one
+ QString locale = reader.attributes().value(QLatin1String(localeAttributeC)).toString();
+ const QString comment = reader.readElementText();
+ if (locale.isEmpty()) {
+ data.comment = comment;
+ } else {
+ data.localeComments.insert(locale, comment);
+ }
+ }
+ break;
+ case ParseAlias: {
+ const QString alias = reader.attributes().value(QLatin1String(mimeTypeAttributeC)).toString();
+ if (!alias.isEmpty())
+ data.aliases.push_back(alias);
+ }
+ break;
+ case ParseMagic: {
+ int priority = 0;
+ const QString priorityS = reader.attributes().value(QLatin1String(priorityAttributeC)).toString();
+ if (!priorityS.isEmpty()) {
+ if (!parseNumber(priorityS, &priority, errorMessage))
+ return false;
+
+ }
+ ruleMatcher = new MagicRuleMatcher;
+ ruleMatcher->setPriority(priority);
+ }
+ break;
+ case ParseMagicMatchRule:
+ if (!addMagicMatchRule(reader.attributes(), ruleMatcher, errorMessage))
+ return false;
+ break;
+ case ParseError:
+ reader.raiseError(QCoreApplication::translate("MimeDatabase", "Unexpected element <%1>").arg(reader.name().toString()));
+ break;
+ default:
+ break;
+ } // switch nextStage
+ break;
+ // continue switch QXmlStreamReader::Token...
+ case QXmlStreamReader::EndElement: // Finished element
+ if (reader.name() == QLatin1String(mimeTypeTagC)) {
+ if (!process(MimeType(data), errorMessage))
+ return false;
+ data.clear();
+ } else {
+ // Finished a match sequence
+ if (reader.name() == QLatin1String(QLatin1String(magicTagC))) {
+ data.magicMatchers.push_back(QSharedPointer<IMagicMatcher>(ruleMatcher));
+ ruleMatcher = 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ } // switch reader.readNext()
+ }
+
+ if (reader.hasError()) {
+ *errorMessage = QCoreApplication::translate("MimeDatabase", "An error has been encountered at line %1 of %2: %3:").arg(reader.lineNumber()).arg(fileName, reader.errorString());
+ return false;
+ }
+ return true;
+}
+
+} // namespace Internal
+
+// MimeMapEntry: Entry of a type map, consisting of type and level.
+
+enum { Dangling = 32767 };
+
+struct MimeMapEntry {
+ explicit MimeMapEntry(const MimeType &t = MimeType(), int aLevel = Dangling);
+ MimeType type;
+ int level; // hierachy level
+};
+
+MimeMapEntry::MimeMapEntry(const MimeType &t, int aLevel) :
+ type(t),
+ level(aLevel)
+{
+}
+
+/* MimeDatabasePrivate: Requirements for storage:
+ * - Must be robust in case of incomplete hierachies, dangling entries
+ * - Plugins will not load and register their mime types in order
+ * of inheritance.
+ * - Multiple inheritance (several subClassesOf) can occur
+ * - Provide quick lookup by name
+ * - Provide quick lookup by file type.
+ * This basically rules out some pointer-based tree, so the structure choosen
+ * is:
+ * - An alias map <QString->QString> for mapping aliases to types
+ * - A Map <QString-MimeMapEntry> for the types (MimeMapEntry being a pair of
+ * MimeType and (hierarchy) level.
+ * - A map <QString->QString> representing parent->child relations (enabling
+ * recursing over children)
+ * Using strings avoids dangling pointers.
+ * The hierarchy level is used for mapping by file types. When findByFile()
+ * is first called after addMimeType() it recurses over the hierarchy and sets
+ * the hierarchy level of the entries accordingly (0 toplevel, 1 first
+ * order...). It then does several passes over the type map, checking the
+ * globs for maxLevel, maxLevel-1....until it finds a match (idea being to
+ * to check the most specific types first). Starting a recursion from the
+ * leaves is not suitable since it will hit parent nodes several times. */
+
+class MimeDatabasePrivate {
+ Q_DISABLE_COPY(MimeDatabasePrivate)
+public:
+ MimeDatabasePrivate();
+
+ bool addMimeTypes(const QString &fileName, QString *errorMessage);
+ bool addMimeTypes(QIODevice *device, QString *errorMessage);
+ bool addMimeType(MimeType mt);
+
+ // Returns a mime type or Null one if none found
+ MimeType findByType(const QString &type) const;
+ // Returns a mime type or Null one if none found
+ MimeType findByFile(const QFileInfo &f) const;
+
+ bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
+
+ // Return all known suffixes
+ QStringList suffixes() const;
+ QStringList filterStrings() const;
+
+ void debug(QTextStream &str) const;
+
+private:
+ typedef QHash<QString, MimeMapEntry> TypeMimeTypeMap;
+ typedef QHash<QString, QString> AliasMap;
+ typedef QMultiHash<QString, QString> ParentChildrenMap;
+
+ bool addMimeTypes(QIODevice *device, const QString &fileName, QString *errorMessage);
+ inline const QString &resolveAlias(const QString &name) const;
+ MimeType findByFile(const QFileInfo &f, unsigned *priority) const;
+ void determineLevels();
+ void raiseLevelRecursion(MimeMapEntry &e, int level);
+
+ TypeMimeTypeMap m_typeMimeTypeMap;
+ AliasMap m_aliasMap;
+ ParentChildrenMap m_parentChildrenMap;
+ int m_maxLevel;
+};
+
+MimeDatabasePrivate::MimeDatabasePrivate() :
+ m_maxLevel(-1)
+{
+}
+
+namespace Internal {
+ // Parser that builds MimeDB hierarchy by adding to MimeDatabasePrivate
+ class MimeTypeParser : public BaseMimeTypeParser {
+ public:
+ explicit MimeTypeParser(MimeDatabasePrivate &db) : m_db(db) {}
+ private:
+ virtual bool process(const MimeType &t, QString *) { m_db.addMimeType(t); return true; }
+
+ MimeDatabasePrivate &m_db;
+ };
+} // namespace Internal
+
+bool MimeDatabasePrivate::addMimeTypes(QIODevice *device, const QString &fileName, QString *errorMessage)
+{
+ Internal::MimeTypeParser parser(*this);
+ return parser.parse(device, fileName, errorMessage);
+}
+
+bool MimeDatabasePrivate::addMimeTypes(const QString &fileName, QString *errorMessage)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ *errorMessage = QCoreApplication::translate("MimeDatabase", "Cannot open %1: %2").arg(fileName, file.errorString());
+ return false;
+ }
+ return addMimeTypes(&file, fileName, errorMessage);
+}
+
+bool MimeDatabasePrivate::addMimeTypes(QIODevice *device, QString *errorMessage)
+{
+ return addMimeTypes(device, QLatin1String("<stream>"), errorMessage);
+}
+
+bool MimeDatabasePrivate::addMimeType(MimeType mt)
+{
+ if (!mt)
+ return false;
+
+ const QString type = mt.type();
+ // Hack: Add a magic text matcher to "text/plain" and the fallback matcher to
+ // binary types "application/octet-stream"
+ if (type == QLatin1String(textTypeC)) {
+ mt.addMagicMatcher(QSharedPointer<IMagicMatcher>(new Internal::HeuristicTextMagicMatcher));
+ } else {
+ if (type == QLatin1String(binaryTypeC))
+ mt.addMagicMatcher(QSharedPointer<IMagicMatcher>(new Internal::BinaryMatcher));
+ }
+ // insert the type.
+ m_typeMimeTypeMap.insert(type, MimeMapEntry(mt));
+ // Register the children, resolved via alias map. Note that it is still
+ // possible that aliases end up in the map if the parent classes are not inserted
+ // at this point (thus their aliases not known).
+ const QStringList subClassesOf = mt.subClassesOf();
+ if (!subClassesOf.empty()) {
+ const QStringList::const_iterator socend = subClassesOf.constEnd();
+ for (QStringList::const_iterator soit = subClassesOf.constBegin(); soit != socend; ++soit)
+ m_parentChildrenMap.insert(resolveAlias(*soit), type);
+ }
+ // register aliasses
+ const QStringList aliases = mt.aliases();
+ if (!aliases.empty()) {
+ const QStringList::const_iterator cend = aliases.constEnd();
+ for (QStringList::const_iterator it = aliases.constBegin(); it != cend; ++it)
+ m_aliasMap.insert(*it, type);
+ }
+ m_maxLevel = -1; // Mark as dirty
+ return true;
+}
+
+const QString &MimeDatabasePrivate::resolveAlias(const QString &name) const
+{
+ const AliasMap::const_iterator aliasIt = m_aliasMap.constFind(name);
+ return aliasIt == m_aliasMap.constEnd() ? name : aliasIt.value();
+}
+
+void MimeDatabasePrivate::raiseLevelRecursion(MimeMapEntry &e, int level)
+{
+ if (e.level == Dangling || e.level < level)
+ e.level = level;
+ if (m_maxLevel < level)
+ m_maxLevel = level;
+ // At all events recurse over children since nodes might have been
+ // added.
+ const QStringList childTypes = m_parentChildrenMap.values(e.type.type());
+ if (childTypes.empty())
+ return;
+ // look them up in the type->mime type map
+ const int nextLevel = level + 1;
+ const TypeMimeTypeMap::iterator tm_end = m_typeMimeTypeMap.end();
+ const QStringList::const_iterator cend = childTypes.constEnd();
+ for (QStringList::const_iterator it = childTypes.constBegin(); it != cend; ++it) {
+ const TypeMimeTypeMap::iterator tm_it = m_typeMimeTypeMap.find(resolveAlias(*it));
+ if (tm_it == tm_end) {
+ qWarning("%s: Inconsistent mime hierarchy detected, child %s of %s cannot be found.",
+ Q_FUNC_INFO, it->toUtf8().constData(), e.type.type().toUtf8().constData());
+ } else {
+ raiseLevelRecursion(*tm_it, nextLevel);
+ }
+ }
+}
+
+void MimeDatabasePrivate::determineLevels()
+{
+ // Loop over toplevels and recurse down their hierarchies.
+ // Determine top levels by subtracting the children from the parent
+ // set. Note that a toplevel at this point might have 'subclassesOf'
+ // set to some class that is not in the DB, so, checking for an empty
+ // 'subclassesOf' set is not sufficient to find the toplevels.
+ // First, take the parent->child entries whose parent exists and build
+ // sets of parents/children
+ QSet<QString> parentSet, childrenSet;
+ const ParentChildrenMap::const_iterator pcend = m_parentChildrenMap.constEnd();
+ for (ParentChildrenMap::const_iterator it = m_parentChildrenMap.constBegin(); it != pcend; ++it)
+ if (m_typeMimeTypeMap.contains(it.key())) {
+ parentSet.insert(it.key());
+ childrenSet.insert(it.value());
+ }
+ const QSet<QString> topLevels = parentSet.subtract(childrenSet);
+ if (debugMimeDB)
+ qDebug() << Q_FUNC_INFO << "top levels" << topLevels;
+ const TypeMimeTypeMap::iterator tm_end = m_typeMimeTypeMap.end();
+ const QSet<QString>::const_iterator tl_cend = topLevels.constEnd();
+ for (QSet<QString>::const_iterator tl_it = topLevels.constBegin(); tl_it != tl_cend; ++tl_it) {
+ const TypeMimeTypeMap::iterator tm_it = m_typeMimeTypeMap.find(resolveAlias(*tl_it));
+ if (tm_it == tm_end) {
+ qWarning("%s: Inconsistent mime hierarchy detected, top level element %s cannot be found.",
+ Q_FUNC_INFO, tl_it->toUtf8().constData());
+ } else {
+ raiseLevelRecursion(tm_it.value(), 0);
+ }
+ }
+}
+
+bool MimeDatabasePrivate::setPreferredSuffix(const QString &typeOrAlias, const QString &suffix)
+{
+ TypeMimeTypeMap::iterator tit = m_typeMimeTypeMap.find(resolveAlias(typeOrAlias));
+ if (tit != m_typeMimeTypeMap.end())
+ return tit.value().type.setPreferredSuffix(suffix);
+ return false;
+}
+
+// Returns a mime type or Null one if none found
+MimeType MimeDatabasePrivate::findByType(const QString &typeOrAlias) const
+{
+ const TypeMimeTypeMap::const_iterator tit = m_typeMimeTypeMap.constFind(resolveAlias(typeOrAlias));
+ if (tit != m_typeMimeTypeMap.constEnd())
+ return tit.value().type;
+ return MimeType();
+}
+
+// Debugging wrapper around findByFile()
+MimeType MimeDatabasePrivate::findByFile(const QFileInfo &f) const
+{
+ unsigned priority = 0;
+ if (debugMimeDB)
+ qDebug() << '>' << Q_FUNC_INFO << f.fileName();
+ const MimeType rc = findByFile(f, &priority);
+ if (debugMimeDB) {
+ if (rc) {
+ qDebug() << "<MimeDatabase::findByFile: match prio=" << priority << rc.type();
+ } else {
+ qDebug() << "<MimeDatabase::findByFile: no match";
+ }
+ }
+ return rc;
+}
+
+// Returns a mime type or Null one if none found
+MimeType MimeDatabasePrivate::findByFile(const QFileInfo &f, unsigned *priorityPtr) const
+{
+ typedef QList<MimeMapEntry> MimeMapEntryList;
+
+ // Is the hierarchy set up in case we find several matches?
+ if (m_maxLevel < 0) {
+ MimeDatabasePrivate *db = const_cast<MimeDatabasePrivate *>(this);
+ db->determineLevels();
+ }
+ // Starting from max level (most specific): Try to find a match of
+ // best (max) priority. Return if a glob match triggers.
+ *priorityPtr = 0;
+ unsigned maxPriority = 0;
+ MimeType rc;
+ Internal::FileMatchContext context(f);
+ const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
+ for (int level = m_maxLevel; level >= 0; level--)
+ for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
+ if (it.value().level == level) {
+ const unsigned priority = it.value().type.matchesFile(context);
+ if (debugMimeDB > 1)
+ qDebug() << "pass" << level << it.value().type.type() << " matches " << priority;
+ if (priority)
+ if (priority > maxPriority) {
+ rc = it.value().type;
+ maxPriority = priority;
+ // Glob (exact) match?! We are done
+ if (maxPriority == MimeType::GlobMatchPriority) {
+ *priorityPtr = priority;
+ return rc;
+ }
+ }
+ }
+ return rc;
+}
+
+// Return all known suffixes
+QStringList MimeDatabasePrivate::suffixes() const
+{
+ QStringList rc;
+ const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
+ for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
+ rc += it.value().type.suffixes();
+ return rc;
+}
+
+QStringList MimeDatabasePrivate::filterStrings() const
+{
+ QStringList rc;
+ const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
+ for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
+ rc += it.value().type.filterString();
+ return rc;
+}
+
+void MimeDatabasePrivate::debug(QTextStream &str) const
+{
+ str << ">MimeDatabase\n";
+ const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
+ for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it) {
+ str << "Entry level " << it.value().level << '\n';
+ it.value().type.m_d->debug(str);
+ }
+ str << "<MimeDatabase\n";
+}
+
+// --------------- MimeDatabase
+MimeDatabase::MimeDatabase() :
+ m_d(new MimeDatabasePrivate)
+{
+}
+
+MimeDatabase::~MimeDatabase()
+{
+ delete m_d;
+}
+
+MimeType MimeDatabase::findByType(const QString &typeOrAlias) const
+{
+ return m_d->findByType(typeOrAlias);
+}
+
+MimeType MimeDatabase::findByFile(const QFileInfo &f) const
+{
+ return m_d->findByFile(f);
+}
+
+bool MimeDatabase::addMimeType(const MimeType &mt)
+{
+ return m_d->addMimeType(mt);
+}
+
+bool MimeDatabase::addMimeTypes(const QString &fileName, QString *errorMessage)
+{
+ return m_d->addMimeTypes(fileName, errorMessage);
+}
+
+bool MimeDatabase::addMimeTypes(QIODevice *device, QString *errorMessage)
+{
+ return m_d->addMimeTypes(device, errorMessage);
+}
+
+QStringList MimeDatabase::suffixes() const
+{
+ return m_d->suffixes();
+}
+
+QStringList MimeDatabase::filterStrings() const
+{
+ return m_d->filterStrings();
+}
+
+QString MimeDatabase::preferredSuffixByType(const QString &type) const
+{
+ if (const MimeType mt = findByType(type))
+ return mt.preferredSuffix();
+ return QString();
+}
+
+QString MimeDatabase::preferredSuffixByFile(const QFileInfo &f) const
+{
+ if (const MimeType mt = findByFile(f))
+ return mt.preferredSuffix();
+ return QString();
+}
+
+bool MimeDatabase::setPreferredSuffix(const QString &typeOrAlias, const QString &suffix)
+{
+ return m_d->setPreferredSuffix(typeOrAlias, suffix);
+}
+
+QDebug operator<<(QDebug d, const MimeDatabase &mt)
+{
+ QString s;
+ {
+ QTextStream str(&s);
+ mt.m_d->debug(str);
+ }
+ d << s;
+ return d;
+}
+
+} // namespace Core
diff --git a/src/plugins/coreplugin/mimedatabase.h b/src/plugins/coreplugin/mimedatabase.h
new file mode 100644
index 0000000000..d4f96cf8d9
--- /dev/null
+++ b/src/plugins/coreplugin/mimedatabase.h
@@ -0,0 +1,226 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MIMEDATABASE_H
+#define MIMEDATABASE_H
+
+#include <coreplugin/core_global.h>
+#include <QtCore/QStringList>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QByteArray>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+class QRegExp;
+class QDebug;
+class QFileInfo;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class MimeTypeData;
+class MimeDatabasePrivate;
+
+namespace Internal {
+ class BaseMimeTypeParser;
+ class FileMatchContext;
+}
+
+/* Magic (file contents) matcher interface. */
+class CORE_EXPORT IMagicMatcher {
+ Q_DISABLE_COPY(IMagicMatcher)
+protected:
+ IMagicMatcher() {}
+public:
+ // Check for a match on contents of a file
+ virtual bool matches(const QByteArray &data) const = 0;
+ // Return a priority value from 1..100
+ virtual int priority() const = 0;
+ virtual ~IMagicMatcher() {}
+};
+
+/* Utility class: A standard Magic match rule based on contents. Provides
+ * static factory methods for creation (currently only for "string". This can
+ * be extended to handle "little16"/"big16", etc.). */
+class CORE_EXPORT MagicRule {
+ Q_DISABLE_COPY(MagicRule)
+public:
+ explicit MagicRule(const QByteArray &pattern, int startPos, int endPos);
+ bool matches(const QByteArray &data) const;
+
+ // Convenience factory methods
+ static MagicRule *createStringRule(const QString &c, int startPos, int endPos);
+
+private:
+ const QByteArray m_pattern;
+ const int m_startPos;
+ const int m_endPos;
+};
+
+/* Utility class: A Magic matcher that checks a number of rules based on
+ * operator "or". It is used for rules parsed from XML files. */
+class CORE_EXPORT MagicRuleMatcher : public IMagicMatcher {
+ Q_DISABLE_COPY(MagicRuleMatcher)
+public:
+ typedef QSharedPointer<MagicRule> MagicRuleSharedPointer;
+
+ MagicRuleMatcher();
+ void add(const MagicRuleSharedPointer &rule);
+ virtual bool matches(const QByteArray &data) const;
+
+ virtual int priority() const;
+ void setPriority(int p);
+
+private:
+ typedef QList<MagicRuleSharedPointer> MagicRuleList;
+ MagicRuleList m_list;
+ int m_priority;
+};
+
+/* Mime type data used in Qt Creator. Contains most information from
+ * standard mime type XML database files.
+ * Omissions:
+ * - Only magic of type "string" is supported. In addition, C++ classes
+ * derived from IMagicMatcher can be added to check on contents
+ * - acronyms, language-specific comments
+ * Extensions:
+ * - List of suffixes and preferred suffix (derived from glob patterns).
+ */
+class CORE_EXPORT MimeType {
+public:
+ /* Return value of a glob match, which is higher than magic */
+ enum { GlobMatchPriority = 101 };
+
+ MimeType();
+ MimeType(const MimeType&);
+ MimeType &operator=(const MimeType&);
+ ~MimeType();
+
+ void clear();
+ bool isNull() const;
+ operator bool() const;
+
+ bool isTopLevel() const;
+
+ QString type() const;
+ void setType(const QString &type);
+
+ QStringList aliases() const;
+ void setAliases(const QStringList &);
+
+ QString comment() const;
+ void setComment(const QString &comment);
+
+ QString localeComment(const QString &locale = QString() /* en, de...*/) const;
+ void setLocaleComment(const QString &locale, const QString &comment);
+
+ QList<QRegExp> globPatterns() const;
+ void setGlobPatterns(const QList<QRegExp> &);
+
+ QStringList subClassesOf() const;
+ void setSubClassesOf(const QStringList &);
+
+ // Extension over standard mime data
+ QStringList suffixes() const;
+ void setSuffixes(const QStringList &);
+
+ // Extension over standard mime data
+ QString preferredSuffix() const;
+ bool setPreferredSuffix(const QString&);
+
+ // Check for type or one of the aliases
+ bool matchesType(const QString &type) const;
+ // Check glob patterns and magic. Returns the match priority (0 no match,
+ // 1..100 indicating a magic match or GlobMatchPriority indicating an
+ // exact glob match).
+ unsigned matchesFile(const QFileInfo &file) const;
+
+ // Return a filter string usable for a file dialog
+ QString filterString() const;
+
+ // Add magic matcher
+ void addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher);
+
+ friend QDebug operator<<(QDebug d, const MimeType &mt);
+
+private:
+ explicit MimeType(const MimeTypeData &d);
+ unsigned matchesFile(Internal::FileMatchContext &c) const;
+
+ friend class Internal::BaseMimeTypeParser;
+ friend class MimeDatabasePrivate;
+ QSharedDataPointer<MimeTypeData> m_d;
+};
+
+/* A Mime data base to which the plugins can add the mime types they handle.
+ * When adding a "text/plain" to it, the mimetype will receive a magic matcher
+ * that checks for text files that do not match the globs by heuristics.
+ *
+ * A good testcase is to run it over '/usr/share/mime/<*>/<*>.xml' on Linux. */
+
+class CORE_EXPORT MimeDatabase
+{
+ Q_DISABLE_COPY(MimeDatabase)
+public:
+ MimeDatabase();
+
+ ~MimeDatabase();
+
+ bool addMimeTypes(const QString &fileName, QString *errorMessage);
+ bool addMimeTypes(QIODevice *device, QString *errorMessage);
+ bool addMimeType(const MimeType &mt);
+
+ // Returns a mime type or Null one if none found
+ MimeType findByType(const QString &type) const;
+ // Returns a mime type or Null one if none found
+ MimeType findByFile(const QFileInfo &f) const;
+
+ // Convenience
+ QString preferredSuffixByType(const QString &type) const;
+ QString preferredSuffixByFile(const QFileInfo &f) const;
+
+ // Return all known suffixes
+ QStringList suffixes() const;
+ bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
+
+ QStringList filterStrings() const;
+
+ friend QDebug operator<<(QDebug d, const MimeDatabase &mt);
+
+private:
+ MimeDatabasePrivate *m_d;
+};
+
+} // namespace Core
+
+#endif // MIMEDATABASE_H
diff --git a/src/plugins/coreplugin/minisplitter.cpp b/src/plugins/coreplugin/minisplitter.cpp
new file mode 100644
index 0000000000..dfdad9fb53
--- /dev/null
+++ b/src/plugins/coreplugin/minisplitter.cpp
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "minisplitter.h"
+#include "stylehelper.h"
+
+#include <QtGui/QPaintEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QSplitterHandle>
+
+namespace Core {
+namespace Internal {
+
+class MiniSplitterHandle : public QSplitterHandle
+{
+public:
+ MiniSplitterHandle(Qt::Orientation orientation, QSplitter *parent)
+ : QSplitterHandle(orientation, parent)
+ {
+ setMask(QRegion(contentsRect()));
+ setAttribute(Qt::WA_MouseNoMask, true);
+ }
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+};
+
+} // namespace Internal
+} // namespace Core
+
+using namespace Core;
+using namespace Core::Internal;
+
+void MiniSplitterHandle::resizeEvent(QResizeEvent *event)
+{
+ if (orientation() == Qt::Horizontal)
+ setContentsMargins(2, 0, 2, 0);
+ else
+ setContentsMargins(0, 2, 0, 2);
+ setMask(QRegion(contentsRect()));
+ QSplitterHandle::resizeEvent(event);
+}
+
+void MiniSplitterHandle::paintEvent(QPaintEvent *event)
+{
+ QPainter painter(this);
+ painter.fillRect(event->rect(), StyleHelper::borderColor());
+}
+
+QSplitterHandle *MiniSplitter::createHandle()
+{
+ return new MiniSplitterHandle(orientation(), this);
+}
+
+MiniSplitter::MiniSplitter(QWidget *parent)
+ : QSplitter(parent)
+{
+ setHandleWidth(1);
+ setChildrenCollapsible(false);
+ setProperty("minisplitter", true);
+}
+
+MiniSplitter::MiniSplitter(Qt::Orientation orientation)
+ : QSplitter(orientation)
+{
+ setHandleWidth(1);
+ setChildrenCollapsible(false);
+ setProperty("minisplitter", true);
+}
diff --git a/src/plugins/coreplugin/minisplitter.h b/src/plugins/coreplugin/minisplitter.h
new file mode 100644
index 0000000000..aedb2b757c
--- /dev/null
+++ b/src/plugins/coreplugin/minisplitter.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MINISPLITTER_H
+#define MINISPLITTER_H
+
+#include "core_global.h"
+
+#include <QtGui/QSplitter>
+
+QT_BEGIN_NAMESPACE
+class QSplitterHandle;
+QT_END_NAMESPACE
+
+namespace Core {
+
+/*! This is a simple helper-class to obtain mac-style 1-pixel wide splitters */
+class CORE_EXPORT MiniSplitter : public QSplitter
+{
+public:
+ MiniSplitter(QWidget *parent = 0);
+ MiniSplitter(Qt::Orientation orientation);
+
+protected:
+ QSplitterHandle *createHandle();
+};
+
+} // namespace Core
+
+#endif // MINISPLITTER_H
diff --git a/src/plugins/coreplugin/modemanager.cpp b/src/plugins/coreplugin/modemanager.cpp
new file mode 100644
index 0000000000..74027ab391
--- /dev/null
+++ b/src/plugins/coreplugin/modemanager.cpp
@@ -0,0 +1,236 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "modemanager.h"
+#include "fancytabwidget.h"
+#include "fancyactionbar.h"
+#include "mainwindow.h"
+
+#include <aggregation/aggregate.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/icommand.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/coreimpl.h>
+#include <coreplugin/imode.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QDebug>
+#include <QtCore/QSignalMapper>
+#include <QtGui/QAction>
+#include <QtGui/QTabWidget>
+#include <QtGui/QVBoxLayout>
+
+using namespace Core;
+using namespace Core::Internal;
+
+ModeManager *ModeManager::m_instance = 0;
+
+ModeManager::ModeManager(Internal::MainWindow *mainWindow, FancyTabWidget *modeStack):
+ m_mainWindow(mainWindow),
+ m_modeStack(modeStack),
+ m_signalMapper(new QSignalMapper(this))
+{
+ m_instance = this;
+
+ m_actionBar = new FancyActionBar(modeStack);
+ m_modeStack->addCornerWidget(m_actionBar);
+
+ connect(m_modeStack, SIGNAL(currentAboutToShow(int)), SLOT(currentTabAboutToChange(int)));
+ connect(m_modeStack, SIGNAL(currentChanged(int)), SLOT(currentTabChanged(int)));
+ connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(activateMode(QString)));
+}
+
+void ModeManager::init()
+{
+ QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)),
+ this, SLOT(objectAdded(QObject*)));
+ QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)),
+ this, SLOT(aboutToRemoveObject(QObject*)));
+}
+
+void ModeManager::addWidget(QWidget *widget)
+{
+ // We want the actionbar to stay on the bottom
+ // so m_modeStack->cornerWidgetCount() -1 inserts it at the position immediately above
+ // the actionbar
+ m_modeStack->insertCornerWidget(m_modeStack->cornerWidgetCount() -1, widget);
+}
+
+IMode *ModeManager::currentMode() const
+{
+ return m_modes.at(m_modeStack->currentIndex());
+}
+
+int ModeManager::indexOf(const QString &id) const
+{
+ for (int i = 0; i < m_modes.count(); ++i) {
+ if (m_modes.at(i)->uniqueModeName() == id)
+ return i;
+ }
+ qDebug() << "Warning, no such mode:" << id;
+ return -1;
+}
+
+IMode *ModeManager::mode(const QString &id) const
+{
+ const int index = indexOf(id);
+ if (index >= 0)
+ return m_modes.at(index);
+ return 0;
+}
+
+void ModeManager::activateMode(const QString &id)
+{
+ const int index = indexOf(id);
+ if (index >= 0)
+ m_modeStack->setCurrentIndex(index);
+}
+
+void ModeManager::objectAdded(QObject *obj)
+{
+ IMode *mode = Aggregation::query<IMode>(obj);
+ if (!mode)
+ return;
+
+ m_mainWindow->addContextObject(mode);
+
+ // Count the number of modes with a higher priority
+ int index = 0;
+ foreach (const IMode *m, m_modes)
+ if (m->priority() > mode->priority())
+ ++index;
+
+ m_modes.insert(index, mode);
+ m_modeStack->insertTab(index, mode->widget(), mode->icon(), mode->name());
+
+ // Register mode shortcut
+ ActionManagerInterface *am = m_mainWindow->actionManager();
+ const QString shortcutId = QLatin1String("QtCreator.Mode.") + mode->uniqueModeName();
+ QShortcut *shortcut = new QShortcut(m_mainWindow);
+ shortcut->setWhatsThis(tr("Switch to %1 mode").arg(mode->name()));
+ ICommand *cmd = am->registerShortcut(shortcut, shortcutId, QList<int>() << Constants::C_GLOBAL_ID);
+
+ m_modeShortcuts.insert(index, cmd);
+ connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updateModeToolTip()));
+ for (int i = 0; i < m_modeShortcuts.size(); ++i) {
+#ifdef Q_OS_MAC
+ m_modeShortcuts.at(i)->setDefaultKeySequence(QKeySequence(QString("Meta+%1").arg(i+1)));
+#else
+ m_modeShortcuts.at(i)->setDefaultKeySequence(QKeySequence(QString("Ctrl+%1").arg(i+1)));
+#endif
+ }
+
+ m_signalMapper->setMapping(shortcut, mode->uniqueModeName());
+ connect(shortcut, SIGNAL(activated()), m_signalMapper, SLOT(map()));
+}
+
+void ModeManager::updateModeToolTip()
+{
+ ICommand *cmd = qobject_cast<ICommand *>(sender());
+ if (cmd) {
+ int index = m_modeShortcuts.indexOf(cmd);
+ if (index != -1)
+ m_modeStack->setTabToolTip(index, cmd->stringWithAppendedShortcut(cmd->shortcut()->whatsThis()));
+ }
+}
+
+void ModeManager::aboutToRemoveObject(QObject *obj)
+{
+ IMode *mode = Aggregation::query<IMode>(obj);
+ if (!mode)
+ return;
+
+ const int index = m_modes.indexOf(mode);
+ m_modes.remove(index);
+ m_modeShortcuts.remove(index);
+ m_modeStack->removeTab(index);
+
+ m_mainWindow->removeContextObject(mode);
+}
+
+void ModeManager::addAction(ICommand *command, int priority, QMenu *menu)
+{
+ m_actions.insert(command, priority);
+
+ // Count the number of commands with a higher priority
+ int index = 0;
+ foreach (int p, m_actions.values())
+ if (p > priority)
+ ++index;
+
+ m_actionBar->insertAction(index, command->action(), menu);
+}
+
+void ModeManager::currentTabAboutToChange(int index)
+{
+ if (index >= 0) {
+ IMode *mode = m_modes.at(index);
+ if (mode)
+ emit currentModeAboutToChange(mode);
+ }
+}
+
+void ModeManager::currentTabChanged(int index)
+{
+ // Tab index changes to -1 when there is no tab left.
+ if (index >= 0) {
+ IMode *mode = m_modes.at(index);
+
+ // FIXME: This hardcoded context update is required for the Debug and Edit modes, since
+ // they use the editor widget, which is already a context widget so the main window won't
+ // go further up the parent tree to find the mode context.
+ CoreImpl *core = CoreImpl::instance();
+ foreach (const int context, m_addedContexts)
+ core->removeAdditionalContext(context);
+
+ m_addedContexts = mode->context();
+ foreach (const int context, m_addedContexts)
+ core->addAdditionalContext(context);
+ emit currentModeChanged(mode);
+ core->updateContext();
+ }
+}
+
+void ModeManager::setFocusToCurrentMode()
+{
+ IMode *mode = currentMode();
+ Q_ASSERT(mode);
+ QWidget *widget = mode->widget();
+ if (widget) {
+ QWidget *focusWidget = widget->focusWidget();
+ if (focusWidget)
+ focusWidget->setFocus();
+ else
+ widget->setFocus();
+ }
+}
diff --git a/src/plugins/coreplugin/modemanager.h b/src/plugins/coreplugin/modemanager.h
new file mode 100644
index 0000000000..775c8d4a61
--- /dev/null
+++ b/src/plugins/coreplugin/modemanager.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MODEMANAGER_H
+#define MODEMANAGER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QVector>
+
+#include <coreplugin/core_global.h>
+
+QT_BEGIN_NAMESPACE
+class QSignalMapper;
+class QMenu;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class ICommand;
+class IMode;
+
+namespace Internal {
+class FancyTabWidget;
+class FancyActionBar;
+class MainWindow;
+} // namespace Internal
+
+class CORE_EXPORT ModeManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ ModeManager(Internal::MainWindow *mainWindow, Internal::FancyTabWidget *modeStack);
+
+ void init();
+ static ModeManager *instance() { return m_instance; }
+
+ IMode* currentMode() const;
+ IMode* mode(const QString &id) const;
+
+ void addAction(ICommand *command, int priority, QMenu *menu = 0);
+ void addWidget(QWidget *widget);
+
+signals:
+ void currentModeAboutToChange(Core::IMode *mode);
+ void currentModeChanged(Core::IMode *mode);
+
+public slots:
+ void activateMode(const QString &id);
+ void setFocusToCurrentMode();
+
+private slots:
+ void objectAdded(QObject *obj);
+ void aboutToRemoveObject(QObject *obj);
+ void currentTabAboutToChange(int index);
+ void currentTabChanged(int index);
+ void updateModeToolTip();
+
+private:
+ int indexOf(const QString &id) const;
+
+ static ModeManager *m_instance;
+ Internal::MainWindow *m_mainWindow;
+ Internal::FancyTabWidget *m_modeStack;
+ Internal::FancyActionBar *m_actionBar;
+ QMap<ICommand*, int> m_actions;
+ QVector<IMode*> m_modes;
+ QVector<ICommand*> m_modeShortcuts;
+ QSignalMapper *m_signalMapper;
+ QList<int> m_addedContexts;
+};
+
+} // namespace Core
+
+#endif // MODEMANAGER_H
diff --git a/src/plugins/coreplugin/navigationwidget.cpp b/src/plugins/coreplugin/navigationwidget.cpp
new file mode 100644
index 0000000000..0a29c24d7c
--- /dev/null
+++ b/src/plugins/coreplugin/navigationwidget.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "navigationwidget.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/inavigationwidgetfactory.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <extensionsystem/ExtensionSystemInterfaces>
+
+#include <QtGui/QAction>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QToolButton>
+#include <QtGui/QToolBar>
+#include <QtGui/QResizeEvent>
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+
+Q_DECLARE_METATYPE(Core::INavigationWidgetFactory *)
+
+using namespace Core;
+using namespace Core::Internal;
+
+NavigationWidgetPlaceHolder *NavigationWidgetPlaceHolder::m_current = 0;
+
+NavigationWidgetPlaceHolder* NavigationWidgetPlaceHolder::current()
+{
+ return m_current;
+}
+
+NavigationWidgetPlaceHolder::NavigationWidgetPlaceHolder(Core::IMode *mode, QWidget *parent)
+ :QWidget(parent), m_mode(mode)
+{
+ setLayout(new QVBoxLayout);
+ layout()->setMargin(0);
+ connect(Core::ModeManager::instance(), SIGNAL(currentModeAboutToChange(Core::IMode *)),
+ this, SLOT(currentModeAboutToChange(Core::IMode *)));
+}
+
+NavigationWidgetPlaceHolder::~NavigationWidgetPlaceHolder()
+{
+ if (m_current == this) {
+ NavigationWidget::instance()->setParent(0);
+ NavigationWidget::instance()->hide();
+ }
+}
+
+void NavigationWidgetPlaceHolder::applyStoredSize(int width)
+{
+ if (width) {
+ QSplitter *splitter = qobject_cast<QSplitter *>(parentWidget());
+ if (splitter) {
+ // A splitter we need to resize the splitter sizes
+ QList<int> sizes = splitter->sizes();
+ int index = splitter->indexOf(this);
+ int diff = width - sizes.at(index);
+ int adjust = sizes.count() > 1? ( diff / (sizes.count() - 1)) : 0;
+ for(int i=0; i<sizes.count(); ++i) {
+ if (i != index)
+ sizes[i] += adjust;
+ }
+ sizes[index]= width;
+ splitter->setSizes(sizes);
+ } else {
+ QSize s = size();
+ s.setWidth(width);
+ resize(s);
+ }
+ }
+}
+
+// This function does work even though the order in which
+// the placeHolder get the signal is undefined.
+// It does ensure that after all PlaceHolders got the signal
+// m_current points to the current PlaceHolder, or zero if there
+// is no PlaceHolder in this mode
+// And that the parent of the NavigationWidget gets the correct parent
+void NavigationWidgetPlaceHolder::currentModeAboutToChange(Core::IMode *mode)
+{
+ NavigationWidget *navigationWidget = NavigationWidget::instance();
+
+ if (m_current == this) {
+ m_current = 0;
+ navigationWidget->setParent(0);
+ navigationWidget->hide();
+ navigationWidget->placeHolderChanged(m_current);
+ }
+ if (m_mode == mode) {
+ m_current = this;
+
+ int width = navigationWidget->storedWidth();
+
+ layout()->addWidget(navigationWidget);
+ navigationWidget->show();
+
+ applyStoredSize(width);
+ setVisible(navigationWidget->isShown());
+ navigationWidget->placeHolderChanged(m_current);
+ }
+}
+
+NavigationWidget *NavigationWidget::m_instance = 0;
+
+NavigationWidget::NavigationWidget(QAction *toggleSideBarAction)
+ : m_shown(true)
+ , m_suppressed(false)
+ , m_width(0)
+ , m_toggleSideBarAction(toggleSideBarAction)
+{
+ connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)),
+ this, SLOT(objectAdded(QObject*)));
+
+ setOrientation(Qt::Vertical);
+ insertSubItem(0);
+ m_instance = this;
+}
+
+NavigationWidget::~NavigationWidget()
+{
+ m_instance = 0;
+}
+
+NavigationWidget *NavigationWidget::instance()
+{
+ return m_instance;
+}
+
+int NavigationWidget::storedWidth()
+{
+ return m_width;
+}
+
+void NavigationWidget::placeHolderChanged(NavigationWidgetPlaceHolder *holder)
+{
+ m_toggleSideBarAction->setEnabled(holder);
+}
+
+void NavigationWidget::resizeEvent(QResizeEvent *re)
+{
+ if (m_width && re->size().width())
+ m_width = re->size().width();
+ MiniSplitter::resizeEvent(re);
+}
+
+NavigationSubWidget *NavigationWidget::insertSubItem(int position)
+{
+ NavigationSubWidget *nsw = new NavigationSubWidget(this);
+ connect(nsw, SIGNAL(split()), this, SLOT(split()));
+ connect(nsw, SIGNAL(close()), this, SLOT(close()));
+ insertWidget(position, nsw);
+ m_subWidgets.insert(position, nsw);
+ return nsw;
+}
+
+void NavigationWidget::activateSubWidget()
+{
+ QShortcut *original = qobject_cast<QShortcut *>(sender());
+ QString title = m_shortcutMap[original];
+
+ foreach (NavigationSubWidget *subWidget, m_subWidgets)
+ if (subWidget->factory()->displayName() == title) {
+ subWidget->setFocusWidget();
+ return;
+ }
+
+ m_subWidgets.first()->setFactory(title);
+ m_subWidgets.first()->setFocusWidget();
+}
+
+void NavigationWidget::split()
+{
+ NavigationSubWidget *original = qobject_cast<NavigationSubWidget *>(sender());
+ int pos = indexOf(original) + 1;
+ NavigationSubWidget *newnsw = insertSubItem(pos);
+ newnsw->setFactory(original->factory());
+}
+
+void NavigationWidget::close()
+{
+ if (m_subWidgets.count() != 1) {
+ NavigationSubWidget *subWidget = qobject_cast<NavigationSubWidget *>(sender());
+ m_subWidgets.removeOne(subWidget);
+ subWidget->hide();
+ subWidget->deleteLater();
+ } else {
+ setShown(false);
+ }
+}
+
+void NavigationWidget::saveSettings(QSettings *settings)
+{
+ QStringList views;
+ for (int i=0; i<m_subWidgets.count(); ++i) {
+ views.append(m_subWidgets.at(i)->factory()->displayName());
+ }
+ settings->setValue("Navigation/Views", views);
+ settings->setValue("Navigation/Visible", isShown());
+ settings->setValue("Navigation/VerticalPosition", saveState());
+ settings->setValue("Navigation/Width", m_width);
+}
+
+void NavigationWidget::readSettings(QSettings *settings)
+{
+ if (settings->contains("Navigation/Views")) {
+ QStringList views = settings->value("Navigation/Views").toStringList();
+ for (int i=0; i<views.count()-1; ++i) {
+ insertSubItem(0);
+ }
+ for (int i=0; i<views.count(); ++i) {
+ const QString &view = views.at(i);
+ NavigationSubWidget *nsw = m_subWidgets.at(i);
+ nsw->setFactory(view);
+ }
+ }
+
+ if (settings->contains("Navigation/Visible")) {
+ setShown(settings->value("Navigation/Visible").toBool());
+ } else {
+ setShown(true);
+ }
+
+ if (settings->contains("Navigation/VerticalPosition"))
+ restoreState(settings->value("Navigation/VerticalPosition").toByteArray());
+
+ if (settings->contains("Navigation/Width")) {
+ m_width = settings->value("Navigation/Width").toInt();
+ if (!m_width)
+ m_width = 240;
+ } else {
+ m_width = 240; //pixel
+ }
+ // Apply
+ if (NavigationWidgetPlaceHolder::m_current) {
+ NavigationWidgetPlaceHolder::m_current->applyStoredSize(m_width);
+ }
+}
+
+void NavigationWidget::setShown(bool b)
+{
+ if (m_shown == b)
+ return;
+ m_shown = b;
+ if (NavigationWidgetPlaceHolder::m_current)
+ NavigationWidgetPlaceHolder::m_current->setVisible(m_shown && !m_suppressed);
+}
+
+bool NavigationWidget::isShown() const
+{
+ return m_shown;
+}
+
+bool NavigationWidget::isSuppressed() const
+{
+ return m_suppressed;
+}
+
+void NavigationWidget::setSuppressed(bool b)
+{
+ if (m_suppressed == b)
+ return;
+ m_suppressed = b;
+ if (NavigationWidgetPlaceHolder::m_current)
+ NavigationWidgetPlaceHolder::m_current->setVisible(m_shown && !m_suppressed);
+}
+
+void NavigationWidget::objectAdded(QObject * obj)
+{
+ INavigationWidgetFactory *factory = Aggregation::query<INavigationWidgetFactory>(obj);
+ if (!factory)
+ return;
+
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ Core::ActionManagerInterface *am = core->actionManager();
+ QList<int> navicontext = QList<int>() << core->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::C_NAVIGATION_PANE);
+
+ QString displayName = factory->displayName();
+ QShortcut *shortcut = new QShortcut(this);
+ shortcut->setWhatsThis(tr("Activate %1 Pane").arg(displayName));
+ Core::ICommand *cmd = am->registerShortcut(shortcut,
+ displayName + QLatin1String(".FocusShortcut"), navicontext);
+ cmd->setDefaultKeySequence(factory->activationSequence());
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateSubWidget()));
+
+ m_shortcutMap.insert(shortcut, displayName);
+ m_commandMap.insert(displayName, cmd);
+}
+
+////
+// NavigationSubWidget
+////
+
+
+NavigationSubWidget::NavigationSubWidget(NavigationWidget *parentWidget)
+ : m_parentWidget(parentWidget)
+{
+ connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)),
+ this, SLOT(objectAdded(QObject*)));
+ connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)),
+ this, SLOT(aboutToRemoveObject(QObject*)));
+
+ m_navigationComboBox = new NavComboBox(this);
+ m_navigationWidget = 0;
+
+ m_toolbar = new QToolBar(this);
+ m_toolbar->setContentsMargins(0, 0, 0, 0);
+ m_toolbar->addWidget(m_navigationComboBox);
+
+ QToolButton *split = new QToolButton;
+ split->setProperty("type", QLatin1String("dockbutton"));
+ split->setIcon(QIcon(":/qworkbench/images/splitbutton_horizontal.png"));
+ split->setToolTip(tr("Split"));
+ connect(split, SIGNAL(clicked(bool)), this, SIGNAL(split()));
+
+ QToolButton *close = new QToolButton;
+ close->setProperty("type", QLatin1String("dockbutton"));
+ close->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+ close->setToolTip(tr("Close"));
+
+ connect(close, SIGNAL(clicked(bool)), this, SIGNAL(close()));
+
+ QWidget *spacerItem = new QWidget(this);
+ spacerItem->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ m_toolbar->addWidget(spacerItem);
+ m_splitAction = m_toolbar->addWidget(split);
+ m_toolbar->addWidget(close);
+
+ QVBoxLayout *lay = new QVBoxLayout();
+ lay->setMargin(0);
+ lay->setSpacing(0);
+ setLayout(lay);
+ lay->addWidget(m_toolbar);
+
+ connect(m_navigationComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(setCurrentIndex(int)));
+
+ foreach (INavigationWidgetFactory *factory, ExtensionSystem::PluginManager::instance()->getObjects<INavigationWidgetFactory>()) {
+ QVariant v;
+ v.setValue(factory);
+ m_navigationComboBox->addItem(factory->displayName(), v);
+ }
+}
+
+NavigationSubWidget::~NavigationSubWidget()
+{
+}
+
+void NavigationSubWidget::setCurrentIndex(int index)
+{
+ // Remove toolbutton
+ foreach (QWidget *w, m_additionalToolBarWidgets) {
+ delete w;
+ }
+
+ // Remove old Widget
+ delete m_navigationWidget;
+ if (index == -1)
+ return;
+
+ // Get new stuff
+ INavigationWidgetFactory *factory = m_navigationComboBox->itemData(index).value<INavigationWidgetFactory *>();
+ NavigationView n = factory->createWidget();
+ m_navigationWidget = n.widget;
+ layout()->addWidget(m_navigationWidget);
+
+ // Add Toolbutton
+ m_additionalToolBarWidgets = n.doockToolBarWidgets;
+ foreach (QToolButton *w, m_additionalToolBarWidgets) {
+ m_toolbar->insertWidget(m_splitAction, w);
+ }
+}
+
+void NavigationSubWidget::setFocusWidget()
+{
+ if (m_navigationWidget)
+ m_navigationWidget->setFocus();
+}
+
+void NavigationSubWidget::objectAdded(QObject * obj)
+{
+ INavigationWidgetFactory *factory = Aggregation::query<INavigationWidgetFactory>(obj);
+ if (!factory)
+ return;
+
+ QVariant v;
+ v.setValue(factory);
+ m_navigationComboBox->addItem(factory->displayName(), v);
+ //qDebug()<<"added factory :"<<factory<<m_navigationComboBox->findData(v);
+}
+
+void NavigationSubWidget::aboutToRemoveObject(QObject *obj)
+{
+ INavigationWidgetFactory *factory = Aggregation::query<INavigationWidgetFactory>(obj);
+ if (!factory)
+ return;
+ QVariant v;
+ v.setValue(factory);
+ int index = m_navigationComboBox->findData(v);
+ if (index == -1) {
+ qDebug()<<"factory not found not removing" << factory;
+ return;
+ }
+ m_navigationComboBox->removeItem(index);
+}
+
+void NavigationSubWidget::setFactory(INavigationWidgetFactory *factory)
+{
+ QVariant v;
+ v.setValue(factory);
+ int index = m_navigationComboBox->findData(v);
+ if (index == -1)
+ return;
+ m_navigationComboBox->setCurrentIndex(index);
+}
+
+void NavigationSubWidget::setFactory(const QString &name)
+{
+ for (int i = 0; i < m_navigationComboBox->count(); ++i)
+ {
+ INavigationWidgetFactory *factory =
+ m_navigationComboBox->itemData(i).value<INavigationWidgetFactory *>();
+ if (factory->displayName() == name)
+ m_navigationComboBox->setCurrentIndex(i);
+ }
+}
+
+INavigationWidgetFactory *NavigationSubWidget::factory()
+{
+ int index = m_navigationComboBox->currentIndex();
+ if (index == -1)
+ return 0;
+ return m_navigationComboBox->itemData(index).value<INavigationWidgetFactory *>();
+}
+
+Core::ICommand *NavigationSubWidget::command(const QString &title) const
+{
+ const QHash<QString, Core::ICommand*> commandMap = m_parentWidget->commandMap();
+ QHash<QString, Core::ICommand*>::const_iterator r = commandMap.find(title);
+ if (r != commandMap.end())
+ return r.value();
+ return 0;
+}
+
+NavComboBox::NavComboBox(NavigationSubWidget *navSubWidget)
+ : m_navSubWidget(navSubWidget)
+{
+}
+
+bool NavComboBox::event(QEvent *e)
+{
+ if (e->type() == QEvent::ToolTip) {
+ QString txt = currentText();
+ Core::ICommand *cmd = m_navSubWidget->command(txt);
+ if (cmd) {
+ txt = tr("Activate %1").arg(txt);
+ setToolTip(cmd->stringWithAppendedShortcut(txt));
+ } else {
+ setToolTip(txt);
+ }
+ }
+ return QComboBox::event(e);
+}
diff --git a/src/plugins/coreplugin/navigationwidget.h b/src/plugins/coreplugin/navigationwidget.h
new file mode 100644
index 0000000000..d8244f8868
--- /dev/null
+++ b/src/plugins/coreplugin/navigationwidget.h
@@ -0,0 +1,172 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef NAVIGATIONWIDGET_H
+#define NAVIGATIONWIDGET_H
+
+#include <QtGui/QWidget>
+#include <QtGui/QComboBox>
+#include <QtGui/QSplitter>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+#include <coreplugin/minisplitter.h>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+class QShortcut;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class INavigationWidgetFactory;
+class IMode;
+class ICommand;
+
+namespace Internal {
+class NavigationWidget;
+}
+
+class CORE_EXPORT NavigationWidgetPlaceHolder : public QWidget
+{
+ friend class Core::Internal::NavigationWidget;
+ Q_OBJECT
+public:
+ NavigationWidgetPlaceHolder(Core::IMode *mode, QWidget *parent = 0);
+ ~NavigationWidgetPlaceHolder();
+ static NavigationWidgetPlaceHolder* current();
+ void applyStoredSize(int width);
+private slots:
+ void currentModeAboutToChange(Core::IMode *);
+private:
+ Core::IMode *m_mode;
+ static NavigationWidgetPlaceHolder* m_current;
+};
+
+namespace Internal {
+
+class NavigationSubWidget;
+
+class NavigationWidget : public MiniSplitter
+{
+ Q_OBJECT
+public:
+ NavigationWidget(QAction *toggleSideBarAction);
+ ~NavigationWidget();
+
+ void saveSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+ bool isShown() const;
+ void setShown(bool b);
+
+ bool isSuppressed() const;
+ void setSuppressed(bool b);
+
+ static NavigationWidget* instance();
+
+ int storedWidth();
+
+ // Called from the place holders
+ void placeHolderChanged(NavigationWidgetPlaceHolder *holder);
+
+ QHash<QString, Core::ICommand*> commandMap() const { return m_commandMap; }
+
+protected:
+ void resizeEvent(QResizeEvent *);
+private slots:
+ void objectAdded(QObject*);
+ void activateSubWidget();
+ void split();
+ void close();
+
+private:
+ NavigationSubWidget *insertSubItem(int position);
+ QList<NavigationSubWidget *> m_subWidgets;
+ QHash<QShortcut *, QString> m_shortcutMap;
+ QHash<QString, Core::ICommand*> m_commandMap;
+ bool m_shown;
+ bool m_suppressed;
+ int m_width;
+ static NavigationWidget* m_instance;
+ QAction *m_toggleSideBarAction;
+};
+
+class NavigationSubWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ NavigationSubWidget(NavigationWidget *parentWidget);
+ virtual ~NavigationSubWidget();
+
+ INavigationWidgetFactory *factory();
+ void setFactory(INavigationWidgetFactory *factory);
+ void setFactory(const QString &name);
+ void setFocusWidget();
+
+ Core::ICommand *command(const QString &title) const;
+
+signals:
+ void split();
+ void close();
+
+private slots:
+ void objectAdded(QObject*);
+ void aboutToRemoveObject(QObject*);
+ void setCurrentIndex(int);
+
+private:
+ NavigationWidget *m_parentWidget;
+ QComboBox *m_navigationComboBox;
+ QWidget *m_navigationWidget;
+ QToolBar *m_toolbar;
+ QAction *m_splitAction;
+ QList<QToolButton *> m_additionalToolBarWidgets;
+};
+
+class NavComboBox : public QComboBox
+{
+ Q_OBJECT
+
+public:
+ NavComboBox(NavigationSubWidget *navSubWidget);
+
+protected:
+ bool event(QEvent *event);
+
+private:
+ NavigationSubWidget *m_navSubWidget;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // NAVIGATIONWIDGET_H
diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp
new file mode 100644
index 0000000000..92378d72e9
--- /dev/null
+++ b/src/plugins/coreplugin/outputpane.cpp
@@ -0,0 +1,531 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "outputpane.h"
+#include "coreconstants.h"
+#include "ioutputpane.h"
+#include "mainwindow.h"
+#include "modemanager.h"
+
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/iactioncontainer.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/editorgroup.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QComboBox>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QPainter>
+#include <QtGui/QPushButton>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+#include <QtGui/QStackedWidget>
+#include <QDebug>
+
+using namespace Core;
+using namespace Core::Internal;
+
+namespace Core {
+namespace Internal {
+
+class OutputPaneToggleButton : public QPushButton
+{
+public:
+ OutputPaneToggleButton(int number, const QString &text, QWidget *parent = 0);
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *event);
+
+private:
+ QString m_number;
+ QString m_text;
+};
+
+} // namespace Internal
+} // namespace Core
+
+OutputPanePlaceHolder *OutputPanePlaceHolder::m_current = 0;
+
+OutputPanePlaceHolder::OutputPanePlaceHolder(Core::IMode *mode, QWidget *parent)
+ :QWidget(parent), m_mode(mode), m_closeable(true)
+{
+ setVisible(false);
+ setLayout(new QVBoxLayout);
+ QSizePolicy sp;
+ sp.setHorizontalPolicy(QSizePolicy::Preferred);
+ sp.setVerticalPolicy(QSizePolicy::Preferred);
+ sp.setHorizontalStretch(0);
+ setSizePolicy(sp);
+ layout()->setMargin(0);
+ connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
+ this, SLOT(currentModeChanged(Core::IMode *)));
+}
+
+OutputPanePlaceHolder::~OutputPanePlaceHolder()
+{
+ if (m_current == this) {
+ OutputPane::instance()->setParent(0);
+ OutputPane::instance()->hide();
+ }
+}
+
+void OutputPanePlaceHolder::setCloseable(bool b)
+{
+ m_closeable = b;
+}
+
+bool OutputPanePlaceHolder::closeable()
+{
+ return m_closeable;
+}
+
+void OutputPanePlaceHolder::currentModeChanged(Core::IMode *mode)
+{
+ if (m_current == this) {
+ m_current = 0;
+ OutputPane::instance()->setParent(0);
+ OutputPane::instance()->hide();
+ OutputPane::instance()->updateStatusButtons(false);
+ }
+ if (m_mode == mode) {
+ m_current = this;
+ layout()->addWidget(OutputPane::instance());
+ OutputPane::instance()->show();
+ OutputPane::instance()->updateStatusButtons(isVisible());
+ OutputPane::instance()->setCloseable(m_closeable);
+ }
+}
+
+////
+// OutputPane
+////
+
+OutputPane *OutputPane::m_instance = 0;
+
+OutputPane *OutputPane::instance()
+{
+ return m_instance;
+}
+
+void OutputPane::updateStatusButtons(bool visible)
+{
+ int idx = m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt();
+ if (m_buttons.value(idx))
+ m_buttons.value(idx)->setChecked(visible);
+}
+
+OutputPane::OutputPane(const QList<int> &context, QWidget *parent) :
+ QWidget(parent),
+ m_context(context),
+ m_widgetComboBox(new QComboBox),
+ m_clearButton(new QToolButton),
+ m_closeButton(new QToolButton),
+ m_closeAction(0),
+ m_pluginManager(0),
+ m_core(0),
+ m_lastIndex(-1),
+ m_outputWidgetPane(new QStackedWidget),
+ m_opToolBarWidgets(new QStackedWidget)
+{
+ setWindowTitle(tr("Output"));
+ connect(m_widgetComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changePage()));
+
+ m_clearButton->setIcon(QIcon(Constants::ICON_CLEAN_PANE));
+ m_clearButton->setToolTip(tr("Clear"));
+ connect(m_clearButton, SIGNAL(clicked()), this, SLOT(clearPage()));
+
+ m_closeButton->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+ m_closeButton->setProperty("type", QLatin1String("dockbutton"));
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(slotHide()));
+
+ QVBoxLayout *mainlayout = new QVBoxLayout;
+ mainlayout->setSpacing(0);
+ mainlayout->setMargin(0);
+ QToolBar *toolBar = new QToolBar;
+ toolBar->addWidget(m_widgetComboBox);
+ toolBar->addWidget(m_clearButton);
+ toolBar->addWidget(m_opToolBarWidgets);
+ m_closeAction = toolBar->addWidget(m_closeButton);
+ mainlayout->addWidget(toolBar);
+ mainlayout->addWidget(m_outputWidgetPane, 10);
+ setLayout(mainlayout);
+
+ m_buttonsWidget = new QWidget;
+ m_buttonsWidget->setLayout(new QHBoxLayout);
+ m_buttonsWidget->layout()->setContentsMargins(5,0,0,0);
+#ifdef Q_OS_MAC
+ m_buttonsWidget->layout()->setSpacing(16);
+#else
+ m_buttonsWidget->layout()->setSpacing(4);
+#endif
+
+ m_instance = this;
+}
+
+OutputPane::~OutputPane()
+{
+ m_instance = 0;
+}
+
+QWidget *OutputPane::buttonsWidget()
+{
+ return m_buttonsWidget;
+}
+
+void OutputPane::init(ICore *core, ExtensionSystem::PluginManager *pm)
+{
+ m_pluginManager = pm;
+ m_core = core;
+
+ ActionManagerInterface *am = m_core->actionManager();
+ IActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
+
+ // Window->Output Panes
+ IActionContainer *mpanes = am->createMenu(Constants::M_WINDOW_PANES);
+ mwindow->addMenu(mpanes, Constants::G_WINDOW_PANES);
+ mpanes->menu()->setTitle(tr("Output &Panes"));
+
+ QList<IOutputPane*> panes = m_pluginManager->getObjects<IOutputPane>();
+ QMultiMap<int, IOutputPane*> sorted;
+ foreach (IOutputPane* outPane, panes)
+ sorted.insertMulti(outPane->priorityInStatusBar(), outPane);
+
+ QMultiMap<int, IOutputPane*>::const_iterator it, begin;
+ begin = sorted.constBegin();
+ it = sorted.constEnd();
+ int shortcutNumber = 1;
+ do {
+ --it;
+ IOutputPane* outPane = it.value();
+ const int idx = m_outputWidgetPane->addWidget(outPane->outputWidget(this));
+
+ m_pageMap.insert(idx, outPane);
+ connect(outPane, SIGNAL(showPage(bool)), this, SLOT(showPage(bool)));
+ connect(outPane, SIGNAL(hidePage()), this, SLOT(slotHide()));
+ connect(outPane, SIGNAL(togglePage(bool)), this, SLOT(togglePage(bool)));
+
+ QWidget *toolButtonsContainer = new QWidget(m_opToolBarWidgets);
+ QHBoxLayout *toolButtonsLayout = new QHBoxLayout;
+ toolButtonsLayout->setMargin(0);
+ toolButtonsLayout->setSpacing(0);
+ foreach (QWidget *toolButton, outPane->toolBarWidgets())
+ toolButtonsLayout->addWidget(toolButton);
+ toolButtonsLayout->addStretch(5);
+ toolButtonsContainer->setLayout(toolButtonsLayout);
+
+ m_opToolBarWidgets->addWidget(toolButtonsContainer);
+
+ QString actionId = QString("QtCreator.Pane.%1").arg(outPane->name().simplified());
+ actionId.remove(QLatin1Char(' '));
+ QAction *action = new QAction(outPane->name(), this);
+
+ ICommand *cmd = am->registerAction(action, actionId, m_context);
+ if (outPane->priorityInStatusBar() != -1) {
+#ifdef Q_OS_MAC
+ cmd->setDefaultKeySequence(QKeySequence("Ctrl+" + QString::number(shortcutNumber)));
+#else
+ cmd->setDefaultKeySequence(QKeySequence("Alt+" + QString::number(shortcutNumber)));
+#endif
+ }
+ mpanes->addAction(cmd);
+ m_actions.insert(cmd->action(), idx);
+
+ // TODO priority -1
+ if (outPane->priorityInStatusBar() != -1) {
+ QPushButton *button = new OutputPaneToggleButton(shortcutNumber, outPane->name());
+ ++shortcutNumber;
+ m_buttonsWidget->layout()->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(buttonTriggered()));
+ m_buttons.insert(idx, button);
+ }
+
+ // Now add the entry to the combobox, since the first item we add sets the currentIndex, thus we need to be set up for that
+ m_widgetComboBox->addItem(outPane->name(), idx);
+
+ connect(cmd->action(), SIGNAL(triggered()), this, SLOT(shortcutTriggered()));
+ connect(cmd->action(), SIGNAL(changed()), this, SLOT(updateToolTip()));
+ } while(it != begin);
+
+ changePage();
+}
+
+void OutputPane::shortcutTriggered()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (action && m_actions.contains(action)) {
+ int idx = m_actions.value(action);
+ Core::IOutputPane *outputPane = m_pageMap.value(idx);
+ // Now check the special case, the output window is already visible,
+ // we are already on that page
+ // but the outputpane doesn't have focus
+ // then just give it focus
+ // else do the same as clicking on the button does
+ if(OutputPanePlaceHolder::m_current
+ && OutputPanePlaceHolder::m_current->isVisible()
+ && m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt() == idx) {
+ if (!outputPane->hasFocus() && outputPane->canFocus())
+ outputPane->setFocus();
+ else
+ slotHide();
+ } else {
+ outputPane->popup(true);
+ }
+ }
+}
+
+void OutputPane::buttonTriggered()
+{
+ QPushButton *button = qobject_cast<QPushButton *>(sender());
+ QMap<int, QPushButton *>::const_iterator it, end;
+ end = m_buttons.constEnd();
+ for (it = m_buttons.begin(); it != end; ++it) {
+ if (it.value() == button)
+ break;
+ }
+ int idx = it.key();
+
+ if (m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt() == idx &&
+ OutputPanePlaceHolder::m_current &&
+ OutputPanePlaceHolder::m_current->isVisible() &&
+ OutputPanePlaceHolder::m_current->closeable()) {
+ // we should toggle and the page is already visible and we are actually closeable
+ slotHide();
+ } else {
+ showPage(idx, true);
+ }
+}
+
+void OutputPane::updateToolTip()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (action) {
+ QPushButton *button = m_buttons.value(m_actions.value(action));
+ if (button)
+ button->setToolTip(action->toolTip());
+ }
+}
+
+void OutputPane::slotHide()
+{
+ if (OutputPanePlaceHolder::m_current) {
+ OutputPanePlaceHolder::m_current->setVisible(false);
+ int idx = m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt();
+ if (m_buttons.value(idx))
+ m_buttons.value(idx)->setChecked(false);
+ EditorGroup *group = Core::EditorManager::instance()->currentEditorGroup();
+ if (group && group->widget())
+ group->widget()->setFocus();
+ }
+}
+
+int OutputPane::findIndexForPage(IOutputPane *out)
+{
+ if (!out)
+ return -1;
+
+ int stackIndex = -1;
+ QMap<int, IOutputPane*>::const_iterator it = m_pageMap.constBegin();
+ while (it != m_pageMap.constEnd()) {
+ if (it.value() == out) {
+ stackIndex = it.key();
+ break;
+ }
+ ++it;
+ }
+ if (stackIndex > -1)
+ return m_widgetComboBox->findData(stackIndex);
+ else
+ return -1;
+}
+
+void OutputPane::ensurePageVisible(int idx)
+{
+ if (m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt() != idx) {
+ m_widgetComboBox->setCurrentIndex(m_widgetComboBox->findData(idx));
+ } else {
+ changePage();
+ }
+}
+
+
+void OutputPane::showPage(bool focus)
+{
+ int idx = findIndexForPage(qobject_cast<IOutputPane*>(sender()));
+ showPage(idx, focus);
+}
+
+void OutputPane::showPage(int idx, bool focus)
+{
+ IOutputPane *out = m_pageMap.value(idx);
+ if (idx > -1) {
+ if (!OutputPanePlaceHolder::m_current) {
+ // In this mode we don't have a placeholder
+ // switch to the output mode and switch the page
+ ICore *core = m_pluginManager->getObject<ICore>();
+ core->modeManager()->activateMode(Constants::MODE_OUTPUT);
+ ensurePageVisible(idx);
+ } else {
+ // else we make that page visible
+ OutputPanePlaceHolder::m_current->setVisible(true);
+ ensurePageVisible(idx);
+ if (focus && out->canFocus())
+ out->setFocus();
+ }
+ }
+}
+
+void OutputPane::togglePage(bool focus)
+{
+ int idx = findIndexForPage(qobject_cast<IOutputPane*>(sender()));
+ if(OutputPanePlaceHolder::m_current
+ && OutputPanePlaceHolder::m_current->isVisible()
+ && m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt() == idx) {
+ slotHide();
+ } else {
+ showPage(idx, focus);
+ }
+
+}
+
+void OutputPane::setCloseable(bool b)
+{
+ m_closeAction->setVisible(b);
+}
+
+bool OutputPane::closeable()
+{
+ return m_closeButton->isVisibleTo(m_closeButton->parentWidget());
+}
+
+void OutputPane::focusInEvent(QFocusEvent *e)
+{
+ if (m_outputWidgetPane->currentWidget())
+ m_outputWidgetPane->currentWidget()->setFocus(e->reason());
+}
+
+void OutputPane::changePage()
+{
+ if (m_outputWidgetPane->count() <= 0)
+ return;
+
+ if (!m_pageMap.contains(m_lastIndex)) {
+ int idx = m_outputWidgetPane->currentIndex();
+ m_pageMap.value(idx)->visibilityChanged(true);
+ if (m_buttons.value(idx)) {
+ if (OutputPanePlaceHolder::m_current)
+ m_buttons.value(idx)->setChecked(OutputPanePlaceHolder::m_current->isVisible());
+ else
+ m_buttons.value(idx)->setChecked(false);
+ }
+ m_lastIndex = idx;
+ return;
+ }
+
+ int idx = m_widgetComboBox->itemData(m_widgetComboBox->currentIndex()).toInt();
+ m_outputWidgetPane->setCurrentIndex(idx);
+ m_opToolBarWidgets->setCurrentIndex(idx);
+ m_pageMap.value(idx)->visibilityChanged(true);
+ m_pageMap.value(m_lastIndex)->visibilityChanged(false);
+
+ if (m_buttons.value(m_lastIndex))
+ m_buttons.value(m_lastIndex)->setChecked(false);
+
+ if (m_buttons.value(idx)) {
+ if (OutputPanePlaceHolder::m_current)
+ m_buttons.value(idx)->setChecked(OutputPanePlaceHolder::m_current->isVisible());
+ else
+ m_buttons.value(idx)->setChecked(false);
+ }
+
+ m_lastIndex = idx;
+}
+
+void OutputPane::clearPage()
+{
+ if (m_pageMap.contains(m_outputWidgetPane->currentIndex()))
+ m_pageMap.value(m_outputWidgetPane->currentIndex())->clearContents();
+}
+
+
+OutputPaneToggleButton::OutputPaneToggleButton(int number, const QString &text, QWidget *parent)
+ : QPushButton(parent)
+ , m_number(QString::number(number))
+ , m_text(text)
+{
+ setFocusPolicy(Qt::NoFocus);
+ setCheckable(true);
+ setStyleSheet(
+ "QPushButton { border-image: url(:/qworkbench/images/panel_button.png) 2 2 2 19 repeat;"
+ " border-width: 2px 2px 2px 19px; padding-left: -17; padding-right: 4 } "
+ "QPushButton:checked { border-image: url(:/qworkbench/images/panel_button_checked.png) 2 2 2 19 repeat } "
+#ifndef Q_WS_MAC // Mac UI's dont usually do hover
+ "QPushButton:checked:hover { border-image: url(:/qworkbench/images/panel_button_checked_hover.png) 2 2 2 19 repeat } "
+ "QPushButton:pressed:hover { border-image: url(:/qworkbench/images/panel_button_pressed.png) 2 2 2 19 repeat } "
+ "QPushButton:hover { border-image: url(:/qworkbench/images/panel_button_hover.png) 2 2 2 19 repeat } "
+#endif
+ );
+}
+
+QSize OutputPaneToggleButton::sizeHint() const
+{
+ ensurePolished();
+
+ QSize s = fontMetrics().size(Qt::TextSingleLine, m_text);
+
+ // Expand to account for border image set by stylesheet above
+ s.rwidth() += 19 + 5 + 2;
+ s.rheight() += 2 + 2;
+
+ return s.expandedTo(QApplication::globalStrut());
+}
+
+void OutputPaneToggleButton::paintEvent(QPaintEvent *event)
+{
+ // For drawing the style sheet stuff
+ QPushButton::paintEvent(event);
+
+ const QFontMetrics fm = fontMetrics();
+ const int baseLine = (height() - fm.height()) / 2 + fm.ascent();
+ const int numberWidth = fm.width(m_number);
+
+ QPainter p(this);
+ p.setFont(font());
+ p.setPen(Qt::white);
+ p.drawText((20 - numberWidth) / 2, baseLine, m_number);
+ if (!isChecked())
+ p.setPen(Qt::black);
+ int leftPart = 22;
+ p.drawText(leftPart, baseLine, fm.elidedText(m_text, Qt::ElideRight, width() - leftPart - 1));
+}
diff --git a/src/plugins/coreplugin/outputpane.h b/src/plugins/coreplugin/outputpane.h
new file mode 100644
index 0000000000..fcc54745b0
--- /dev/null
+++ b/src/plugins/coreplugin/outputpane.h
@@ -0,0 +1,142 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OUTPUTPANE_H
+#define OUTPUTPANE_H
+
+#include "core_global.h"
+
+#include <QtCore/QMap>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QComboBox;
+class QToolButton;
+class QStackedWidget;
+class QPushButton;
+QT_END_NAMESPACE
+
+namespace ExtensionSystem { class PluginManager; }
+
+namespace Core {
+
+class ICore;
+class IMode;
+class IOutputPane;
+
+namespace Internal {
+class OutputPane;
+}
+
+
+class CORE_EXPORT OutputPanePlaceHolder : public QWidget
+{
+ friend class Core::Internal::OutputPane; // needs to set m_visible and thus access m_current
+ Q_OBJECT
+public:
+ OutputPanePlaceHolder(Core::IMode *mode, QWidget *parent = 0);
+ ~OutputPanePlaceHolder();
+ void setCloseable(bool b);
+ bool closeable();
+ static OutputPanePlaceHolder *getCurrent() { return m_current; }
+
+private slots:
+ void currentModeChanged(Core::IMode *);
+private:
+ Core::IMode *m_mode;
+ bool m_closeable;
+ static OutputPanePlaceHolder* m_current;
+};
+
+namespace Internal {
+
+class OutputPane
+ : public QWidget
+{
+ Q_OBJECT
+
+public:
+ OutputPane(const QList<int> &context, QWidget *parent = 0);
+ ~OutputPane();
+ void init(Core::ICore *core, ExtensionSystem::PluginManager *pm);
+ static OutputPane *instance();
+ const QList<int> &context() const { return m_context; }
+ void setCloseable(bool b);
+ bool closeable();
+ QWidget *buttonsWidget();
+ void updateStatusButtons(bool visible);
+
+public slots:
+ void slotHide();
+ void shortcutTriggered();
+
+protected:
+ void focusInEvent(QFocusEvent *e);
+
+private slots:;
+ void changePage();
+ void showPage(bool focus);
+ void togglePage(bool focus);
+ void clearPage();
+ void updateToolTip();
+ void buttonTriggered();
+
+private:
+ void showPage(int idx, bool focus);
+ void ensurePageVisible(int idx);
+ int findIndexForPage(IOutputPane *out);
+ const QList<int> m_context;
+ QComboBox *m_widgetComboBox;
+ QToolButton *m_clearButton;
+ QToolButton *m_closeButton;
+ QAction *m_closeAction;
+
+ ExtensionSystem::PluginManager *m_pluginManager;
+ Core::ICore *m_core;
+
+ QMap<int, Core::IOutputPane*> m_pageMap;
+ int m_lastIndex;
+
+ QStackedWidget *m_outputWidgetPane;
+ QStackedWidget *m_opToolBarWidgets;
+ QWidget *m_buttonsWidget;
+ QMap<int, QPushButton *> m_buttons;
+ QMap<QAction *, int> m_actions;
+
+ static OutputPane *m_instance;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // OUTPUTPANE_H
diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp
new file mode 100644
index 0000000000..dcf8c9b826
--- /dev/null
+++ b/src/plugins/coreplugin/plugindialog.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plugindialog.h"
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginview.h>
+#include <extensionsystem/plugindetailsview.h>
+#include <extensionsystem/pluginerrorview.h>
+#include <extensionsystem/pluginspec.h>
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QDialog>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QPushButton>
+#include <QtDebug>
+
+using namespace Core::Internal;
+
+PluginDialog::PluginDialog(ExtensionSystem::PluginManager *manager, QWidget *parent)
+ : QDialog(parent)
+ , m_view(new ExtensionSystem::PluginView(manager, this))
+{
+ QVBoxLayout *vl = new QVBoxLayout(this);
+ vl->addWidget(m_view);
+
+ m_detailsButton = new QPushButton(tr("Details"), this);
+ m_errorDetailsButton = new QPushButton(tr("Error Details"), this);
+ m_closeButton = new QPushButton(tr("Close"), this);
+ m_detailsButton->setEnabled(false);
+ m_errorDetailsButton->setEnabled(false);
+ m_closeButton->setEnabled(true);
+ m_closeButton->setDefault(true);
+
+ QHBoxLayout *hl = new QHBoxLayout;
+ hl->addWidget(m_detailsButton);
+ hl->addWidget(m_errorDetailsButton);
+ hl->addStretch(5);
+ hl->addWidget(m_closeButton);
+
+ vl->addLayout(hl);
+
+ resize(650, 400);
+ setWindowTitle(tr("Installed Plugins"));
+
+ connect(m_view, SIGNAL(currentPluginChanged(ExtensionSystem::PluginSpec*)),
+ this, SLOT(updateButtons()));
+ connect(m_view, SIGNAL(pluginActivated(ExtensionSystem::PluginSpec*)),
+ this, SLOT(openDetails(ExtensionSystem::PluginSpec*)));
+ connect(m_detailsButton, SIGNAL(clicked()), this, SLOT(openDetails()));
+ connect(m_errorDetailsButton, SIGNAL(clicked()), this, SLOT(openErrorDetails()));
+ connect(m_closeButton, SIGNAL(clicked()), this, SLOT(accept()));
+ updateButtons();
+}
+
+void PluginDialog::updateButtons()
+{
+ ExtensionSystem::PluginSpec *selectedSpec = m_view->currentPlugin();
+ if (selectedSpec) {
+ m_detailsButton->setEnabled(true);
+ m_errorDetailsButton->setEnabled(selectedSpec->hasError());
+ } else {
+ m_detailsButton->setEnabled(false);
+ m_errorDetailsButton->setEnabled(false);
+ }
+}
+
+
+void PluginDialog::openDetails()
+{
+ openDetails(m_view->currentPlugin());
+}
+
+void PluginDialog::openDetails(ExtensionSystem::PluginSpec *spec)
+{
+ if (!spec)
+ return;
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Plugin Details of %1").arg(spec->name()));
+ QVBoxLayout *layout = new QVBoxLayout;
+ dialog.setLayout(layout);
+ ExtensionSystem::PluginDetailsView *details = new ExtensionSystem::PluginDetailsView(&dialog);
+ layout->addWidget(details);
+ details->update(spec);
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
+ layout->addWidget(buttons);
+ connect(buttons, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ dialog.resize(400, 500);
+ dialog.exec();
+}
+
+void PluginDialog::openErrorDetails()
+{
+ ExtensionSystem::PluginSpec *spec = m_view->currentPlugin();
+ if (!spec)
+ return;
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("Plugin Errors of %1").arg(spec->name()));
+ QVBoxLayout *layout = new QVBoxLayout;
+ dialog.setLayout(layout);
+ ExtensionSystem::PluginErrorView *errors = new ExtensionSystem::PluginErrorView(&dialog);
+ layout->addWidget(errors);
+ errors->update(spec);
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
+ layout->addWidget(buttons);
+ connect(buttons, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ dialog.resize(500, 300);
+ dialog.exec();
+}
+
diff --git a/src/plugins/coreplugin/plugindialog.h b/src/plugins/coreplugin/plugindialog.h
new file mode 100644
index 0000000000..d3c0d312a6
--- /dev/null
+++ b/src/plugins/coreplugin/plugindialog.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINDIALOG_H
+#define PLUGINDIALOG_H
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+QT_END_NAMESPACE
+
+namespace ExtensionSystem {
+class PluginManager;
+class PluginSpec;
+class PluginView;
+}
+
+namespace Core {
+namespace Internal {
+
+class PluginDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ PluginDialog(ExtensionSystem::PluginManager *manager, QWidget *parent);
+
+private slots:
+ void updateButtons();
+ void openDetails();
+ void openDetails(ExtensionSystem::PluginSpec *spec);
+ void openErrorDetails();
+
+private:
+ ExtensionSystem::PluginView *m_view;
+
+ QPushButton *m_detailsButton;
+ QPushButton *m_errorDetailsButton;
+ QPushButton *m_closeButton;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif
diff --git a/src/plugins/coreplugin/progressmanager/futureprogress.cpp b/src/plugins/coreplugin/progressmanager/futureprogress.cpp
new file mode 100644
index 0000000000..2aeb817bc2
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/futureprogress.cpp
@@ -0,0 +1,167 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "futureprogress.h"
+#include "progresspie.h"
+
+#include <QtGui/QColor>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QMenu>
+
+using namespace Core;
+
+FutureProgress::FutureProgress(QWidget *parent)
+ : QWidget(parent),
+ m_progress(new ProgressBar),
+ m_widget(0),
+ m_widgetLayout(new QHBoxLayout)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ setLayout(layout);
+ layout->addWidget(m_progress);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addLayout(m_widgetLayout);
+ m_widgetLayout->setContentsMargins(7, 0, 7, 0);
+ m_widgetLayout->setSpacing(0);
+
+ connect(&m_watcher, SIGNAL(started()), this, SLOT(setStarted()));
+ connect(&m_watcher, SIGNAL(finished()), this, SLOT(setFinished()));
+ connect(&m_watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(setProgressRange(int,int)));
+ connect(&m_watcher, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int)));
+ connect(&m_watcher, SIGNAL(progressTextChanged(const QString&)),
+ this, SLOT(setProgressText(const QString&)));
+ connect(m_progress, SIGNAL(clicked()), this, SLOT(cancel()));
+}
+
+FutureProgress::~FutureProgress()
+{
+ if (m_widget)
+ delete m_widget;
+}
+
+void FutureProgress::setWidget(QWidget *widget)
+{
+ if (m_widget)
+ delete m_widget;
+ QSizePolicy sp = widget->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Ignored);
+ widget->setSizePolicy(sp);
+ m_widget = widget;
+ if (m_widget)
+ m_widgetLayout->addWidget(m_widget);
+}
+
+void FutureProgress::setTitle(const QString &title)
+{
+ m_progress->setTitle(title);
+}
+
+QString FutureProgress::title() const
+{
+ return m_progress->title();
+}
+
+void FutureProgress::cancel()
+{
+ m_watcher.future().cancel();
+}
+
+void FutureProgress::setStarted()
+{
+ m_progress->reset();
+ m_progress->setError(false);
+ m_progress->setRange(m_watcher.progressMinimum(), m_watcher.progressMaximum());
+ m_progress->setValue(m_watcher.progressValue());
+// if (m_watcher.progressMinimum() == 0 && m_watcher.progressMaximum() == 0)
+// m_progress->startAnimation();
+}
+
+void FutureProgress::setFinished()
+{
+// m_progress->stopAnimation();
+ setToolTip(m_watcher.future().progressText());
+ if (m_watcher.future().isCanceled()) {
+ m_progress->setError(true);
+// m_progress->execGlowOut(true);
+ } else {
+ m_progress->setError(false);
+// m_progress->execGlowOut(false);
+ }
+// m_progress->showToolTip();
+ emit finished();
+}
+
+void FutureProgress::setProgressRange(int min, int max)
+{
+ m_progress->setRange(min, max);
+ if (min != 0 || max != 0) {
+// m_progress->setUsingAnimation(false);
+ } else {
+// m_progress->setUsingAnimation(true);
+ if (m_watcher.future().isRunning()) {
+ //m_progress->startAnimation();
+ }
+ }
+}
+
+void FutureProgress::setProgressValue(int val)
+{
+ m_progress->setValue(val);
+}
+
+void FutureProgress::setProgressText(const QString &text)
+{
+ setToolTip(text);
+}
+
+void FutureProgress::setFuture(const QFuture<void> &future)
+{
+ m_watcher.setFuture(future);
+}
+
+QFuture<void> FutureProgress::future() const
+{
+ return m_watcher.future();
+}
+
+void FutureProgress::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ emit clicked();
+ QWidget::mousePressEvent(event);
+}
+
+bool FutureProgress::hasError() const
+{
+ return m_progress->hasError();
+}
diff --git a/src/plugins/coreplugin/progressmanager/futureprogress.h b/src/plugins/coreplugin/progressmanager/futureprogress.h
new file mode 100644
index 0000000000..4f46a4a1fb
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/futureprogress.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FUTUREPROGRESS_H
+#define FUTUREPROGRESS_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QString>
+#include <QtCore/QFuture>
+#include <QtCore/QFutureWatcher>
+#include <QtGui/QWidget>
+#include <QtGui/QIcon>
+#include <QtGui/QAction>
+#include <QtGui/QProgressBar>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QHBoxLayout>
+
+class ProgressBar;
+
+namespace Core {
+
+class CORE_EXPORT FutureProgress : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FutureProgress(QWidget *parent = 0);
+ ~FutureProgress();
+
+ void setFuture(const QFuture<void> &future);
+ QFuture<void> future() const;
+
+ void setTitle(const QString &title);
+ QString title() const;
+
+ bool hasError() const;
+
+ void setWidget(QWidget *widget);
+ QWidget *widget() const { return m_widget; }
+
+signals:
+ void clicked();
+ void finished();
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+
+private slots:
+ void cancel();
+ void setStarted();
+ void setFinished();
+ void setProgressRange(int min, int max);
+ void setProgressValue(int val);
+ void setProgressText(const QString &text);
+
+private:
+ QFutureWatcher<void> m_watcher;
+ ProgressBar *m_progress;
+ QWidget *m_widget;
+ QHBoxLayout *m_widgetLayout;
+};
+
+} // namespace Core
+#endif // FUTUREPROGRESS_H
diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp
new file mode 100644
index 0000000000..6e4e15644e
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "progressmanager.h"
+#include "progressview.h"
+#include "coreimpl.h"
+#include "baseview.h"
+
+#include "coreconstants.h"
+#include "uniqueidmanager.h"
+#include "viewmanagerinterface.h"
+
+using namespace Core;
+using namespace Core::Internal;
+
+ProgressManager::ProgressManager(QObject *parent) :
+ ProgressManagerInterface(parent)
+{
+ m_progressView = new ProgressView;
+ ICore *core = CoreImpl::instance();
+ connect(core, SIGNAL(coreAboutToClose()), this, SLOT(cancelAllRunningTasks()));
+}
+
+ProgressManager::~ProgressManager()
+{
+}
+
+void ProgressManager::init()
+{
+
+}
+
+void ProgressManager::cancelTasks(const QString &type)
+{
+ QMap<QFutureWatcher<void> *, QString>::iterator task = m_runningTasks.begin();
+ while (task != m_runningTasks.end()) {
+ if (task.value() != type) {
+ ++task;
+ continue;
+ }
+ disconnect(task.key(), SIGNAL(finished()), this, SLOT(taskFinished()));
+ task.key()->cancel();
+ delete task.key();
+ task = m_runningTasks.erase(task);
+ }
+}
+
+void ProgressManager::cancelAllRunningTasks()
+{
+ QMap<QFutureWatcher<void> *, QString>::const_iterator task = m_runningTasks.constBegin();
+ while (task != m_runningTasks.constEnd()) {
+ disconnect(task.key(), SIGNAL(finished()), this, SLOT(taskFinished()));
+ task.key()->cancel();
+ delete task.key();
+ ++task;
+ }
+ m_runningTasks.clear();
+}
+
+FutureProgress *ProgressManager::addTask(const QFuture<void> &future, const QString &title, const QString &type, PersistentType persistency)
+{
+ QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
+ m_runningTasks.insert(watcher, type);
+ connect(watcher, SIGNAL(finished()), this, SLOT(taskFinished()));
+ watcher->setFuture(future);
+ return m_progressView->addTask(future, title, type, persistency);
+}
+
+QWidget *ProgressManager::progressView()
+{
+ return m_progressView;
+}
+
+void ProgressManager::taskFinished()
+{
+ QObject *taskObject = sender();
+ Q_ASSERT(taskObject);
+ QFutureWatcher<void> *task = static_cast<QFutureWatcher<void> *>(taskObject);
+ m_runningTasks.remove(task);
+ delete task;
+}
diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.h b/src/plugins/coreplugin/progressmanager/progressmanager.h
new file mode 100644
index 0000000000..0c40dcc0fa
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progressmanager.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROGRESSMANAGER_H
+#define PROGRESSMANAGER_H
+
+#include "progressmanagerinterface.h"
+
+#include <QtCore/QPointer>
+#include <QtCore/QList>
+#include <QtCore/QFutureWatcher>
+
+namespace Core {
+
+namespace Internal {
+
+class ProgressView;
+
+class ProgressManager : public Core::ProgressManagerInterface
+{
+ Q_OBJECT
+public:
+ ProgressManager(QObject *parent = 0);
+ ~ProgressManager();
+ void init();
+
+ FutureProgress *addTask(const QFuture<void> &future, const QString &title, const QString &type, PersistentType persistency);
+
+ QWidget *progressView();
+
+public slots:
+ void cancelTasks(const QString &type);
+
+private slots:
+ void taskFinished();
+ void cancelAllRunningTasks();
+private:
+ QPointer<ProgressView> m_progressView;
+ QMap<QFutureWatcher<void> *, QString> m_runningTasks;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //PROGRESSMANAGER_H
diff --git a/src/plugins/coreplugin/progressmanager/progressmanagerinterface.h b/src/plugins/coreplugin/progressmanager/progressmanagerinterface.h
new file mode 100644
index 0000000000..6a89293467
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progressmanagerinterface.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROGRESSMANAGERINTERFACE_H
+#define PROGRESSMANAGERINTERFACE_H
+
+#include <coreplugin/core_global.h>
+#include <coreplugin/progressmanager/futureprogress.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QFuture>
+#include <QtGui/QIcon>
+
+namespace Core {
+
+class CORE_EXPORT ProgressManagerInterface : public QObject
+{
+ Q_OBJECT
+public:
+ enum PersistentType { CloseOnSuccess, KeepOnFinish };
+
+ ProgressManagerInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ProgressManagerInterface() {}
+
+ virtual FutureProgress *addTask(const QFuture<void> &future, const QString &title, const QString &type, PersistentType persistency = KeepOnFinish) = 0;
+
+public slots:
+ virtual void cancelTasks(const QString &type) = 0;
+};
+
+} //namespace
+
+#endif //PROGRESSMANAGERINTERFACE_H
diff --git a/src/plugins/coreplugin/progressmanager/progresspie.cpp b/src/plugins/coreplugin/progressmanager/progresspie.cpp
new file mode 100644
index 0000000000..7a237fe5d9
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progresspie.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "progresspie.h"
+#include "stylehelper.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QFont>
+#include <QtGui/QBrush>
+#include <QtGui/QColor>
+#include <QtDebug>
+
+ProgressBar::ProgressBar(QWidget *parent)
+ : QProgressBar(parent), m_error(false)
+{
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+}
+
+ProgressBar::~ProgressBar()
+{
+
+}
+
+QString ProgressBar::title() const
+{
+ return m_title;
+}
+
+bool ProgressBar::hasError() const
+{
+ return m_error;
+}
+
+
+void ProgressBar::setTitle(const QString &title)
+{
+ m_title = title;
+}
+
+void ProgressBar::setError(bool on)
+{
+ m_error = on;
+ update();
+}
+
+QSize ProgressBar::sizeHint() const
+{
+ QSize s;
+ s.setWidth(50);
+ s.setHeight(fontMetrics().height() * 2);
+ return s;
+}
+
+namespace { const int INDENT = 7; }
+
+void ProgressBar::mousePressEvent(QMouseEvent *event)
+{
+ if (event->modifiers() == Qt::NoModifier
+ && event->x() >= size().width()-INDENT-m_progressHeight) {
+ event->accept();
+ emit clicked();
+ return;
+ }
+ QProgressBar::mousePressEvent(event);
+}
+
+void ProgressBar::paintEvent(QPaintEvent *)
+{
+ // TODO move font into stylehelper
+ // TODO use stylehelper white
+
+ double range = maximum() - minimum();
+ double percent = 0.50;
+ if (range != 0)
+ percent = (value() - minimum()) / range;
+ if(percent > 1)
+ percent = 1;
+ else if(percent < 0)
+ percent = 0;
+
+ QPainter p(this);
+ QFont boldFont(p.font());
+ boldFont.setPointSizeF(StyleHelper::sidebarFontSize());
+ boldFont.setBold(true);
+ p.setFont(boldFont);
+ QFontMetrics fm(boldFont);
+
+ // Draw separator
+ int h = fm.height();
+ p.setPen(QColor(0, 0, 0, 70));
+ p.drawLine(0,0, size().width(), 0);
+
+ p.setPen(QColor(255, 255, 255, 70));
+ p.drawLine(0, 1, size().width(), 1);
+
+ p.setPen(StyleHelper::panelTextColor());
+ p.drawText(QPoint(7, h+1), m_title);
+
+ m_progressHeight = h-4;
+ m_progressHeight += ((m_progressHeight % 2) + 1) % 2; // make odd
+ // draw outer rect
+ QRect rect(INDENT, h+6, size().width()-2*INDENT-m_progressHeight+1, m_progressHeight-1);
+ p.setPen(StyleHelper::panelTextColor());
+ p.drawRect(rect);
+
+ // draw inner rect
+ QColor c = StyleHelper::panelTextColor();
+ c.setAlpha(180);
+ p.setPen(Qt::NoPen);
+ p.setBrush(c);
+ QRect inner = rect.adjusted(2, 2, -1, -1);
+ inner.adjust(0, 0, qRound((percent - 1) * inner.width()), 0);
+ if (m_error) {
+ // TODO this is not fancy enough
+ QColor red(255, 0, 0, 180);
+ p.setBrush(red);
+ // avoid too small red bar
+ if (inner.width() < 10)
+ inner.adjust(0, 0, 10 - inner.width(), 0);
+ } else if (value() == maximum()) {
+ QColor green(140, 255, 140, 180);
+ p.setBrush(green);
+ }
+ p.drawRect(inner);
+
+ if (value() < maximum() && !m_error) {
+ // draw cancel thingy
+ // TODO this is quite ugly at the moment
+ p.setPen(StyleHelper::panelTextColor());
+ p.setBrush(QBrush(Qt::NoBrush));
+ QRect cancelRect(size().width()-INDENT-m_progressHeight+3, h+6+1, m_progressHeight-3, m_progressHeight-3);
+ p.drawRect(cancelRect);
+ p.setPen(c);
+ p.drawLine(cancelRect.center()+QPoint(-1,-1), cancelRect.center()+QPoint(+3,+3));
+ p.drawLine(cancelRect.center()+QPoint(+3,-1), cancelRect.center()+QPoint(-1,+3));
+ }
+}
diff --git a/src/plugins/coreplugin/progressmanager/progresspie.h b/src/plugins/coreplugin/progressmanager/progresspie.h
new file mode 100644
index 0000000000..dfeb33e558
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progresspie.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROGRESSPIE_H
+#define PROGRESSPIE_H
+
+#include <QtCore/QString>
+#include <QtGui/QWidget>
+#include <QtGui/QProgressBar>
+#include <QtGui/QMouseEvent>
+
+class ProgressBar : public QProgressBar
+{
+ Q_OBJECT
+public:
+ ProgressBar(QWidget *parent = 0);
+ ~ProgressBar();
+
+ QString title() const;
+ void setTitle(const QString &title);
+ // TODO rename setError
+ void setError(bool on);
+ bool hasError() const;
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *);
+
+signals:
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+
+private:
+ QString m_text;
+ QString m_title;
+ bool m_error;
+ int m_progressHeight;
+};
+
+#endif // PROGRESSPIE_H
diff --git a/src/plugins/coreplugin/progressmanager/progressview.cpp b/src/plugins/coreplugin/progressmanager/progressview.cpp
new file mode 100644
index 0000000000..bb0008056b
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progressview.cpp
@@ -0,0 +1,142 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "progressview.h"
+#include "futureprogress.h"
+
+#include <QtGui/QHBoxLayout>
+
+using namespace Core;
+using namespace Core::Internal;
+
+ProgressView::ProgressView(QWidget *parent)
+: QWidget(parent)
+{
+ m_layout = new QVBoxLayout;
+ setLayout(m_layout);
+ m_layout->setMargin(0);
+ m_layout->setSpacing(0);
+ setWindowTitle(tr("Processes"));
+}
+
+ProgressView::~ProgressView()
+{
+ qDeleteAll(m_taskList);
+ m_taskList.clear();
+ m_type.clear();
+ m_keep.clear();
+}
+
+FutureProgress *ProgressView::addTask(const QFuture<void> &future,
+ const QString &title,
+ const QString &type,
+ ProgressManagerInterface::PersistentType persistency)
+{
+ removeOldTasks(type);
+ if (m_taskList.size() == 3)
+ removeOneOldTask();
+ FutureProgress *progress = new FutureProgress(this);
+ progress->setTitle(title);
+ progress->setFuture(future);
+ m_layout->insertWidget(0, progress);
+ m_taskList.append(progress);
+ m_type.insert(progress, type);
+ m_keep.insert(progress, (persistency == ProgressManagerInterface::KeepOnFinish));
+ connect(progress, SIGNAL(finished()), this, SLOT(slotFinished()));
+ return progress;
+}
+
+void ProgressView::removeOldTasks(const QString &type, bool keepOne)
+{
+ bool firstFound = !keepOne; // start with false if we want to keep one
+ QList<FutureProgress *>::iterator i = m_taskList.end();
+ while (i != m_taskList.begin()) {
+ --i;
+ if (m_type.value(*i) == type) {
+ if (firstFound && (*i)->future().isFinished()) {
+ deleteTask(*i);
+ i = m_taskList.erase(i);
+ }
+ firstFound = true;
+ }
+ }
+}
+
+void ProgressView::deleteTask(FutureProgress *progress)
+{
+ m_type.remove(progress);
+ m_keep.remove(progress);
+ layout()->removeWidget(progress);
+ progress->deleteLater();
+}
+
+void ProgressView::removeOneOldTask()
+{
+ if (m_taskList.isEmpty())
+ return;
+ // look for oldest ended process
+ for (QList<FutureProgress *>::iterator i = m_taskList.begin(); i != m_taskList.end(); ++i) {
+ if ((*i)->future().isFinished()) {
+ deleteTask(*i);
+ i = m_taskList.erase(i);
+ return;
+ }
+ }
+ // no ended process, look for a task type with multiple running tasks and remove the oldest one
+ for (QList<FutureProgress *>::iterator i = m_taskList.begin(); i != m_taskList.end(); ++i) {
+ QString type = m_type.value(*i);
+ if (m_type.keys(type).size() > 1) { // don't care for optimizations it's only a handful of entries
+ deleteTask(*i);
+ i = m_taskList.erase(i);
+ return;
+ }
+ }
+
+ // no ended process, no type with multiple processes, just remove the oldest task
+ FutureProgress *task = m_taskList.takeFirst();
+ deleteTask(task);
+}
+
+void ProgressView::removeTask(FutureProgress *task)
+{
+ m_taskList.removeAll(task);
+ deleteTask(task);
+}
+
+void ProgressView::slotFinished()
+{
+ FutureProgress *progress = qobject_cast<FutureProgress *>(sender());
+ Q_ASSERT(progress);
+ if (m_keep.contains(progress) && !m_keep.value(progress) && !progress->hasError())
+ removeTask(progress);
+ removeOldTasks(m_type.value(progress), true);
+}
diff --git a/src/plugins/coreplugin/progressmanager/progressview.h b/src/plugins/coreplugin/progressmanager/progressview.h
new file mode 100644
index 0000000000..7e832f92f2
--- /dev/null
+++ b/src/plugins/coreplugin/progressmanager/progressview.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROGRESSVIEW_H
+#define PROGRESSVIEW_H
+
+#include "progressmanagerinterface.h"
+
+#include <QtCore/QFuture>
+#include <QtGui/QWidget>
+#include <QtGui/QIcon>
+#include <QtGui/QVBoxLayout>
+
+namespace Core {
+
+class FutureProgress;
+
+namespace Internal {
+
+class ProgressView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ProgressView(QWidget *parent = 0);
+ ~ProgressView();
+
+ /** The returned FutureProgress instance is guaranteed to live till next main loop event processing (deleteLater). */
+ FutureProgress *addTask(const QFuture<void> &future,
+ const QString &title,
+ const QString &type,
+ ProgressManagerInterface::PersistentType persistency);
+
+private slots:
+ void slotFinished();
+
+private:
+ void removeOldTasks(const QString &type, bool keepOne = false);
+ void removeOneOldTask();
+ void removeTask(FutureProgress *task);
+ void deleteTask(FutureProgress *task);
+
+ QVBoxLayout *m_layout;
+ QList<FutureProgress *> m_taskList;
+ QHash<FutureProgress *, QString> m_type;
+ QHash<FutureProgress *, bool> m_keep;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //PROGRESSVIEW_H
diff --git a/src/plugins/coreplugin/rightpane.cpp b/src/plugins/coreplugin/rightpane.cpp
new file mode 100644
index 0000000000..90db8df7c2
--- /dev/null
+++ b/src/plugins/coreplugin/rightpane.cpp
@@ -0,0 +1,242 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "rightpane.h"
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QSplitter>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QTextEdit>
+#include <coreplugin/modemanager.h>
+#include <extensionsystem/pluginmanager.h>
+
+using namespace Core;
+using namespace Core::Internal;
+
+RightPanePlaceHolder *RightPanePlaceHolder::m_current = 0;
+
+RightPanePlaceHolder* RightPanePlaceHolder::current()
+{
+ return m_current;
+}
+
+RightPanePlaceHolder::RightPanePlaceHolder(Core::IMode *mode, QWidget *parent)
+ :QWidget(parent), m_mode(mode)
+{
+ setLayout(new QVBoxLayout);
+ layout()->setMargin(0);
+ connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
+ this, SLOT(currentModeChanged(Core::IMode *)));
+}
+
+RightPanePlaceHolder::~RightPanePlaceHolder()
+{
+ if (m_current == this) {
+ RightPaneWidget::instance()->setParent(0);
+ RightPaneWidget::instance()->hide();
+ }
+}
+
+void RightPanePlaceHolder::applyStoredSize(int width)
+{
+ if (width) {
+ QSplitter *splitter = qobject_cast<QSplitter *>(parentWidget());
+ if (splitter) {
+ // A splitter we need to resize the splitter sizes
+ QList<int> sizes = splitter->sizes();
+ int index = splitter->indexOf(this);
+ int diff = width - sizes.at(index);
+ int adjust = sizes.count() > 1? ( diff / (sizes.count() - 1)) : 0;
+ for(int i=0; i<sizes.count(); ++i) {
+ if (i != index)
+ sizes[i] -= adjust;
+ }
+ sizes[index]= width;
+ splitter->setSizes(sizes);
+ } else {
+ QSize s = size();
+ s.setWidth(width);
+ resize(s);
+ }
+ }
+}
+
+// This function does work even though the order in which
+// the placeHolder get the signal is undefined.
+// It does ensure that after all PlaceHolders got the signal
+// m_current points to the current PlaceHolder, or zero if there
+// is no PlaceHolder in this mode
+// And that the parent of the RightPaneWidget gets the correct parent
+void RightPanePlaceHolder::currentModeChanged(Core::IMode *mode)
+{
+ if (m_current == this) {
+ m_current = 0;
+ RightPaneWidget::instance()->setParent(0);
+ RightPaneWidget::instance()->hide();
+ }
+ if (m_mode == mode) {
+ m_current = this;
+
+ int width = RightPaneWidget::instance()->storedWidth();
+
+ layout()->addWidget(RightPaneWidget::instance());
+ RightPaneWidget::instance()->show();
+
+ applyStoredSize(width);
+ setVisible(RightPaneWidget::instance()->isShown());
+ }
+}
+
+/////
+// RightPaneWidget
+/////
+
+
+RightPaneWidget *RightPaneWidget::m_instance = 0;
+
+RightPaneWidget::RightPaneWidget()
+ :m_shown(true), m_width(0)
+{
+ m_instance = this;
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ setLayout(layout);
+
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+
+ BaseRightPaneWidget *rpw = pm->getObject<BaseRightPaneWidget>();
+ if (rpw) {
+ layout->addWidget(rpw->widget());
+ }
+ connect(pm, SIGNAL(objectAdded(QObject *)),
+ this, SLOT(objectAdded(QObject *)));
+ connect(pm, SIGNAL(aboutToRemoveObject(QObject *)),
+ this, SLOT(aboutToRemoveObject(QObject *)));
+}
+
+RightPaneWidget::~RightPaneWidget()
+{
+ m_instance = 0;
+}
+
+void RightPaneWidget::objectAdded(QObject *obj)
+{
+ BaseRightPaneWidget *rpw = qobject_cast<BaseRightPaneWidget *>(obj);
+ if (rpw) {
+ layout()->addWidget(rpw->widget());
+ setFocusProxy(rpw->widget());
+ }
+}
+
+void RightPaneWidget::aboutToRemoveObject(QObject *obj)
+{
+ BaseRightPaneWidget *rpw = qobject_cast<BaseRightPaneWidget *>(obj);
+ if (rpw) {
+ delete rpw->widget();
+ }
+}
+
+RightPaneWidget *RightPaneWidget::instance()
+{
+ return m_instance;
+}
+
+int RightPaneWidget::storedWidth()
+{
+ return m_width;
+}
+
+void RightPaneWidget::resizeEvent(QResizeEvent *re)
+{
+ if (m_width && re->size().width())
+ m_width = re->size().width();
+ QWidget::resizeEvent(re);
+}
+
+void RightPaneWidget::saveSettings(QSettings *settings)
+{
+ settings->setValue("RightPane/Visible", isShown());
+ settings->setValue("RightPane/Width", m_width);
+}
+
+void RightPaneWidget::readSettings(QSettings *settings)
+{
+ if (settings->contains("RightPane/Visible")) {
+ setShown(settings->value("RightPane/Visible").toBool());
+ } else {
+ setShown(false); //TODO set to false
+ }
+
+ if (settings->contains("RightPane/Width")) {
+ m_width = settings->value("RightPane/Width").toInt();
+ if (!m_width)
+ m_width = 500;
+ } else {
+ m_width = 500; //pixel
+ }
+ // Apply
+ if (RightPanePlaceHolder::m_current) {
+ RightPanePlaceHolder::m_current->applyStoredSize(m_width);
+ }
+}
+
+void RightPaneWidget::setShown(bool b)
+{
+ if (RightPanePlaceHolder::m_current)
+ RightPanePlaceHolder::m_current->setVisible(b);
+ m_shown = b;
+}
+
+bool RightPaneWidget::isShown()
+{
+ return m_shown;
+}
+
+/////
+// BaseRightPaneWidget
+/////
+
+BaseRightPaneWidget::BaseRightPaneWidget(QWidget *widget)
+{
+ m_widget = widget;
+}
+
+BaseRightPaneWidget::~BaseRightPaneWidget()
+{
+
+}
+
+QWidget *BaseRightPaneWidget::widget() const
+{
+ return m_widget;
+}
diff --git a/src/plugins/coreplugin/rightpane.h b/src/plugins/coreplugin/rightpane.h
new file mode 100644
index 0000000000..7b44b6fe01
--- /dev/null
+++ b/src/plugins/coreplugin/rightpane.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RIGHTPANE_H
+#define RIGHTPANE_H
+
+#include "core_global.h"
+#include <QtGui/QWidget>
+#include <QtCore/QSettings>
+
+namespace Core {
+class IMode;
+
+class RightPaneWidget;
+
+// TODO: The right pane works only for the help plugin atm.
+// It can't cope with more than one plugin publishing objects they want in the right pane
+// For that the API would need to be different. (Might be that instead of adding objects
+// to the pool, there should be a method RightPaneWidget::setWidget(QWidget *w)
+// Anyway if a second plugin wants to show something there, redesign this API
+class CORE_EXPORT RightPanePlaceHolder : public QWidget
+{
+ friend class Core::RightPaneWidget;
+ Q_OBJECT
+public:
+ RightPanePlaceHolder(Core::IMode *mode, QWidget *parent = 0);
+ ~RightPanePlaceHolder();
+ static RightPanePlaceHolder *current();
+private slots:
+ void currentModeChanged(Core::IMode *);
+private:
+ void applyStoredSize(int width);
+ Core::IMode *m_mode;
+ static RightPanePlaceHolder* m_current;
+};
+
+class CORE_EXPORT BaseRightPaneWidget : public QObject
+{
+ Q_OBJECT
+public:
+ BaseRightPaneWidget(QWidget *widget);
+ ~BaseRightPaneWidget();
+ QWidget *widget() const;
+private:
+ QWidget *m_widget;
+};
+
+class CORE_EXPORT RightPaneWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ RightPaneWidget();
+ ~RightPaneWidget();
+
+ void saveSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+ bool isShown();
+ void setShown(bool b);
+
+ static RightPaneWidget* instance();
+
+ int storedWidth();
+protected:
+ void resizeEvent(QResizeEvent *);
+private slots:
+ void objectAdded(QObject *obj);
+ void aboutToRemoveObject(QObject *obj);
+
+private:
+ bool m_shown;
+ int m_width;
+ static RightPaneWidget *m_instance;
+};
+
+} // namespace Core
+
+
+#endif // RIGHTPANE_H
diff --git a/src/plugins/coreplugin/scriptmanager/metatypedeclarations.h b/src/plugins/coreplugin/scriptmanager/metatypedeclarations.h
new file mode 100644
index 0000000000..221dc7975d
--- /dev/null
+++ b/src/plugins/coreplugin/scriptmanager/metatypedeclarations.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef METATYPEDECLARATIONS_H
+#define METATYPEDECLARATIONS_H
+
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/ifile.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/editormanager/editorgroup.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
+
+#include <QtCore/QList>
+#include <QtCore/QMetaType>
+
+QT_BEGIN_NAMESPACE
+class QMainWindow;
+class QStatusBar;
+class QToolBar;
+class QSettings;
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Core::MessageManager*)
+Q_DECLARE_METATYPE(Core::FileManager*)
+Q_DECLARE_METATYPE(Core::IFile*)
+Q_DECLARE_METATYPE(QList<Core::IFile*>)
+Q_DECLARE_METATYPE(Core::IEditor*)
+Q_DECLARE_METATYPE(QList<Core::IEditor*>)
+Q_DECLARE_METATYPE(Core::EditorGroup*)
+Q_DECLARE_METATYPE(QList<Core::EditorGroup*>)
+Q_DECLARE_METATYPE(Core::EditorManager*)
+Q_DECLARE_METATYPE(Core::ICore*)
+
+Q_DECLARE_METATYPE(QMainWindow*)
+Q_DECLARE_METATYPE(QStatusBar*)
+Q_DECLARE_METATYPE(QToolBar*)
+Q_DECLARE_METATYPE(QSettings*)
+
+#endif // METATYPEDECLARATIONS_H
diff --git a/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp
new file mode 100644
index 0000000000..acb84ff2ce
--- /dev/null
+++ b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp
@@ -0,0 +1,381 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qworkbench_wrapper.h"
+#include <wrap_helpers.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+
+#include <QtGui/QMainWindow>
+#include <QtGui/QStatusBar>
+#include <QtGui/QToolBar>
+#include <QtScript/QScriptEngine>
+
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/editormanager/editorgroup.h>
+
+namespace {
+ enum { debugQWorkbenchWrappers = 0 };
+}
+
+namespace Core {
+namespace Internal {
+
+// -- CorePrototype
+CorePrototype::CorePrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+Core::MessageManager *CorePrototype::messageManager() const
+{
+ return callee()->messageManager();
+}
+
+Core::FileManager *CorePrototype::fileManager() const
+{
+ return callee()->fileManager();
+}
+
+Core::EditorManager *CorePrototype::editorManager() const
+{
+ return callee()->editorManager();
+}
+
+QMainWindow *CorePrototype::mainWindow() const
+{
+ return callee()->mainWindow();
+}
+
+QStatusBar *CorePrototype::statusBar() const
+{
+ return callee()->statusBar();
+}
+
+QSettings *CorePrototype::settings() const
+{
+ return callee()->settings();
+}
+
+void CorePrototype::addAdditionalContext(int context)
+{
+ callee()->addAdditionalContext(context);
+}
+
+void CorePrototype::removeAdditionalContext(int context)
+{
+ callee()->removeAdditionalContext(context);
+}
+
+QString CorePrototype::toString() const
+{
+ return QLatin1String("Core");
+}
+
+CorePrototype::ICore *CorePrototype::callee() const
+{
+ ICore *rc = qscriptvalue_cast<ICore *>(thisObject());
+ Q_ASSERT(rc);
+ return rc;
+}
+
+// -- MessageManager
+
+MessageManagerPrototype::MessageManagerPrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+void MessageManagerPrototype::displayStatusBarMessage(const QString &text, int ms)
+{
+ MessageManager *mm = qscriptvalue_cast<MessageManager *>(thisObject());
+ Q_ASSERT(mm);
+ mm->displayStatusBarMessage(text, ms);
+}
+
+void MessageManagerPrototype::printToOutputPane(const QString &text, bool bringToForeground)
+{
+ MessageManager *mm = qscriptvalue_cast<MessageManager *>(thisObject());
+ Q_ASSERT(mm);
+ mm->printToOutputPane(text, bringToForeground);
+}
+
+QString MessageManagerPrototype::toString() const
+{
+ return QLatin1String("MessageManager");
+}
+
+// -- FileManagerPrototype
+
+FileManagerPrototype::FileManagerPrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+FileManager *FileManagerPrototype::callee() const
+{
+ FileManager *rc = qscriptvalue_cast<FileManager *>(thisObject());
+ Q_ASSERT(rc);
+ return rc;
+}
+
+bool FileManagerPrototype::addFiles(const QList<Core::IFile *> &files) { return callee()->addFiles(files); }
+bool FileManagerPrototype::addFile(Core::IFile *file) { return callee()->addFile(file); }
+bool FileManagerPrototype::removeFile(Core::IFile *file) { return callee()->removeFile(file); }
+
+QList<Core::IFile*>
+ FileManagerPrototype::saveModifiedFilesSilently(const QList<Core::IFile*> &files) { return callee()->saveModifiedFilesSilently(files); }
+
+QString FileManagerPrototype::getSaveAsFileName(Core::IFile *file) { return callee()->getSaveAsFileName(file); }
+
+bool FileManagerPrototype::isFileManaged(const QString &fileName) const { return callee()->isFileManaged(fileName); }
+QList<Core::IFile *>
+ FileManagerPrototype::managedFiles(const QString &fileName) const { return callee()->managedFiles(fileName); }
+
+void FileManagerPrototype::blockFileChange(Core::IFile *file) { callee()->blockFileChange(file); }
+void FileManagerPrototype::unblockFileChange(Core::IFile *file) { return callee()->unblockFileChange(file); }
+
+void FileManagerPrototype::addToRecentFiles(const QString &fileName) { return callee()->addToRecentFiles(fileName); }
+QStringList FileManagerPrototype::recentFiles() const { return callee()->recentFiles(); }
+
+QString FileManagerPrototype::toString() const
+{
+ return QLatin1String("FileManager");
+}
+
+// ------- FilePrototype
+
+FilePrototype::FilePrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+IFile *FilePrototype::callee() const
+{
+ IFile *rc = qscriptvalue_cast<IFile *>(thisObject());
+ Q_ASSERT(rc);
+ return rc;
+}
+
+QString FilePrototype::fileName () const { return callee()->fileName(); }
+QString FilePrototype::defaultPath () const { return callee()->defaultPath(); }
+QString FilePrototype::suggestedFileName () const { return callee()->suggestedFileName(); }
+
+bool FilePrototype::isModified () const { return callee()->isModified(); }
+bool FilePrototype::isReadOnly () const { return callee()->isReadOnly(); }
+bool FilePrototype::isSaveAsAllowed () const { return callee()->isSaveAsAllowed(); }
+
+QString FilePrototype::toString() const
+{
+ QString rc = QLatin1String("File(");
+ rc += fileName();
+ rc += QLatin1Char(')');
+ return rc;
+}
+
+// ------------- EditorManagerPrototype
+
+EditorManagerPrototype::EditorManagerPrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+Core::IEditor *EditorManagerPrototype::currentEditor() const
+{
+ return callee()->currentEditor();
+}
+
+void EditorManagerPrototype::setCurrentEditor(Core::IEditor *editor)
+{
+ callee()->setCurrentEditor(editor);
+}
+
+QList<Core::IEditor*> EditorManagerPrototype::openedEditors() const
+{
+ return callee()->openedEditors();
+}
+
+QList<Core::IEditor*> EditorManagerPrototype::editorHistory() const
+{
+ return callee()->editorHistory();
+}
+
+QList<Core::EditorGroup *> EditorManagerPrototype::editorGroups() const
+{
+ return callee()->editorGroups();
+}
+
+QList<Core::IEditor*> EditorManagerPrototype::editorsForFiles(QList<Core::IFile*> files) const
+{
+ return callee()->editorsForFiles(files);
+}
+
+bool EditorManagerPrototype::closeEditors(const QList<Core::IEditor*> editorsToClose, bool askAboutModifiedEditors)
+{
+ return callee()->closeEditors(editorsToClose, askAboutModifiedEditors);
+}
+
+Core::IEditor *EditorManagerPrototype::openEditor(const QString &fileName, const QString &editorKind)
+{
+ return callee()->openEditor(fileName, editorKind);
+}
+
+Core::IEditor *EditorManagerPrototype::newFile(const QString &editorKind, QString titlePattern, const QString &contents)
+{
+ return callee()->newFile(editorKind, &titlePattern, contents);
+}
+
+int EditorManagerPrototype::makeEditorWritable(Core::IEditor *editor)
+{
+ return callee()->makeEditorWritable(editor);
+}
+
+QString EditorManagerPrototype::toString() const
+{
+ return QLatin1String("EditorManager");
+}
+
+EditorManagerPrototype::EditorManager *EditorManagerPrototype::callee() const
+{
+ EditorManager *rc = qscriptvalue_cast<EditorManager *>(thisObject());
+ Q_ASSERT(rc);
+ return rc;
+
+}
+
+// ------------- EditorPrototype
+
+EditorPrototype::EditorPrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QString EditorPrototype::displayName() const { return callee()->displayName(); }
+void EditorPrototype::setDisplayName(const QString &title) { callee()->setDisplayName(title); }
+
+QString EditorPrototype::kind() const { return QLatin1String(callee()->kind()); }
+bool EditorPrototype::duplicateSupported() const { return callee()->duplicateSupported(); }
+
+bool EditorPrototype::createNew(const QString &contents) { return callee()->createNew(contents); }
+bool EditorPrototype::open(const QString &fileName) { return callee()->open(fileName); }
+
+Core::IEditor *EditorPrototype::duplicate(QWidget *parent)
+{
+ return callee()->duplicate(parent);
+}
+
+Core::IFile *EditorPrototype::file() const { return callee()->file(); }
+QToolBar* EditorPrototype::toolBar() const { return callee()->toolBar();}
+
+Core::IEditor *EditorPrototype::callee() const
+{
+ IEditor *rc = qscriptvalue_cast<IEditor *>(thisObject());
+ Q_ASSERT(rc);
+ return rc;
+}
+
+QString EditorPrototype::toString() const
+{
+ QString rc = QLatin1String("Editor(");
+ rc += displayName();
+ rc += QLatin1Char(')');
+ return rc;
+}
+
+// ----------- EditorGroupPrototype
+
+EditorGroupPrototype::EditorGroupPrototype(QObject *parent) :
+ QObject(parent)
+{
+}
+
+int EditorGroupPrototype::editorCount() const
+{
+ return callee()->editorCount();
+}
+
+Core::IEditor *EditorGroupPrototype::currentEditor() const
+{
+ return callee()->currentEditor();
+}
+
+void EditorGroupPrototype::setCurrentEditor(Core::IEditor *editor)
+{
+ callee()->setCurrentEditor(editor);
+}
+
+QList<Core::IEditor*> EditorGroupPrototype::editors() const
+{
+ return callee()->editors();
+}
+
+void EditorGroupPrototype::addEditor(Core::IEditor *editor)
+{
+ callee()->addEditor(editor);
+}
+
+void EditorGroupPrototype::insertEditor(int i, Core::IEditor *editor)
+{
+ callee()->insertEditor(i, editor);
+}
+
+void EditorGroupPrototype::removeEditor(Core::IEditor *editor)
+{
+ callee()->removeEditor(editor);
+}
+
+
+void EditorGroupPrototype::moveEditorsFromGroup(Core::EditorGroup *group)
+{
+ callee()->moveEditorsFromGroup(group);
+}
+
+void EditorGroupPrototype::moveEditorFromGroup(Core::EditorGroup *group, Core::IEditor *editor)
+{
+ callee()->moveEditorFromGroup(group, editor);
+}
+
+QString EditorGroupPrototype::toString() const
+{
+ return QLatin1String("EditorGroup");
+}
+
+Core::EditorGroup *EditorGroupPrototype::callee() const
+{
+ EditorGroup *rc = qscriptvalue_cast<EditorGroup *>(thisObject());
+ Q_ASSERT(rc);
+ return rc;
+}
+
+}
+}
diff --git a/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h
new file mode 100644
index 0000000000..0561ac4221
--- /dev/null
+++ b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h
@@ -0,0 +1,262 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QWORKBENCH_WRAPPER_H
+#define QWORKBENCH_WRAPPER_H
+
+#include "metatypedeclarations.h" // required for property declarations
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtScript/QScriptable>
+#include <QtScript/QScriptValue>
+
+namespace Core {
+namespace Internal {
+
+// Script prototype for the core interface.
+
+class CorePrototype : public QObject, public QScriptable {
+ Q_OBJECT
+
+ Q_PROPERTY(Core::MessageManager* messageManager READ messageManager DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(Core::FileManager* fileManager READ fileManager DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(Core::EditorManager* editorManager READ editorManager DESIGNABLE false SCRIPTABLE true STORED false)
+
+ Q_PROPERTY(QMainWindow* mainWindow READ mainWindow DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QStatusBar* statusBar READ statusBar DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QSettings* settings READ settings DESIGNABLE false SCRIPTABLE true STORED false)
+
+public:
+ typedef Core::ICore ICore;
+
+ CorePrototype(QObject *parent);
+
+ Core::MessageManager *messageManager() const;
+ Core::FileManager *fileManager() const;
+ Core::EditorManager *editorManager() const;
+
+ QMainWindow *mainWindow() const;
+ QStatusBar *statusBar() const;
+ QSettings *settings() const;
+
+public slots:
+ void addAdditionalContext(int context);
+ void removeAdditionalContext(int context);
+ QString toString() const;
+
+private:
+ ICore *callee() const;
+};
+
+// Script prototype for the message manager.
+
+class MessageManagerPrototype : public QObject, public QScriptable
+{
+ Q_OBJECT
+
+public:
+ typedef Core::MessageManager MessageManager;
+
+ MessageManagerPrototype(QObject *parent = 0);
+
+public slots:
+ void displayStatusBarMessage(const QString &text, int ms = 0);
+ void printToOutputPane(const QString &text, bool bringToForeground = true);
+ QString toString() const;
+};
+
+// Script prototype for the file manager interface.
+
+class FileManagerPrototype : public QObject, public QScriptable {
+ Q_OBJECT
+
+ Q_PROPERTY(QStringList recentFiles READ recentFiles DESIGNABLE false SCRIPTABLE true STORED false)
+
+public:
+ typedef Core::FileManager FileManager;
+
+ FileManagerPrototype(QObject *parent = 0);
+ QStringList recentFiles() const;
+
+public slots:
+ bool addFiles(const QList<Core::IFile *> &files);
+ bool addFile(Core::IFile *file);
+ bool removeFile(Core::IFile *file);
+
+ QList<Core::IFile*> saveModifiedFilesSilently(const QList<Core::IFile*> &files);
+ QString getSaveAsFileName(Core::IFile *file);
+
+ bool isFileManaged(const QString &fileName) const;
+ QList<Core::IFile *> managedFiles(const QString &fileName) const;
+
+ void blockFileChange(Core::IFile *file);
+ void unblockFileChange(Core::IFile *file);
+
+ void addToRecentFiles(const QString &fileName);
+ QString toString() const;
+
+private:
+ FileManager *callee() const;
+};
+
+// Script prototype for the file interface.
+
+class FilePrototype : public QObject, public QScriptable
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString fileName READ fileName DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QString defaultPath READ defaultPath DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QString suggestedFileName READ suggestedFileName DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(bool isModified READ isModified DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(bool isReadOnly READ isReadOnly DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(bool isSaveAsAllowed READ isSaveAsAllowed DESIGNABLE false SCRIPTABLE true STORED false)
+public:
+ typedef Core::IFile IFile;
+
+ FilePrototype(QObject *parent = 0);
+
+ QString fileName() const;
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+
+public slots:
+ QString toString() const;
+
+private:
+ IFile *callee() const;
+};
+
+// Script prototype for the editor manager interface.
+
+class EditorManagerPrototype : public QObject, public QScriptable {
+ Q_OBJECT
+ Q_PROPERTY(Core::IEditor* currentEditor READ currentEditor WRITE setCurrentEditor DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QList<Core::IEditor*> openedEditors READ openedEditors DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QList<Core::IEditor*> editorHistory READ editorHistory DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QList<Core::EditorGroup *> editorGroups READ editorGroups DESIGNABLE false SCRIPTABLE true STORED false)
+public:
+ typedef Core::EditorManager EditorManager;
+
+ EditorManagerPrototype(QObject *parent = 0);
+
+ Core::IEditor *currentEditor() const;
+ void setCurrentEditor(Core::IEditor *editor);
+ QList<Core::IEditor*> openedEditors() const;
+ QList<Core::IEditor*> editorHistory() const;
+ QList<Core::EditorGroup *> editorGroups() const;
+
+public slots:
+ QList<Core::IEditor*> editorsForFiles(QList<Core::IFile*> files) const;
+ bool closeEditors(const QList<Core::IEditor*> editorsToClose, bool askAboutModifiedEditors);
+ Core::IEditor *openEditor(const QString &fileName, const QString &editorKind);
+ Core::IEditor *newFile(const QString &editorKind, QString titlePattern, const QString &contents);
+ int makeEditorWritable(Core::IEditor *editor);
+
+ QString toString() const;
+
+private:
+ EditorManager *callee() const;
+};
+
+// Script prototype for the editor interface.
+
+class EditorPrototype : public QObject, public QScriptable {
+ Q_OBJECT
+ Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QString kind READ kind DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(bool duplicateSupported READ duplicateSupported DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(Core::IFile* file READ file DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QToolBar* toolBar READ toolBar DESIGNABLE false SCRIPTABLE true STORED false)
+
+public:
+ EditorPrototype(QObject *parent = 0);
+
+ QString displayName() const;
+ void setDisplayName(const QString &title);
+
+ QString kind() const;
+ bool duplicateSupported() const;
+
+ Core::IFile *file() const;
+ QToolBar* toolBar() const;
+
+public slots:
+ bool createNew(const QString &contents);
+ bool open(const QString &fileName);
+ Core::IEditor *duplicate(QWidget *parent);
+
+ QString toString() const;
+
+private:
+ Core::IEditor *callee() const;
+};
+
+// Script prototype for the editor group interface with Script-managed life cycle.
+
+class EditorGroupPrototype : public QObject, public QScriptable {
+ Q_OBJECT
+ Q_PROPERTY(int editorCount READ editorCount DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(Core::IEditor* currentEditor READ currentEditor WRITE setCurrentEditor DESIGNABLE false SCRIPTABLE true STORED false)
+ Q_PROPERTY(QList<Core::IEditor*> editors READ editors DESIGNABLE false SCRIPTABLE true STORED false)
+
+public:
+ EditorGroupPrototype(QObject *parent = 0);
+
+ int editorCount() const;
+ Core::IEditor *currentEditor() const;
+ void setCurrentEditor(Core::IEditor *editor);
+ QList<Core::IEditor*> editors() const;
+
+public slots:
+ void addEditor(Core::IEditor *editor);
+ void insertEditor(int i, Core::IEditor *editor);
+ void removeEditor(Core::IEditor *editor);
+
+ void moveEditorsFromGroup(Core::EditorGroup *group);
+ void moveEditorFromGroup(Core::EditorGroup *group, Core::IEditor *editor);
+
+ QString toString() const;
+
+private:
+ Core::EditorGroup *callee() const;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //QWORKBENCH_WRAPPER_H
diff --git a/src/plugins/coreplugin/scriptmanager/scriptmanager.cpp b/src/plugins/coreplugin/scriptmanager/scriptmanager.cpp
new file mode 100644
index 0000000000..b4bcae7ada
--- /dev/null
+++ b/src/plugins/coreplugin/scriptmanager/scriptmanager.cpp
@@ -0,0 +1,313 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "scriptmanager.h"
+#include "qworkbench_wrapper.h"
+#include "metatypedeclarations.h"
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <interface_wrap_helpers.h>
+#include <wrap_helpers.h>
+#include <limits.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtGui/QMessageBox>
+#include <QtGui/QInputDialog>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMainWindow>
+#include <QtGui/QToolBar>
+#include <QtGui/QStatusBar>
+
+namespace {
+ enum { debugQWorkbenchWrappers = 0 };
+}
+
+// Script function template to pop up a message box
+// with a certain icon and buttons.
+template <int MsgBoxIcon, int MsgBoxButtons>
+ static QScriptValue messageBox(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() < 3)
+ return QScriptValue(engine, -1);
+
+ QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0));
+ const QString title = context->argument(1).toString();
+ const QString msg = context->argument(2).toString();
+
+ QMessageBox msgBox(static_cast<QMessageBox::Icon>(MsgBoxIcon), title, msg,
+ static_cast<QMessageBox::StandardButtons>(MsgBoxButtons), parent);
+
+ return QScriptValue(engine, msgBox.exec());
+}
+
+static QScriptValue inputDialogGetText(QScriptContext *context, QScriptEngine *engine)
+{
+ const int argumentCount = context->argumentCount();
+ if (argumentCount < 3)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0));
+ const QString title = context->argument(1).toString();
+ const QString label = context->argument(2).toString();
+ const QString defaultValue = argumentCount > 3 ? context->argument(3).toString() : QString();
+
+ bool ok;
+ const QString rc = QInputDialog::getText(parent, title, label, QLineEdit::Normal, defaultValue, &ok);
+ if (!ok)
+ return QScriptValue(engine, QScriptValue::NullValue);
+ return QScriptValue(engine, rc);
+}
+
+static QScriptValue inputDialogGetInteger(QScriptContext *context, QScriptEngine *engine)
+{
+ const int argumentCount = context->argumentCount();
+ if (argumentCount < 3)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0));
+ const QString title = context->argument(1).toString();
+ const QString label = context->argument(2).toString();
+ const int defaultValue = argumentCount > 3 ? context->argument(3).toInt32() : 0;
+ const int minValue = argumentCount > 4 ? context->argument(4).toInt32() : INT_MIN;
+ const int maxValue = argumentCount > 5 ? context->argument(5).toInt32() : INT_MAX;
+
+ bool ok;
+ const int rc = QInputDialog::getInteger(parent, title, label, defaultValue, minValue, maxValue, 1, &ok);
+ if (!ok)
+ return QScriptValue(engine, QScriptValue::NullValue);
+ return QScriptValue(engine, rc);
+}
+
+static QScriptValue inputDialogGetDouble(QScriptContext *context, QScriptEngine *engine)
+{
+ const int argumentCount = context->argumentCount();
+ if (argumentCount < 3)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0));
+ const QString title = context->argument(1).toString();
+ const QString label = context->argument(2).toString();
+ const double defaultValue = argumentCount > 3 ? context->argument(3).toNumber() : 0;
+ // Use QInputDialog defaults
+ const double minValue = argumentCount > 4 ? context->argument(4).toNumber() : INT_MIN;
+ const double maxValue = argumentCount > 5 ? context->argument(5).toNumber() : INT_MAX;
+
+ bool ok;
+ const double rc = QInputDialog::getDouble(parent, title, label, defaultValue, minValue, maxValue, 1, &ok);
+ if (!ok)
+ return QScriptValue(engine, QScriptValue::NullValue);
+ return QScriptValue(engine, rc);
+}
+
+static QScriptValue inputDialogGetItem(QScriptContext *context, QScriptEngine *engine)
+{
+ const int argumentCount = context->argumentCount();
+ if (argumentCount < 4)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0));
+ const QString title = context->argument(1).toString();
+ const QString label = context->argument(2).toString();
+ const QStringList items = qscriptvalue_cast<QStringList>(context->argument(3));
+ const int defaultItem = argumentCount > 4 ? context->argument(4).toInt32() : 0;
+ const bool editable = argumentCount > 5 ? context->argument(5).toInt32() : 0;
+
+ bool ok;
+ const QString rc = QInputDialog::getItem (parent, title, label, items, defaultItem, editable, &ok);
+ if (!ok)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ return QScriptValue(engine, rc);
+}
+
+// Script function template to pop up a file box
+// with a certain icon and buttons.
+template <int TAcceptMode, int TFileMode>
+ static QScriptValue fileBox(QScriptContext *context, QScriptEngine *engine)
+{
+ const int argumentCount = context->argumentCount();
+ if (argumentCount < 2)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QWidget *parent = qscriptvalue_cast<QWidget *>(context->argument(0));
+ const QString title = context->argument(1).toString();
+ const QString directory = argumentCount > 2 ? context->argument(2).toString() : QString();
+ const QString filter = argumentCount > 3 ? context->argument(3).toString() : QString();
+ QFileDialog fileDialog(parent, title, directory, filter);
+ fileDialog.setAcceptMode(static_cast<QFileDialog::AcceptMode>(TAcceptMode));
+ fileDialog.setFileMode (static_cast<QFileDialog::FileMode>(TFileMode));
+ if (fileDialog.exec() == QDialog::Rejected)
+ return QScriptValue(engine, QScriptValue::NullValue);
+ const QStringList rc = fileDialog.selectedFiles();
+ Q_ASSERT(!rc.empty());
+ return TFileMode == QFileDialog::ExistingFiles ?
+ engine->toScriptValue(rc) : engine->toScriptValue(rc.front());
+}
+
+// ------ ScriptManager
+
+namespace Core {
+namespace Internal {
+
+ScriptManager::ScriptManager(QObject *parent, ICore *core) :
+ ScriptManagerInterface(parent),
+ m_core(core),
+ m_initialized(false)
+{
+}
+
+QScriptEngine &ScriptManager::scriptEngine()
+{
+ ensureEngineInitialized();
+ return m_engine;
+}
+
+// Split a backtrace of the form:
+// "<anonymous>(BuildManagerCommand(ls))@:0
+// demoProjectExplorer()@:237
+// <anonymous>()@:276
+// <global>()@:0"
+static void parseBackTrace(const QStringList &backTrace, ScriptManager::Stack &stack)
+{
+ const QChar at = QLatin1Char('@');
+ const QChar colon = QLatin1Char(':');
+ stack.clear();
+ foreach (const QString &line, backTrace) {
+ const int atPos = line.lastIndexOf(at);
+ if (atPos == -1)
+ continue;
+ const int colonPos = line.indexOf(colon, atPos + 1);
+ if (colonPos == -1)
+ continue;
+
+ ScriptManager::StackFrame frame;
+ frame.function = line.left(atPos);
+ frame.fileName = line.mid(atPos + 1, colonPos - atPos - 1);
+ frame.lineNumber = line.right(line.size() - colonPos - 1).toInt();
+ stack.push_back(frame);
+ }
+}
+
+bool ScriptManager::runScript(const QString &script, QString *errorMessage)
+{
+ Stack stack;
+ return runScript(script, errorMessage, &stack);
+}
+
+bool ScriptManager::runScript(const QString &script, QString *errorMessage, Stack *stack)
+{
+ ensureEngineInitialized();
+ stack->clear();
+
+ m_engine.pushContext();
+ m_engine.evaluate(script);
+
+ const bool failed = m_engine.hasUncaughtException ();
+ if (failed) {
+ const int errorLineNumber = m_engine.uncaughtExceptionLineNumber();
+ const QStringList backTrace = m_engine.uncaughtExceptionBacktrace();
+ parseBackTrace(backTrace, *stack);
+ const QString backtrace = backTrace.join(QString(QLatin1Char('\n')));
+ *errorMessage = QObject::tr("Exception at line %1: %2\n%3").arg(errorLineNumber).arg(engineError(m_engine)).arg(backtrace);
+ }
+ m_engine.popContext();
+ return !failed;
+}
+
+void ScriptManager::ensureEngineInitialized()
+{
+ if (m_initialized)
+ return;
+ Q_ASSERT(m_core);
+ // register QObjects that occur as properties
+ SharedTools::registerQObject<QMainWindow>(m_engine);
+ SharedTools::registerQObject<QStatusBar>(m_engine);
+ SharedTools::registerQObject<QToolBar>(m_engine);
+ SharedTools::registerQObject<QSettings>(m_engine);
+ // WB interfaces
+// SharedTools::registerQObjectInterface<Core::MessageManager, MessageManagerPrototype>(m_engine);
+
+// SharedTools::registerQObjectInterface<Core::IFile, FilePrototype>(m_engine);
+// qScriptRegisterSequenceMetaType<QList<Core::IFile *> >(&m_engine);
+// SharedTools::registerQObjectInterface<Core::FileManager, FileManagerPrototype>(m_engine);
+
+// SharedTools::registerQObjectInterface<Core::IEditor, EditorPrototype>(m_engine);
+ qScriptRegisterSequenceMetaType<QList<Core::IEditor *> >(&m_engine);
+
+// SharedTools::registerQObjectInterface<Core::EditorGroup, EditorGroupPrototype>(m_engine);
+ qScriptRegisterSequenceMetaType<QList<Core::EditorGroup *> >(&m_engine);
+
+ SharedTools::registerQObjectInterface<Core::EditorManager, EditorManagerPrototype>(m_engine);
+
+// SharedTools::registerQObjectInterface<Core::ICore, CorePrototype>(m_engine);
+
+ // Make "core" available
+ m_engine.globalObject().setProperty(QLatin1String("core"), qScriptValueFromValue(&m_engine, m_core));
+
+ // CLASSIC: registerInterfaceWithDefaultPrototype<Core::MessageManager, MessageManagerPrototype>(m_engine);
+
+ // Message box conveniences
+ m_engine.globalObject().setProperty(QLatin1String("critical"),
+ m_engine.newFunction(messageBox<QMessageBox::Critical, QMessageBox::Ok>, 3));
+ m_engine.globalObject().setProperty(QLatin1String("warning"),
+ m_engine.newFunction(messageBox<QMessageBox::Warning, QMessageBox::Ok>, 3));
+ m_engine.globalObject().setProperty(QLatin1String("information"),
+ m_engine.newFunction(messageBox<QMessageBox::Information, QMessageBox::Ok>, 3));
+ // StandardButtons has overloaded operator '|' - grrr.
+ enum { MsgBoxYesNo = 0x00014000 };
+ m_engine.globalObject().setProperty(QLatin1String("yesNoQuestion"),
+ m_engine.newFunction(messageBox<QMessageBox::Question, MsgBoxYesNo>, 3));
+
+ m_engine.globalObject().setProperty(QLatin1String("getText"), m_engine.newFunction(inputDialogGetText, 3));
+ m_engine.globalObject().setProperty(QLatin1String("getInteger"), m_engine.newFunction(inputDialogGetInteger, 3));
+ m_engine.globalObject().setProperty(QLatin1String("getDouble"), m_engine.newFunction(inputDialogGetDouble, 3));
+ m_engine.globalObject().setProperty(QLatin1String("getItem"), m_engine.newFunction(inputDialogGetItem, 3));
+
+ // file box
+ m_engine.globalObject().setProperty(QLatin1String("getOpenFileNames"), m_engine.newFunction(fileBox<QFileDialog::AcceptOpen, QFileDialog::ExistingFiles> , 2));
+ m_engine.globalObject().setProperty(QLatin1String("getOpenFileName"), m_engine.newFunction(fileBox<QFileDialog::AcceptOpen, QFileDialog::ExistingFile> , 2));
+ m_engine.globalObject().setProperty(QLatin1String("getSaveFileName"), m_engine.newFunction(fileBox<QFileDialog::AcceptSave, QFileDialog::AnyFile> , 2));
+ m_engine.globalObject().setProperty(QLatin1String("getExistingDirectory"), m_engine.newFunction(fileBox<QFileDialog::AcceptSave, QFileDialog::DirectoryOnly> , 2));
+ m_initialized = true;
+}
+
+QString ScriptManager::engineError(QScriptEngine &scriptEngine)
+{
+ QScriptValue error = scriptEngine.evaluate(QLatin1String("Error"));
+ if (error.isValid())
+ return error.toString();
+ return QObject::tr("Unknown error");
+}
+
+}
+}
diff --git a/src/plugins/coreplugin/scriptmanager/scriptmanager.h b/src/plugins/coreplugin/scriptmanager/scriptmanager.h
new file mode 100644
index 0000000000..5135970710
--- /dev/null
+++ b/src/plugins/coreplugin/scriptmanager/scriptmanager.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SCRIPTMANAGER_H
+#define SCRIPTMANAGER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtScript/QScriptEngine>
+
+#include <coreplugin/scriptmanager/scriptmanagerinterface.h>
+#include <coreplugin/icore.h>
+
+namespace Core {
+namespace Internal {
+
+class ScriptManager : public Core::ScriptManagerInterface
+{
+ Q_OBJECT
+
+public:
+ ScriptManager(QObject *parent, ICore *core);
+
+ virtual QScriptEngine &scriptEngine();
+
+ virtual bool runScript(const QString &script, QString *errorMessage, Stack *stack);
+ virtual bool runScript(const QString &script, QString *errorMessage);
+
+ static QString engineError(QScriptEngine &scriptEngine);
+
+private:
+ void ensureEngineInitialized();
+
+ QScriptEngine m_engine;
+ ICore *m_core;
+ bool m_initialized;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //SCRIPTMANAGER_H
diff --git a/src/plugins/coreplugin/scriptmanager/scriptmanagerinterface.h b/src/plugins/coreplugin/scriptmanager/scriptmanagerinterface.h
new file mode 100644
index 0000000000..5d3a907e75
--- /dev/null
+++ b/src/plugins/coreplugin/scriptmanager/scriptmanagerinterface.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SCRIPTMANAGERINTERFACE_H
+#define SCRIPTMANAGERINTERFACE_H
+
+#include <coreplugin/core_global.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtScript/QScriptEngine>
+
+namespace Core {
+
+/* Script Manager.
+ * Provides a script engine that is initialized with
+ * QWorkBenchs interfaces and allows for running scripts.
+ * @{todo} Should it actually manage script files, too? */
+
+class CORE_EXPORT ScriptManagerInterface : public QObject
+{
+ Q_OBJECT
+public:
+ // A stack frame as returned by a failed invocation (exception)
+ // fileName may be empty. lineNumber can be 0 for the top frame (goof-up?).
+ struct StackFrame {
+ QString function;
+ QString fileName;
+ int lineNumber;
+ };
+ typedef QList<StackFrame> Stack;
+
+ ScriptManagerInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ScriptManagerInterface() { }
+
+ // Access the engine (for plugins to wrap additional interfaces).
+ virtual QScriptEngine &scriptEngine() = 0;
+
+ // Run a script
+ virtual bool runScript(const QString &script, QString *errorMessage, Stack *errorStack) = 0;
+ virtual bool runScript(const QString &script, QString *errorMessage) = 0;
+};
+
+} // namespace Core
+
+#endif // SCRIPTMANAGERINTERFACE_H
diff --git a/src/plugins/coreplugin/sidebar.cpp b/src/plugins/coreplugin/sidebar.cpp
new file mode 100644
index 0000000000..6ea56b917a
--- /dev/null
+++ b/src/plugins/coreplugin/sidebar.cpp
@@ -0,0 +1,371 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "sidebar.h"
+#include "imode.h"
+#include "modemanager.h"
+#include "actionmanager/actionmanagerinterface.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QEvent>
+#include <QtCore/QSettings>
+#include <QtGui/QLayout>
+#include <QtGui/QToolBar>
+#include <QtGui/QAction>
+#include <QtGui/QToolButton>
+
+using namespace Core;
+using namespace Core::Internal;
+
+SideBarItem::~SideBarItem()
+{
+ delete m_widget;
+}
+
+SideBar::SideBar(QList<SideBarItem*> itemList,
+ QList<SideBarItem*> defaultVisible)
+{
+ setOrientation(Qt::Vertical);
+ foreach (SideBarItem *item, itemList) {
+ const QString title = item->widget()->windowTitle();
+ m_itemMap.insert(title, item);
+ if (defaultVisible.contains(item))
+ m_defaultVisible.append(title);
+ }
+
+ m_availableItems = m_itemMap.keys();
+}
+
+SideBar::~SideBar()
+{
+ qDeleteAll(m_itemMap.values());
+}
+
+QStringList SideBar::availableItems() const
+{
+ return m_availableItems;
+}
+
+void SideBar::makeItemAvailable(SideBarItem *item)
+{
+ QMap<QString, SideBarItem*>::const_iterator it = m_itemMap.constBegin();
+ while (it != m_itemMap.constEnd()) {
+ if (it.value() == item) {
+ m_availableItems.append(it.key());
+ qSort(m_availableItems);
+ break;
+ }
+ ++it;
+ }
+}
+
+SideBarItem *SideBar::item(const QString &title)
+{
+ if (m_itemMap.contains(title)) {
+ m_availableItems.removeAll(title);
+ return m_itemMap.value(title);
+ }
+ return 0;
+}
+
+SideBarWidget *SideBar::insertSideBarWidget(int position, const QString &title)
+{
+ SideBarWidget *item = new SideBarWidget(this, title);
+ connect(item, SIGNAL(split()), this, SLOT(split()));
+ connect(item, SIGNAL(close()), this, SLOT(close()));
+ connect(item, SIGNAL(currentWidgetChanged()), this, SLOT(updateWidgets()));
+ insertWidget(position, item);
+ m_widgets.insert(position, item);
+ updateWidgets();
+ return item;
+}
+
+void SideBar::split()
+{
+ SideBarWidget *original = qobject_cast<SideBarWidget*>(sender());
+ int pos = indexOf(original) + 1;
+ insertSideBarWidget(pos);
+ updateWidgets();
+}
+
+void SideBar::close()
+{
+ if (m_widgets.count() != 1) {
+ SideBarWidget *widget = qobject_cast<SideBarWidget*>(sender());
+ if (!widget)
+ return;
+ widget->removeCurrentItem();
+ m_widgets.removeOne(widget);
+ widget->hide();
+ widget->deleteLater();
+ updateWidgets();
+ }
+}
+
+void SideBar::updateWidgets()
+{
+ foreach (SideBarWidget *i, m_widgets)
+ i->updateAvailableItems();
+}
+
+void SideBar::saveSettings(QSettings *settings)
+{
+ QStringList views;
+ for (int i = 0; i < m_widgets.count(); ++i)
+ views.append(m_widgets.at(i)->currentItemTitle());
+ settings->setValue("HelpSideBar/Views", views);
+ settings->setValue("HelpSideBar/Visible", true);//isVisible());
+ settings->setValue("HelpSideBar/VerticalPosition", saveState());
+ settings->setValue("HelpSideBar/Width", width());
+}
+
+void SideBar::readSettings(QSettings *settings)
+{
+ if (settings->contains("HelpSideBar/Views")) {
+ QStringList views = settings->value("HelpSideBar/Views").toStringList();
+ if (views.count()) {
+ foreach (const QString &title, views)
+ insertSideBarWidget(m_widgets.count(), title);
+ } else {
+ insertSideBarWidget(0);
+ }
+ } else {
+ foreach (const QString &title, m_defaultVisible)
+ insertSideBarWidget(0, title);
+ }
+
+ if (settings->contains("HelpSideBar/Visible"))
+ setVisible(settings->value("HelpSideBar/Visible").toBool());
+
+ if (settings->contains("HelpSideBar/VerticalPosition"))
+ restoreState(settings->value("HelpSideBar/VerticalPosition").toByteArray());
+
+ if (settings->contains("HelpSideBar/Width")) {
+ QSize s = size();
+ s.setWidth(settings->value("HelpSideBar/Width").toInt());
+ resize(s);
+ }
+}
+
+void SideBar::activateItem(SideBarItem *item)
+{
+ QMap<QString, SideBarItem*>::const_iterator it = m_itemMap.constBegin();
+ QString title;
+ while (it != m_itemMap.constEnd()) {
+ if (it.value() == item) {
+ title = it.key();
+ break;
+ }
+ ++it;
+ }
+
+ if (title.isEmpty())
+ return;
+
+ for (int i = 0; i < m_widgets.count(); ++i) {
+ if (m_widgets.at(i)->currentItemTitle() == title) {
+ item->widget()->setFocus();
+ return;
+ }
+ }
+
+ SideBarWidget *widget = m_widgets.first();
+ widget->setCurrentItem(title);
+ updateWidgets();
+ item->widget()->setFocus();
+}
+
+void SideBar::setShortcutMap(const QMap<QString, Core::ICommand*> &shortcutMap)
+{
+ m_shortcutMap = shortcutMap;
+}
+
+QMap<QString, Core::ICommand*> SideBar::shortcutMap() const
+{
+ return m_shortcutMap;
+}
+
+
+
+SideBarWidget::SideBarWidget(SideBar *sideBar, const QString &title)
+ : m_currentItem(0)
+ , m_sideBar(sideBar)
+{
+ m_comboBox = new ComboBox(this);
+ m_comboBox->setMinimumContentsLength(15);
+
+ m_toolbar = new QToolBar(this);
+ m_toolbar->setContentsMargins(0, 0, 0, 0);
+ m_toolbar->addWidget(m_comboBox);
+
+ m_splitButton = new QToolButton;
+ m_splitButton->setProperty("type", QLatin1String("dockbutton"));
+ m_splitButton->setIcon(QIcon(":/qworkbench/images/splitbutton_horizontal.png"));
+ m_splitButton->setToolTip(tr("Split"));
+ connect(m_splitButton, SIGNAL(clicked(bool)), this, SIGNAL(split()));
+
+ m_closeButton = new QToolButton;
+ m_closeButton->setProperty("type", QLatin1String("dockbutton"));
+ m_closeButton->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+ m_closeButton->setToolTip(tr("Close"));
+
+ connect(m_closeButton, SIGNAL(clicked(bool)), this, SIGNAL(close()));
+
+ QWidget *spacerItem = new QWidget(this);
+ spacerItem->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ m_toolbar->addWidget(spacerItem);
+ m_splitAction = m_toolbar->addWidget(m_splitButton);
+ m_toolbar->addWidget(m_closeButton);
+
+ QVBoxLayout *lay = new QVBoxLayout();
+ lay->setMargin(0);
+ lay->setSpacing(0);
+ setLayout(lay);
+ lay->addWidget(m_toolbar);
+
+ const QStringList lst = m_sideBar->availableItems();
+ QString t = title;
+ if (lst.count()) {
+ m_comboBox->addItems(lst);
+ m_comboBox->setCurrentIndex(0);
+ if (t.isEmpty())
+ t = m_comboBox->currentText();
+ }
+ setCurrentItem(t);
+
+ connect(m_comboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(setCurrentIndex(int)));
+}
+
+SideBarWidget::~SideBarWidget()
+{
+}
+
+QString SideBarWidget::currentItemTitle() const
+{
+ return m_comboBox->currentText();
+}
+
+void SideBarWidget::setCurrentItem(const QString &title)
+{
+ if (!title.isEmpty()) {
+ int idx = m_comboBox->findText(title);
+ if (idx < 0)
+ idx = 0;
+ m_comboBox->blockSignals(true);
+ m_comboBox->setCurrentIndex(idx);
+ m_comboBox->blockSignals(false);
+ }
+
+ SideBarItem *item = m_sideBar->item(title);
+ if (!item)
+ return;
+ removeCurrentItem();
+ m_currentItem = item;
+ layout()->addWidget(m_currentItem->widget());
+
+ // Add buttons and remember their actions for later removal
+ foreach (QToolButton *b, m_currentItem->createToolBarWidgets())
+ m_addedToolBarActions.append(m_toolbar->insertWidget(m_splitAction, b));
+}
+
+void SideBarWidget::updateAvailableItems()
+{
+ m_comboBox->blockSignals(true);
+ QString current = m_comboBox->currentText();
+ m_comboBox->clear();
+ QStringList itms = m_sideBar->availableItems();
+ if (!current.isEmpty() && !itms.contains(current))
+ itms.append(current);
+ qSort(itms);
+ m_comboBox->addItems(itms);
+ int idx = m_comboBox->findText(current);
+ if (idx < 0)
+ idx = 0;
+ m_comboBox->setCurrentIndex(idx);
+ m_splitButton->setEnabled(itms.count() > 1);
+ m_comboBox->blockSignals(false);
+}
+
+void SideBarWidget::removeCurrentItem()
+{
+ if (!m_currentItem)
+ return;
+
+ QWidget *w = m_currentItem->widget();
+ layout()->removeWidget(w);
+ w->setParent(0);
+ m_sideBar->makeItemAvailable(m_currentItem);
+
+ // Delete custom toolbar widgets
+ qDeleteAll(m_addedToolBarActions);
+ m_addedToolBarActions.clear();
+
+ m_currentItem = 0;
+}
+
+void SideBarWidget::setCurrentIndex(int)
+{
+ setCurrentItem(m_comboBox->currentText());
+ emit currentWidgetChanged();
+}
+
+Core::ICommand *SideBarWidget::command(const QString &title) const
+{
+ const QMap<QString, Core::ICommand*> shortcutMap = m_sideBar->shortcutMap();
+ QMap<QString, Core::ICommand*>::const_iterator r = shortcutMap.find(title);
+ if (r != shortcutMap.end())
+ return r.value();
+ return 0;
+}
+
+
+
+ComboBox::ComboBox(SideBarWidget *sideBarWidget)
+ : m_sideBarWidget(sideBarWidget)
+{
+}
+
+bool ComboBox::event(QEvent *e)
+{
+ if (e->type() == QEvent::ToolTip) {
+ QString txt = currentText();
+ Core::ICommand *cmd = m_sideBarWidget->command(txt);
+ if (cmd) {
+ txt = tr("Activate %1").arg(txt);
+ setToolTip(cmd->stringWithAppendedShortcut(txt));
+ } else {
+ setToolTip(txt);
+ }
+ }
+ return QComboBox::event(e);
+}
diff --git a/src/plugins/coreplugin/sidebar.h b/src/plugins/coreplugin/sidebar.h
new file mode 100644
index 0000000000..98ed1070c1
--- /dev/null
+++ b/src/plugins/coreplugin/sidebar.h
@@ -0,0 +1,184 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SIDEBAR_H
+#define SIDEBAR_H
+
+#include <QtCore/QMap>
+#include <QtGui/QWidget>
+#include <QtGui/QComboBox>
+
+#include <coreplugin/minisplitter.h>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+class QComboBox;
+class QToolBar;
+class QAction;
+class QToolButton;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class ICommand;
+
+namespace Internal {
+class SideBarWidget;
+class ComboBox;
+} // namespace Internal
+
+/*
+ * An item in the sidebar. Has a widget that is displayed in the sidebar and
+ * optionally a list of tool buttons that are added to the toolbar above it.
+ * The window title of the widget is displayed in the combo box.
+ *
+ * The SideBarItem takes ownership over the widget.
+ */
+class CORE_EXPORT SideBarItem
+{
+public:
+ SideBarItem(QWidget *widget)
+ : m_widget(widget)
+ {}
+
+ virtual ~SideBarItem();
+
+ QWidget *widget() { return m_widget; }
+
+ /* Should always return a new set of tool buttons.
+ *
+ * Workaround since there doesn't seem to be a nice way to remove widgets
+ * that have been added to a QToolBar without either not deleting the
+ * associated QAction or causing the QToolButton to be deleted.
+ */
+ virtual QList<QToolButton *> createToolBarWidgets()
+ {
+ return QList<QToolButton *>();
+ }
+
+private:
+ QWidget *m_widget;
+};
+
+class CORE_EXPORT SideBar : public MiniSplitter
+{
+ Q_OBJECT
+public:
+ /*
+ * The SideBar takes ownership of the SideBarItems.
+ */
+ SideBar(QList<SideBarItem*> widgetList,
+ QList<SideBarItem*> defaultVisible);
+ ~SideBar();
+
+ QStringList availableItems() const;
+ void makeItemAvailable(SideBarItem *item);
+ SideBarItem *item(const QString &title);
+
+ void saveSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+ void activateItem(SideBarItem *item);
+
+ void setShortcutMap(const QMap<QString, Core::ICommand*> &shortcutMap);
+ QMap<QString, Core::ICommand*> shortcutMap() const;
+
+private slots:
+ void split();
+ void close();
+ void updateWidgets();
+
+private:
+ Internal::SideBarWidget *insertSideBarWidget(int position,
+ const QString &title = QString());
+ QList<Internal::SideBarWidget*> m_widgets;
+
+ QMap<QString, SideBarItem*> m_itemMap;
+ QStringList m_availableItems;
+ QStringList m_defaultVisible;
+ QMap<QString, Core::ICommand*> m_shortcutMap;
+};
+
+namespace Internal {
+
+class SideBarWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ SideBarWidget(SideBar *sideBar, const QString &title);
+ ~SideBarWidget();
+
+ QString currentItemTitle() const;
+ void setCurrentItem(const QString &title);
+
+ void updateAvailableItems();
+ void removeCurrentItem();
+
+ Core::ICommand *command(const QString &title) const;
+
+signals:
+ void split();
+ void close();
+ void currentWidgetChanged();
+
+private slots:
+ void setCurrentIndex(int);
+
+private:
+ ComboBox *m_comboBox;
+ SideBarItem *m_currentItem;
+ QToolBar *m_toolbar;
+ QAction *m_splitAction;
+ QList<QAction *> m_addedToolBarActions;
+ SideBar *m_sideBar;
+ QToolButton *m_splitButton;
+ QToolButton *m_closeButton;
+};
+
+class ComboBox : public QComboBox
+{
+ Q_OBJECT
+
+public:
+ ComboBox(SideBarWidget *sideBarWidget);
+
+protected:
+ bool event(QEvent *event);
+
+private:
+ SideBarWidget *m_sideBarWidget;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // SIDEBAR_H
diff --git a/src/plugins/coreplugin/styleanimator.cpp b/src/plugins/coreplugin/styleanimator.cpp
new file mode 100644
index 0000000000..5133876b6c
--- /dev/null
+++ b/src/plugins/coreplugin/styleanimator.cpp
@@ -0,0 +1,156 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "styleanimator.h"
+
+#include <QtGui/QStyleOption>
+
+
+Animation * StyleAnimator::widgetAnimation(const QWidget *widget) const
+{
+ if (!widget)
+ return 0;
+ foreach (Animation *a, animations) {
+ if (a->widget() == widget)
+ return a;
+ }
+ return 0;
+}
+
+void Animation::paint(QPainter *painter, const QStyleOption *option)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(painter);
+}
+
+void Animation::drawBlendedImage(QPainter *painter, QRect rect, float alpha) {
+ if (_secondaryImage.isNull() || _primaryImage.isNull())
+ return;
+
+ if (_tempImage.isNull())
+ _tempImage = _secondaryImage;
+
+ const int a = qRound(alpha*256);
+ const int ia = 256 - a;
+ const int sw = _primaryImage.width();
+ const int sh = _primaryImage.height();
+ const int bpl = _primaryImage.bytesPerLine();
+ switch(_primaryImage.depth()) {
+ case 32:
+ {
+ uchar *mixed_data = _tempImage.bits();
+ const uchar *back_data = _primaryImage.bits();
+ const uchar *front_data = _secondaryImage.bits();
+ for (int sy = 0; sy < sh; sy++) {
+ quint32* mixed = (quint32*)mixed_data;
+ const quint32* back = (const quint32*)back_data;
+ const quint32* front = (const quint32*)front_data;
+ for (int sx = 0; sx < sw; sx++) {
+ quint32 bp = back[sx];
+ quint32 fp = front[sx];
+ mixed[sx] = qRgba ((qRed(bp)*ia + qRed(fp)*a)>>8,
+ (qGreen(bp)*ia + qGreen(fp)*a)>>8,
+ (qBlue(bp)*ia + qBlue(fp)*a)>>8,
+ (qAlpha(bp)*ia + qAlpha(fp)*a)>>8);
+ }
+ mixed_data += bpl;
+ back_data += bpl;
+ front_data += bpl;
+ }
+ }
+ default:
+ break;
+ }
+ painter->drawImage(rect, _tempImage);
+}
+
+void Transition::paint(QPainter *painter, const QStyleOption *option)
+{
+ float alpha = 1.0;
+ if (_duration > 0) {
+ QTime current = QTime::currentTime();
+
+ if (_startTime > current)
+ _startTime = current;
+
+ int timeDiff = _startTime.msecsTo(current);
+ alpha = timeDiff/(float)_duration;
+ if (timeDiff > _duration) {
+ _running = false;
+ alpha = 1.0;
+ }
+ }
+ else {
+ _running = false; }
+ drawBlendedImage(painter, option->rect, alpha);
+}
+
+void StyleAnimator::timerEvent(QTimerEvent *)
+{
+ for (int i = animations.size() - 1 ; i >= 0 ; --i) {
+ if (animations[i]->widget())
+ animations[i]->widget()->update();
+
+ if (!animations[i]->widget() ||
+ !animations[i]->widget()->isEnabled() ||
+ !animations[i]->widget()->isVisible() ||
+ animations[i]->widget()->window()->isMinimized() ||
+ !animations[i]->running())
+ {
+ Animation *a = animations.takeAt(i);
+ delete a;
+ }
+ }
+ if (animations.size() == 0 && animationTimer.isActive()) {
+ animationTimer.stop();
+ }
+}
+
+void StyleAnimator::stopAnimation(const QWidget *w)
+{
+ for (int i = animations.size() - 1 ; i >= 0 ; --i) {
+ if (animations[i]->widget() == w) {
+ Animation *a = animations.takeAt(i);
+ delete a;
+ break;
+ }
+ }
+}
+
+void StyleAnimator::startAnimation(Animation *t)
+{
+ stopAnimation(t->widget());
+ animations.append(t);
+ if (animations.size() > 0 && !animationTimer.isActive()) {
+ animationTimer.start(35, this);
+ }
+}
diff --git a/src/plugins/coreplugin/styleanimator.h b/src/plugins/coreplugin/styleanimator.h
new file mode 100644
index 0000000000..6e006ab25a
--- /dev/null
+++ b/src/plugins/coreplugin/styleanimator.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ANIMATION_H
+#define ANIMATION_H
+
+#include <QtCore/QPointer>
+#include <QtCore/QTime>
+#include <QtCore/QBasicTimer>
+#include <QtGui/QStyle>
+#include <QtGui/QPainter>
+#include <QtGui/QWidget>
+
+/*
+ * This is a set of helper classes to allow for widget animations in
+ * the style. Its mostly taken from Vista style so it should be fully documented
+ * there.
+ *
+ */
+
+class Animation
+{
+public :
+ Animation() : _running(true) { }
+ virtual ~Animation() { }
+ QWidget * widget() const { return _widget; }
+ bool running() const { return _running; }
+ const QTime &startTime() const { return _startTime; }
+ void setRunning(bool val) { _running = val; }
+ void setWidget(QWidget *widget) { _widget = widget; }
+ void setStartTime(const QTime &startTime) { _startTime = startTime; }
+ virtual void paint(QPainter *painter, const QStyleOption *option);
+
+protected:
+ void drawBlendedImage(QPainter *painter, QRect rect, float value);
+ QTime _startTime;
+ QPointer<QWidget> _widget;
+ QImage _primaryImage;
+ QImage _secondaryImage;
+ QImage _tempImage;
+ bool _running;
+};
+
+// Handles state transition animations
+class Transition : public Animation
+{
+public :
+ Transition() : Animation() {}
+ virtual ~Transition() { }
+ void setDuration(int duration) { _duration = duration; }
+ void setStartImage(const QImage &image) { _primaryImage = image; }
+ void setEndImage(const QImage &image) { _secondaryImage = image; }
+ virtual void paint(QPainter *painter, const QStyleOption *option);
+ int duration() const { return _duration; }
+ int _duration; //set time in ms to complete a state transition
+};
+
+class StyleAnimator : public QObject
+{
+ Q_OBJECT;
+
+public:
+ StyleAnimator(QObject *parent = 0) : QObject(parent) {}
+
+ void timerEvent(QTimerEvent *);
+ void startAnimation(Animation *);
+ void stopAnimation(const QWidget *);
+ Animation* widgetAnimation(const QWidget *) const;
+
+private:
+ QBasicTimer animationTimer;
+ QList <Animation*> animations;
+};
+
+#endif // ANIMATION_H
diff --git a/src/plugins/coreplugin/stylehelper.cpp b/src/plugins/coreplugin/stylehelper.cpp
new file mode 100644
index 0000000000..5630b464df
--- /dev/null
+++ b/src/plugins/coreplugin/stylehelper.cpp
@@ -0,0 +1,229 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "stylehelper.h"
+
+#include <QtGui/QPixmapCache>
+#include <QtGui/QWidget>
+
+// Clamps float color values within (0, 255)
+static int clamp(float x) {
+ const int val = x > 255 ? 255 : static_cast<int>(x);
+ return val < 0 ? 0 : val;
+}
+
+// Clamps float color values within (0, 255)
+/*
+static int range(float x, int min, int max) {
+ int val = x > max ? max : x;
+ return val < min ? min : val;
+}
+*/
+
+qreal StyleHelper::sidebarFontSize()
+{
+#if defined(Q_OS_MAC)
+ return 9;
+#else
+ return 7.5;
+#endif
+}
+
+QPalette StyleHelper::sidebarFontPalette(const QPalette &original)
+{
+ QPalette palette = original;
+ palette.setColor(QPalette::Active, QPalette::Text, panelTextColor());
+ palette.setColor(QPalette::Active, QPalette::WindowText, panelTextColor());
+ palette.setColor(QPalette::Inactive, QPalette::Text, panelTextColor().darker());
+ palette.setColor(QPalette::Inactive, QPalette::WindowText, panelTextColor().darker());
+ return palette;
+}
+
+QColor StyleHelper::panelTextColor()
+{
+ //qApp->palette().highlightedText().color();
+ return Qt::white;
+}
+
+QColor StyleHelper::m_baseColor(0x666666);
+
+QColor StyleHelper::baseColor()
+{
+ return m_baseColor;
+}
+
+QColor StyleHelper::highlightColor()
+{
+ QColor result = baseColor();
+ result.setHsv(result.hue(),
+ clamp(result.saturation()),
+ clamp(result.value() * 1.16));
+ return result;
+}
+
+QColor StyleHelper::shadowColor()
+{
+ QColor result = baseColor();
+ result.setHsv(result.hue(),
+ clamp(result.saturation() * 1.1),
+ clamp(result.value() * 0.70));
+ return result;
+}
+
+QColor StyleHelper::borderColor()
+{
+ QColor result = baseColor();
+ result.setHsv(result.hue(),
+ result.saturation(),
+ result.value() / 2);
+ return result;
+}
+
+void StyleHelper::setBaseColor(const QColor &color)
+{
+ if (color.isValid() && color != m_baseColor) {
+ m_baseColor = color;
+ foreach (QWidget *w, QApplication::topLevelWidgets())
+ w->update();
+ }
+}
+
+static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50)
+{
+ const int maxFactor = 100;
+ QColor tmp = colorA;
+ tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
+ tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
+ tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
+ return tmp;
+}
+
+void StyleHelper::verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect)
+{
+ QString key;
+ key.sprintf("mh_toolbar %d %d %d %d %d", spanRect.width(), spanRect.height(), clipRect.width(),
+ clipRect.height(), StyleHelper::baseColor().rgb());;
+ QPixmap pixmap;
+ QPainter *p = painter;
+ QRect rect = clipRect;
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ pixmap = QPixmap(clipRect.size());
+ p = new QPainter(&pixmap);
+ rect = QRect(0, 0, clipRect.width(), clipRect.height());
+ }
+
+ QColor base = StyleHelper::baseColor();
+ QLinearGradient grad(spanRect.topRight(), spanRect.topLeft());
+ grad.setColorAt(0, highlightColor());
+ grad.setColorAt(0.301, base);
+ grad.setColorAt(1, shadowColor());
+ p->fillRect(rect, grad);
+
+ QColor light(255, 255, 255, 80);
+ p->setPen(light);
+ p->drawLine(rect.topRight() - QPoint(1, 0), rect.bottomRight() - QPoint(1, 0));
+
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ painter->drawPixmap(clipRect.topLeft(), pixmap);
+ p->end();
+ delete p;
+ QPixmapCache::insert(key, pixmap);
+ }
+
+}
+
+void StyleHelper::horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect)
+{
+ QString key;
+ key.sprintf("mh_toolbar %d %d %d %d %d", spanRect.width(), spanRect.height(),
+ clipRect.width(), clipRect.height(), StyleHelper::baseColor().rgb());
+ QPixmap pixmap;
+ QPainter *p = painter;
+ QRect rect = clipRect;
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ pixmap = QPixmap(clipRect.size());
+ p = new QPainter(&pixmap);
+ rect = QRect(0, 0, clipRect.width(), clipRect.height());
+ }
+
+ QColor base = StyleHelper::baseColor();
+ QLinearGradient grad(rect.topLeft(), rect.bottomLeft());
+
+ grad.setColorAt(0, highlightColor().lighter(120));
+ grad.setColorAt(0.4, highlightColor());
+ grad.setColorAt(0.401, base);
+ grad.setColorAt(1, shadowColor());
+ p->fillRect(rect, grad);
+
+ QLinearGradient shadowGradient(spanRect.topLeft(), spanRect.topRight());
+ shadowGradient.setColorAt(0, QColor(0, 0, 0, 30));
+ QColor highlight = highlightColor().lighter(130);
+ highlight.setAlpha(100);
+ shadowGradient.setColorAt(0.7, highlight);
+ shadowGradient.setColorAt(1, QColor(0, 0, 0, 40));
+ p->fillRect(rect, shadowGradient);
+
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ painter->drawPixmap(clipRect.topLeft(), pixmap);
+ p->end();
+ delete p;
+ QPixmapCache::insert(key, pixmap);
+ }
+}
+
+void StyleHelper::menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect)
+{
+ QString key;
+ key.sprintf("mh_toolbar %d %d %d %d %d", spanRect.width(), spanRect.height(), clipRect.width(),
+ clipRect.height(), StyleHelper::baseColor().rgb());;
+ QPixmap pixmap;
+ QPainter *p = painter;
+ QRect rect = clipRect;
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ pixmap = QPixmap(clipRect.size());
+ p = new QPainter(&pixmap);
+ rect = QRect(0, 0, clipRect.width(), clipRect.height());
+ }
+
+ QLinearGradient grad(spanRect.topLeft(), spanRect.bottomLeft());
+ QColor menuColor = mergedColors(StyleHelper::baseColor(), QColor(240, 240, 240), 25);
+ grad.setColorAt(0, menuColor.lighter(112));
+ grad.setColorAt(1, menuColor);
+ p->fillRect(rect, grad);
+
+ if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) {
+ painter->drawPixmap(clipRect.topLeft(), pixmap);
+ p->end();
+ delete p;
+ QPixmapCache::insert(key, pixmap);
+ }
+}
diff --git a/src/plugins/coreplugin/stylehelper.h b/src/plugins/coreplugin/stylehelper.h
new file mode 100644
index 0000000000..cceb23a012
--- /dev/null
+++ b/src/plugins/coreplugin/stylehelper.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef STYLEHELPER_H
+#define STYLEHELPER_H
+
+#include "core_global.h"
+
+#include <QtCore/QRect>
+#include <QtGui/QPainter>
+#include <QtGui/QApplication>
+#include <QtGui/QPalette>
+#include <QtGui/QColor>
+
+// Helper class holding all custom color values
+
+class CORE_EXPORT StyleHelper {
+public:
+ // Height of the project explorer navigation bar
+ static int navigationWidgetHeight() { return 24; }
+ static qreal sidebarFontSize();
+ static QPalette sidebarFontPalette(const QPalette &original);
+
+ // This is our color table, all colors derive from baseColor
+ static QColor baseColor();
+ static QColor panelTextColor();
+ static QColor highlightColor();
+ static QColor shadowColor();
+ static QColor borderColor();
+ static QColor buttonTextColor() { return QColor(0x4c4c4c); }
+
+ // Sets the base color and makes sure all top level widgets are updated
+ static void setBaseColor(const QColor &color);
+
+ // Gradients used for panels
+ static void horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect);
+ static void verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect);
+ static void menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect);
+
+ // Pixmap cache should only be enabled for X11 due to slow gradients
+ static bool usePixmapCache() {
+ return true;
+ }
+
+private:
+ static QColor m_baseColor;
+};
+
+#endif // STYLEHELPER_H
diff --git a/src/plugins/coreplugin/tabpositionindicator.cpp b/src/plugins/coreplugin/tabpositionindicator.cpp
new file mode 100644
index 0000000000..497b351ad9
--- /dev/null
+++ b/src/plugins/coreplugin/tabpositionindicator.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QBrush>
+#include <QtGui/QPalette>
+
+#include "tabpositionindicator.h"
+
+using namespace Core::Internal;
+
+TabPositionIndicator::TabPositionIndicator()
+ : QWidget(0, Qt::ToolTip)
+{
+
+}
+
+void TabPositionIndicator::paintEvent(QPaintEvent *event)
+{
+ QPainter p(this);
+ QPen pen = p.pen();
+ pen.setWidth(2);
+ pen.setColor(palette().color(QPalette::Active, QPalette::LinkVisited));
+ pen.setStyle(Qt::DotLine);
+ p.setPen(pen);
+ p.drawLine(event->rect().topLeft(), event->rect().bottomLeft());
+}
diff --git a/src/plugins/coreplugin/tabpositionindicator.h b/src/plugins/coreplugin/tabpositionindicator.h
new file mode 100644
index 0000000000..db159a58d0
--- /dev/null
+++ b/src/plugins/coreplugin/tabpositionindicator.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TABPOSITIONINDICATOR_H
+#define TABPOSITIONINDICATOR_H
+
+#include <QtGui/QWidget>
+
+#define TABPOSITIONINDICATOR_WIDTH 2
+
+namespace Core {
+namespace Internal {
+
+class TabPositionIndicator : public QWidget
+{
+ Q_OBJECT
+public:
+ TabPositionIndicator();
+ inline int indicatorWidth() { return TABPOSITIONINDICATOR_WIDTH; }
+
+private:
+ void paintEvent(QPaintEvent *event);
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //TABPOSITIONINDICATOR_H
diff --git a/src/plugins/coreplugin/uniqueidmanager.cpp b/src/plugins/coreplugin/uniqueidmanager.cpp
new file mode 100644
index 0000000000..802bd685e3
--- /dev/null
+++ b/src/plugins/coreplugin/uniqueidmanager.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "uniqueidmanager.h"
+#include "coreconstants.h"
+
+using namespace Core;
+
+UniqueIDManager* UniqueIDManager::m_instance = 0;
+
+UniqueIDManager::UniqueIDManager()
+{
+ m_instance = this;
+ m_uniqueIdentifiers.insert(Constants::C_GLOBAL, Constants::C_GLOBAL_ID);
+}
+
+UniqueIDManager::~UniqueIDManager()
+{
+ m_instance = 0;
+}
+
+bool UniqueIDManager::hasUniqueIdentifier(const QString &id) const
+{
+ return m_uniqueIdentifiers.contains(id);
+}
+
+int UniqueIDManager::uniqueIdentifier(const QString &id)
+{
+ if (hasUniqueIdentifier(id))
+ return m_uniqueIdentifiers.value(id);
+
+ int uid = m_uniqueIdentifiers.count() + 1;
+ m_uniqueIdentifiers.insert(id, uid);
+ return uid;
+}
+
+QString UniqueIDManager::stringForUniqueIdentifier(int uid)
+{
+ return m_uniqueIdentifiers.key(uid);
+}
diff --git a/src/plugins/coreplugin/uniqueidmanager.h b/src/plugins/coreplugin/uniqueidmanager.h
new file mode 100644
index 0000000000..36b5df034d
--- /dev/null
+++ b/src/plugins/coreplugin/uniqueidmanager.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef UNIQUEIDMANAGER_H
+#define UNIQUEIDMANAGER_H
+
+#include "core_global.h"
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+
+namespace Core {
+
+class CORE_EXPORT UniqueIDManager
+{
+public:
+ UniqueIDManager();
+ ~UniqueIDManager();
+
+ static UniqueIDManager* instance() { return m_instance; }
+
+ bool hasUniqueIdentifier(const QString &id) const;
+ int uniqueIdentifier(const QString &id);
+ QString stringForUniqueIdentifier(int uid);
+
+private:
+ QHash<QString, int> m_uniqueIdentifiers;
+ static UniqueIDManager *m_instance;
+};
+
+} // namespace Core
+
+#endif // UNIQUEIDMANAGER_H
diff --git a/src/plugins/coreplugin/variablemanager.cpp b/src/plugins/coreplugin/variablemanager.cpp
new file mode 100644
index 0000000000..adf65b64b4
--- /dev/null
+++ b/src/plugins/coreplugin/variablemanager.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "variablemanager.h"
+
+using namespace Core;
+
+VariableManager *VariableManager::m_instance = 0;
+
+VariableManager::VariableManager(QObject *parent) : QObject(parent)
+{
+ m_instance = this;
+}
+
+VariableManager::~VariableManager()
+{
+ m_instance = 0;
+}
+
+void VariableManager::insert(const QString &variable, const QString &value)
+{
+ m_map.insert(variable, value);
+}
+
+QString VariableManager::value(const QString &variable)
+{
+ return m_map.value(variable);
+}
+
+QString VariableManager::value(const QString &variable, const QString &defaultValue)
+{
+ return m_map.value(variable, defaultValue);
+}
+
+void VariableManager::remove(const QString &variable)
+{
+ m_map.remove(variable);
+}
+
+QString VariableManager::resolve(const QString &stringWithVariables)
+{
+ QString result = stringWithVariables;
+ QMapIterator<QString, QString> i(m_map);
+ while (i.hasNext()) {
+ i.next();
+ result.replace(QString("${%1}").arg(i.key()), i.value());
+ }
+ return result;
+}
diff --git a/src/plugins/coreplugin/variablemanager.h b/src/plugins/coreplugin/variablemanager.h
new file mode 100644
index 0000000000..a5e39522ab
--- /dev/null
+++ b/src/plugins/coreplugin/variablemanager.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VARIABLEMANAGER_H
+#define VARIABLEMANAGER_H
+
+#include "core_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+
+namespace Core {
+
+class CORE_EXPORT VariableManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ VariableManager(QObject *parent);
+ ~VariableManager();
+
+ static VariableManager* instance() { return m_instance; }
+
+ void insert(const QString &variable, const QString &value);
+ QString value(const QString &variable);
+ QString value(const QString &variable, const QString &defaultValue);
+ void remove(const QString &variable);
+ QString resolve(const QString &stringWithVariables);
+
+private:
+ QMap<QString, QString> m_map;
+ static VariableManager *m_instance;
+};
+
+} // namespace Core
+
+#endif // VARIABLEMANAGER_H
diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp
new file mode 100644
index 0000000000..36ba1ecd28
--- /dev/null
+++ b/src/plugins/coreplugin/vcsmanager.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "vcsmanager.h"
+#include "iversioncontrol.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QCoreApplication>
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtGui/QMessageBox>
+
+namespace Core {
+
+struct VCSManagerPrivate {
+ QMap<QString, IVersionControl *> m_cachedMatches;
+};
+
+VCSManager::VCSManager() :
+ m_d(new VCSManagerPrivate)
+{
+}
+
+VCSManager::~VCSManager()
+{
+ delete m_d;
+}
+
+IVersionControl* VCSManager::findVersionControlForDirectory(const QString &directory)
+{
+ // first look into the cache
+ int pos = 0;
+ { // First try the whole name
+ QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directory);
+ if (it != m_d->m_cachedMatches.constEnd()) {
+ return it.value();
+ }
+ }
+
+ while(true) {
+ int index = directory.indexOf('/', pos);
+ if (index == -1)
+ break;
+ QString directoryPart = directory.left(index);
+ QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directoryPart);
+ if (it != m_d->m_cachedMatches.constEnd()) {
+ return it.value();
+ }
+ pos = index+1;
+ }
+
+ // ah nothing so ask the IVersionControls directly
+ QList<IVersionControl *> versionControls = ExtensionSystem::PluginManager::instance()->getObjects<IVersionControl>();
+ foreach(IVersionControl * versionControl, versionControls) {
+ if (versionControl->managesDirectory(directory)) {
+ m_d->m_cachedMatches.insert(versionControl->findTopLevelForDirectory(directory), versionControl);
+ return versionControl;
+ }
+ }
+ return 0;
+}
+
+void VCSManager::showDeleteDialog(const QString &fileName)
+{
+ IVersionControl *vc = findVersionControlForDirectory(QFileInfo(fileName).absolutePath());
+ if (!vc)
+ return;
+ const QString title = QCoreApplication::translate("VCSManager", "Version Control");
+ const QString msg = QCoreApplication::translate("VCSManager",
+ "Would you like to remove this file from the version control system?\n"
+ "Note: This might remove the local file.");
+ const QMessageBox::StandardButton button =
+ QMessageBox::question(0, title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ if (button == QMessageBox::Yes) {
+ vc->vcsDelete(fileName);
+ }
+}
+
+}
diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h
new file mode 100644
index 0000000000..3fad411ec4
--- /dev/null
+++ b/src/plugins/coreplugin/vcsmanager.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSMANAGER_H
+#define VCSMANAGER_H
+
+
+#include "core_global.h"
+#include <QtCore/QString>
+
+namespace Core {
+
+struct VCSManagerPrivate;
+class IVersionControl;
+
+// The VCSManager has only one notable function:
+// findVersionControlFor(), which returns the IVersionControl * for a given
+// filename. Note that the VCSManager assumes that if a IVersionControl *
+// manages a directory, then it also manages all the files and all the
+// subdirectories.
+//
+// It works by asking all IVersionControl * if they manage the file, and ask
+// for the topmost directory it manages. This information is cached and
+// VCSManager thus knows pretty fast which IVersionControl * is responsible.
+
+class CORE_EXPORT VCSManager
+{
+ Q_DISABLE_COPY(VCSManager)
+public:
+ VCSManager();
+ virtual ~VCSManager();
+
+ IVersionControl *findVersionControlForDirectory(const QString &directory);
+
+ // Shows a confirmation dialog,
+ // wheter the file should also be deleted from revision control
+ // Calls sccDelete on the file
+ void showDeleteDialog(const QString &fileName);
+
+private:
+ VCSManagerPrivate *m_d;
+};
+
+} // namespace Core
+
+#endif // VCSMANAGER_H
diff --git a/src/plugins/coreplugin/versiondialog.cpp b/src/plugins/coreplugin/versiondialog.cpp
new file mode 100644
index 0000000000..45b8d6a800
--- /dev/null
+++ b/src/plugins/coreplugin/versiondialog.cpp
@@ -0,0 +1,135 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "versiondialog.h"
+#include "coreconstants.h"
+#include "coreimpl.h"
+
+using namespace Core;
+using namespace Core::Internal;
+using namespace Core::Constants;
+
+#include <QtCore/QDate>
+#include <QtCore/QFile>
+#include <QtGui/QGridLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QPushButton>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QTextBrowser>
+
+VersionDialog::VersionDialog(QWidget *parent):
+ QDialog(parent)
+{
+ // We need to set the window icon explicitly here since for some reason the
+ // application icon isn't used when the size of the dialog is fixed (at least not on X11/GNOME)
+ setWindowIcon(QIcon(":/qworkbench/images/qtcreator_logo_128.png"));
+
+ setWindowTitle(tr("About Qt Creator"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ QGridLayout *layout = new QGridLayout(this);
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+
+ QString version = QLatin1String(IDE_VERSION_LONG);
+ version += QDate(2007, 25, 10).toString(Qt::SystemLocaleDate);
+
+ const QString description = tr(
+ "<h3>Qt Creator %1</h3>"
+ "Based on Qt %2<br/>"
+ "<br/>"
+ "Built on " __DATE__ " at " __TIME__ "<br />"
+#ifdef IDE_REVISION
+ "Using revision %5<br/>"
+#endif
+ "<br/>"
+ "<br/>"
+ "Copyright 2006-%3 %4. All rights reserved.<br/>"
+ "<br/>"
+ "The program is provided AS IS with NO WARRANTY OF ANY KIND, "
+ "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A "
+ "PARTICULAR PURPOSE.<br/>")
+ .arg(version, QLatin1String(QT_VERSION_STR), QLatin1String(IDE_YEAR), (QLatin1String(IDE_AUTHOR))
+#ifdef IDE_REVISION
+ , QString(IDE_REVISION_STR).left(10)
+#endif
+ );
+
+ QLabel *copyRightLabel = new QLabel(description);
+ copyRightLabel->setWordWrap(true);
+ copyRightLabel->setOpenExternalLinks(true);
+ copyRightLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+ QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
+ Q_ASSERT(closeButton);
+ buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole | QDialogButtonBox::AcceptRole));
+ connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
+
+ buttonBox->addButton(tr("Show License"), QDialogButtonBox::HelpRole);
+ connect(buttonBox , SIGNAL(helpRequested()), this, SLOT(popupLicense()));
+
+ QLabel *logoLabel = new QLabel;
+ logoLabel->setPixmap(QPixmap(QLatin1String(":/qworkbench/images/qtcreator_logo_128.png")));
+ layout->addWidget(logoLabel , 0, 0, 1, 1);
+ layout->addWidget(copyRightLabel, 0, 1, 4, 4);
+ layout->addWidget(buttonBox, 4, 0, 1, 5);
+}
+
+void VersionDialog::popupLicense()
+{
+ QDialog *dialog = new QDialog(this);
+ dialog->setWindowTitle("License");
+ QVBoxLayout *layout = new QVBoxLayout(dialog);
+ QTextBrowser *licenseBrowser = new QTextBrowser(dialog);
+ layout->addWidget(licenseBrowser);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+ connect(buttonBox , SIGNAL(rejected()), dialog, SLOT(reject()));
+ layout->addWidget(buttonBox);
+
+ // Read file into string
+ ICore * core = CoreImpl::instance();
+ Q_ASSERT(core != NULL);
+ QString fileName = core->resourcePath() + "/license.txt";
+ QFile file(fileName);
+
+ QString licenseText;
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ licenseText = "File '" + fileName + "' could not be read.";
+ else
+ licenseText = file.readAll();
+
+ licenseBrowser->setPlainText(licenseText);
+
+ dialog->setMinimumSize(QSize(550, 690));
+ dialog->exec();
+ delete dialog;
+}
diff --git a/src/plugins/coreplugin/versiondialog.h b/src/plugins/coreplugin/versiondialog.h
new file mode 100644
index 0000000000..aa17bb8d3e
--- /dev/null
+++ b/src/plugins/coreplugin/versiondialog.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VERSIONDIALOG_H
+#define VERSIONDIALOG_H
+
+#include <QtGui/QDialog>
+
+namespace Core {
+namespace Internal {
+
+class VersionDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit VersionDialog(QWidget *parent);
+private slots:
+ void popupLicense();
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // VERSIONDIALOG_H
diff --git a/src/plugins/coreplugin/viewmanager.cpp b/src/plugins/coreplugin/viewmanager.cpp
new file mode 100644
index 0000000000..ea520e0b25
--- /dev/null
+++ b/src/plugins/coreplugin/viewmanager.cpp
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "viewmanager.h"
+
+#include "coreconstants.h"
+#include "mainwindow.h"
+#include "uniqueidmanager.h"
+#include "iview.h"
+
+#include <QtCore/QSettings>
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#include <QtGui/QDockWidget>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QMenu>
+#include <QtGui/QStatusBar>
+#include <QtGui/QLabel>
+#include <QtGui/QComboBox>
+#include <QtGui/QStackedWidget>
+#include <QtGui/QToolButton>
+
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/icommand.h>
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <aggregation/aggregate.h>
+
+#include <QtGui/QHBoxLayout>
+
+using namespace Core;
+using namespace Core::Internal;
+
+ViewManager::ViewManager(MainWindow *mainWnd) :
+ ViewManagerInterface(mainWnd),
+ m_mainWnd(mainWnd)
+{
+ for(int i = 0; i< 3; ++i) {
+ QWidget *w = new QWidget();
+ m_mainWnd->statusBar()->insertPermanentWidget(i, w);
+ w->setLayout(new QHBoxLayout);
+ w->setVisible(true);
+ w->layout()->setMargin(0);
+ m_statusBarWidgets.append(w);
+ }
+ QLabel *l = new QLabel();
+ m_mainWnd->statusBar()->insertPermanentWidget(3, l, 1);
+}
+
+ViewManager::~ViewManager()
+{
+}
+
+void ViewManager::init()
+{
+ connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)),
+ this, SLOT(objectAdded(QObject*)));
+ connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)),
+ this, SLOT(aboutToRemoveObject(QObject*)));
+}
+
+void ViewManager::objectAdded(QObject *obj)
+{
+ IView * view = Aggregation::query<IView>(obj);
+ if (!view)
+ return;
+
+ QWidget *viewWidget = 0;
+ viewWidget = view->widget();
+ m_statusBarWidgets.at(view->defaultPosition())->layout()->addWidget(viewWidget);
+
+ m_viewMap.insert(view, viewWidget);
+ viewWidget->setObjectName(view->uniqueViewName());
+ m_mainWnd->addContextObject(view);
+}
+
+void ViewManager::aboutToRemoveObject(QObject *obj)
+{
+ IView * view = Aggregation::query<IView>(obj);
+ if(!view)
+ return;
+ m_mainWnd->removeContextObject(view);
+}
+
+void ViewManager::extensionsInitalized()
+{
+ QSettings *settings = m_mainWnd->settings();
+ m_mainWnd->restoreState(settings->value(QLatin1String("ViewGroup_Default"), QByteArray()).toByteArray());
+}
+
+void ViewManager::saveSettings(QSettings *settings)
+{
+ settings->setValue(QLatin1String("ViewGroup_Default"), m_mainWnd->saveState());
+}
+
+IView * ViewManager::view(const QString & id)
+{
+ QList<IView *> list = m_mainWnd->pluginManager()->getObjects<IView>();
+ foreach (IView * view, list) {
+ if (view->uniqueViewName() == id)
+ return view;
+ }
+ return 0;
+}
diff --git a/src/plugins/coreplugin/viewmanager.h b/src/plugins/coreplugin/viewmanager.h
new file mode 100644
index 0000000000..615a867bee
--- /dev/null
+++ b/src/plugins/coreplugin/viewmanager.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VIEWMANAGER_H
+#define VIEWMANAGER_H
+
+#include "viewmanagerinterface.h"
+
+#include <QtCore/QMap>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QSettings;
+class QMainWindow;
+class QComboBox;
+class QStackedWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class UniqueIDManager;
+
+namespace Internal {
+
+class MainWindow;
+class NavigationWidget;
+
+class ViewManager
+ : public Core::ViewManagerInterface
+{
+ Q_OBJECT
+
+public:
+ ViewManager(MainWindow *mainWnd);
+ ~ViewManager();
+
+ void init();
+ void extensionsInitalized();
+ void saveSettings(QSettings *settings);
+
+ IView * view(const QString & id);
+private slots:
+ void objectAdded(QObject *obj);
+ void aboutToRemoveObject(QObject *obj);
+
+private:
+ QMap<Core::IView *, QWidget *> m_viewMap;
+
+ MainWindow *m_mainWnd;
+ QList<QWidget *> m_statusBarWidgets;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif //VIEWMANAGER_H
diff --git a/src/plugins/coreplugin/viewmanagerinterface.h b/src/plugins/coreplugin/viewmanagerinterface.h
new file mode 100644
index 0000000000..0b53e02908
--- /dev/null
+++ b/src/plugins/coreplugin/viewmanagerinterface.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VIEWMANAGERINTERFACE_H
+#define VIEWMANAGERINTERFACE_H
+
+#include <coreplugin/core_global.h>
+#include <QtCore/QObject>
+#include <QtGui/QKeySequence>
+
+QT_BEGIN_NAMESPACE
+class QIcon;
+class QString;
+QT_END_NAMESPACE
+
+namespace Core {
+
+class IView;
+
+class CORE_EXPORT ViewManagerInterface
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ ViewManagerInterface(QObject *parent = 0) : QObject(parent) { }
+ virtual ~ViewManagerInterface() { }
+
+ // returns the view @p id
+ virtual IView * view(const QString & id) = 0;
+};
+
+} //namespace Core
+
+#endif //VIEWMANAGERINTERFACE_H
diff --git a/src/plugins/coreplugin/welcomemode.cpp b/src/plugins/coreplugin/welcomemode.cpp
new file mode 100644
index 0000000000..e6c69c0001
--- /dev/null
+++ b/src/plugins/coreplugin/welcomemode.cpp
@@ -0,0 +1,271 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "welcomemode.h"
+#include "coreconstants.h"
+#include "uniqueidmanager.h"
+#include "coreimpl.h"
+#include "modemanager.h"
+
+#ifdef QT_WEBKIT
+#include <QtWebKit/QWebView>
+#include <QtGui/QApplication>
+#include <QtCore/QFileInfo>
+#else
+#include <QtGui/QLabel>
+#endif
+#include <QtGui/QToolBar>
+#include <QtGui/QDesktopServices>
+
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <QtCore/QUrl>
+
+namespace Core {
+namespace Internal {
+
+static QString readFile(const QString &name)
+{
+ QFile f(name);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning("Unable to open %s: %s", name.toUtf8().constData(), f.errorString().toUtf8().constData());
+ return QString();
+ }
+ QTextStream ts(&f);
+ return ts.readAll();
+}
+
+struct WelcomeModePrivate {
+ WelcomeModePrivate();
+
+ QWidget *m_widget;
+#ifdef QT_WEBKIT
+ QWebView *m_webview;
+#else
+ QLabel *m_label;
+#endif
+
+ WelcomeMode::WelcomePageData lastData;
+
+ const QString m_htmlTemplate;
+ const QString m_sessionHtmlTemplate;
+ const QString m_projectHtmlTemplate;
+ const QUrl m_baseUrl;
+};
+
+WelcomeModePrivate::WelcomeModePrivate() :
+ m_widget(new QWidget),
+#ifdef QT_WEBKIT
+ m_webview(new QWebView),
+#else
+ m_label(new QLabel),
+#endif
+ m_htmlTemplate(readFile(QLatin1String(":/qworkbench/html/welcome.html"))),
+ m_sessionHtmlTemplate(readFile(QLatin1String(":/qworkbench/html/recent_sessions.html"))),
+ m_projectHtmlTemplate(readFile(QLatin1String(":/qworkbench/html/recent_projects.html"))),
+ m_baseUrl(QUrl(QLatin1String("qrc:/qworkbench/html/welcome.html")))
+{
+}
+
+#ifndef QT_WEBKIT
+
+const char *LABEL = "<center><table><tr><td><img src=\":/qworkbench/html/images/product_logo.png\"/></td><td width=300>"
+ "<h2><br/><br/>Welcome</h2><p> Qt Creator is an intuitive, modern cross platform IDE that enables "
+ "developers to create graphically appealing applications for desktop, "
+ "embedded, and mobile devices. "
+ "<p><font color=\"red\">(This startup page lacks features due to disabled webkit support)</font>"
+ "</td></tr></table>";
+
+#endif
+// --- WelcomePageData
+
+bool WelcomeMode::WelcomePageData::operator==(const WelcomePageData &rhs) const
+{
+ return previousSession == rhs.previousSession
+ && activeSession == rhs.activeSession
+ && sessionList == rhs.sessionList
+ && projectList == rhs.projectList;
+}
+
+bool WelcomeMode::WelcomePageData::operator!=(const WelcomePageData &rhs) const
+{
+ return previousSession != rhs.previousSession
+ || activeSession != rhs.activeSession
+ || sessionList != rhs.sessionList
+ || projectList != rhs.projectList;
+}
+
+QDebug operator<<(QDebug dgb, const WelcomeMode::WelcomePageData &d)
+{
+ dgb.nospace() << "PreviousSession=" << d.previousSession
+ << " activeSession=" << d.activeSession
+ << " sessionList=" << d.sessionList
+ << " projectList=" << d.projectList;
+ return dgb;
+}
+
+// --- WelcomeMode
+WelcomeMode::WelcomeMode() :
+ m_d(new WelcomeModePrivate)
+{
+ QVBoxLayout *l = new QVBoxLayout(m_d->m_widget);
+ l->setMargin(0);
+ l->setSpacing(0);
+ l->addWidget(new QToolBar(m_d->m_widget));
+#ifdef QT_WEBKIT
+ connect(m_d->m_webview, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl)));
+
+ WelcomePageData welcomePageData;
+ updateWelcomePage(welcomePageData);
+
+ l->addWidget(m_d->m_webview);
+
+#else
+ m_d->m_label->setWordWrap(true);
+ m_d->m_label->setAlignment(Qt::AlignCenter);
+ m_d->m_label->setText(LABEL);
+ l->addWidget(m_d->m_label);
+#endif
+}
+
+WelcomeMode::~WelcomeMode()
+{
+ delete m_d;
+}
+
+QString WelcomeMode::name() const
+{
+ return QLatin1String("Welcome");
+}
+
+QIcon WelcomeMode::icon() const
+{
+ return QIcon(QLatin1String(":/qworkbench/images/qtcreator_logo_32.png"));
+}
+
+int WelcomeMode::priority() const
+{
+ return Constants::P_MODE_WELCOME;
+}
+
+QWidget* WelcomeMode::widget()
+{
+ return m_d->m_widget;
+}
+
+const char* WelcomeMode::uniqueModeName() const
+{
+ return Constants::MODE_WELCOME;
+}
+
+QList<int> WelcomeMode::context() const
+{
+ static QList<int> contexts = QList<int>()
+ << CoreImpl::instance()->uniqueIDManager()->uniqueIdentifier(Constants::C_WELCOME_MODE);
+ return contexts;
+}
+
+void WelcomeMode::updateWelcomePage(const WelcomePageData &welcomePageData)
+{
+// should really only modify the DOM tree
+
+#ifndef QT_WEBKIT
+ Q_UNUSED(welcomePageData);
+#else
+
+ // Update only if data are modified
+ if (welcomePageData == m_d->lastData)
+ return;
+ m_d->lastData = welcomePageData;
+
+ QString html = m_d->m_htmlTemplate;
+
+ if (!welcomePageData.previousSession.isEmpty() || !welcomePageData.projectList.isEmpty()) {
+ QString sessionHtml = m_d->m_sessionHtmlTemplate;
+ sessionHtml.replace(QLatin1String("LAST_SESSION"), welcomePageData.previousSession);
+
+ if (welcomePageData.sessionList.count() > 1) {
+ QString sessions;
+ foreach (QString s, welcomePageData.sessionList) {
+ QString last;
+ if (s == welcomePageData.previousSession)
+ last = tr(" (last session)");
+ sessions += QString::fromLatin1("<li><p><a href=\"gh-session:%1\">%2%3</a></p></li>").arg(s, s, last);
+ }
+ sessionHtml.replace(QLatin1String("<!-- RECENT SESSIONS LIST -->"), sessions);
+ }
+ html.replace(QLatin1String("<!-- RECENT SESSIONS -->"), sessionHtml);
+
+ QString projectHtml = m_d->m_projectHtmlTemplate;
+ {
+ QString projects;
+ QTextStream str(&projects);
+ foreach (const QString &s, welcomePageData.projectList) {
+ const QFileInfo fi(s);
+ str << "<li><p><a href=\"gh-project:" << s << "\" title=\""
+ << fi.absolutePath() << "\">" << fi.fileName() << "</a></p></li>\n";
+ }
+ projectHtml.replace(QLatin1String("<!-- RECENT PROJECTS LIST -->"), projects);
+ }
+ html.replace(QLatin1String("<!-- RECENT PROJECTS -->"), projectHtml);
+ }
+
+ m_d->m_webview->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
+ m_d->m_webview->setHtml(html, m_d->m_baseUrl);
+#endif
+}
+
+void WelcomeMode::linkClicked(const QUrl &url)
+{
+ QString scheme = url.scheme();
+ Core::ModeManager *modeManager = CoreImpl::instance()->modeManager();
+ if (scheme.startsWith(QLatin1String("gh"))) {
+ QString s = url.toString(QUrl::RemoveScheme);
+ if (scheme == QLatin1String("gh")) {
+ emit requestHelp(s);
+ } else if (scheme == QLatin1String("gh-project")) {
+ emit requestProject(s);
+ if (modeManager->currentMode() == this)
+ modeManager->activateMode(Core::Constants::MODE_EDIT);
+ } else if (scheme == QLatin1String("gh-session")) {
+ emit requestSession(s);
+ if (modeManager->currentMode() == this)
+ modeManager->activateMode(Core::Constants::MODE_EDIT);
+ }
+ } else {
+ QDesktopServices::openUrl(url);
+ }
+}
+
+} // namespace Internal
+} // namespace Core
diff --git a/src/plugins/coreplugin/welcomemode.h b/src/plugins/coreplugin/welcomemode.h
new file mode 100644
index 0000000000..416e54c2dc
--- /dev/null
+++ b/src/plugins/coreplugin/welcomemode.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WELCOMEMODE_H
+#define WELCOMEMODE_H
+
+#include <coreplugin/imode.h>
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+class QUrl;
+class QLabel;
+QT_END_NAMESPACE
+
+namespace Core {
+
+namespace Internal {
+
+struct WelcomeModePrivate;
+
+class CORE_EXPORT WelcomeMode : public Core::IMode
+{
+ Q_OBJECT
+
+public:
+ WelcomeMode();
+ ~WelcomeMode();
+
+ struct WelcomePageData{
+ bool operator==(const WelcomePageData &rhs) const;
+ bool operator!=(const WelcomePageData &rhs) const;
+
+ QString previousSession;
+ QString activeSession;
+ QStringList sessionList;
+ QStringList projectList;
+ };
+
+ void updateWelcomePage(const WelcomePageData &welcomePageData);
+
+ // IMode
+ QString name() const;
+ QIcon icon() const;
+ int priority() const;
+ QWidget* widget();
+ const char* uniqueModeName() const;
+ QList<int> context() const;
+ void activated();
+ QString contextHelpId() const
+ { return QLatin1String("Qt Creator"); }
+
+signals:
+ void requestProject(const QString &project);
+ void requestSession(const QString &session);
+ void requestHelp(const QString &help);
+
+private slots:
+ void linkClicked(const QUrl &url);
+
+private:
+ WelcomeModePrivate *m_d;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // WELCOMEMODE_H
diff --git a/src/plugins/cpaster/CodePaster.pluginspec b/src/plugins/cpaster/CodePaster.pluginspec
new file mode 100644
index 0000000000..2ddd73902e
--- /dev/null
+++ b/src/plugins/cpaster/CodePaster.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="CodePaster" version="0.1" compatVersion="0.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Codepaster plugin for pushing/fetching diff from server</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/cpaster/cpaster.pro b/src/plugins/cpaster/cpaster.pro
new file mode 100644
index 0000000000..4ecdc54537
--- /dev/null
+++ b/src/plugins/cpaster/cpaster.pro
@@ -0,0 +1,15 @@
+QT += network
+TEMPLATE = lib
+TARGET = CodePaster
+
+include(../../qworkbenchplugin.pri)
+include(cpaster_dependencies.pri)
+
+HEADERS += cpasterplugin.h \
+ settingspage.h
+SOURCES += cpasterplugin.cpp \
+ settingspage.cpp
+FORMS += settingspage.ui \
+ pasteselect.ui
+
+include(../../../shared/cpaster/cpaster.pri)
diff --git a/src/plugins/cpaster/cpaster_dependencies.pri b/src/plugins/cpaster/cpaster_dependencies.pri
new file mode 100644
index 0000000000..5c489ae1c4
--- /dev/null
+++ b/src/plugins/cpaster/cpaster_dependencies.pri
@@ -0,0 +1,3 @@
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp
new file mode 100644
index 0000000000..ee62688f3d
--- /dev/null
+++ b/src/plugins/cpaster/cpasterplugin.cpp
@@ -0,0 +1,304 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cpasterplugin.h"
+
+#include "ui_pasteselect.h"
+
+#include "splitter.h"
+#include "view.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/itexteditor.h>
+#include <coreplugin/messageoutputwindow.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtGui/QListWidget>
+
+using namespace CodePaster;
+using namespace Core;
+using namespace TextEditor;
+
+Core::ICore *gCoreInstance = NULL;
+
+CodepasterPlugin::CodepasterPlugin()
+ : m_settingsPage(0)
+ , m_fetcher(0)
+ , m_poster(0)
+{
+}
+
+CodepasterPlugin::~CodepasterPlugin()
+{
+ if (m_settingsPage) {
+ removeObject(m_settingsPage);
+ delete m_settingsPage;
+ m_settingsPage = 0;
+ }
+}
+
+bool CodepasterPlugin::initialize(const QStringList &arguments, QString *error_message)
+{
+ Q_UNUSED(arguments);
+ Q_UNUSED(error_message);
+
+ gCoreInstance = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ // Create the globalcontext list to register actions accordingly
+ QList<int> globalcontext;
+ globalcontext << gCoreInstance->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::C_GLOBAL);
+
+ // Create the settings Page
+ m_settingsPage = new SettingsPage();
+ addObject(m_settingsPage);
+
+ //register actions
+ Core::ActionManagerInterface *actionManager = gCoreInstance->actionManager();
+
+ Core::IActionContainer *toolsContainer =
+ actionManager->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *cpContainer =
+ actionManager->createMenu(QLatin1String("CodePaster"));
+ cpContainer->menu()->setTitle(tr("&CodePaster"));
+ toolsContainer->addMenu(cpContainer);
+
+ Core::ICommand *command;
+
+ m_postAction = new QAction(tr("Paste snippet..."), this);
+ command = actionManager->registerAction(m_postAction, "CodePaster.post", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+C,Alt+P")));
+ connect(m_postAction, SIGNAL(triggered()), this, SLOT(post()));
+ cpContainer->addAction(command);
+
+ m_fetchAction = new QAction(tr("Fetch snippet..."), this);
+ command = actionManager->registerAction(m_fetchAction, "CodePaster.fetch", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+C,Alt+F")));
+ connect(m_fetchAction, SIGNAL(triggered()), this, SLOT(fetch()));
+ cpContainer->addAction(command);
+
+ return true;
+}
+
+void CodepasterPlugin::extensionsInitialized()
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+}
+
+void CodepasterPlugin::post()
+{
+ if (m_poster)
+ delete m_poster;
+ IEditor* editor = gCoreInstance->editorManager()->currentEditor();
+ ITextEditor* textEditor = qobject_cast<ITextEditor*>(editor);
+ if (!textEditor)
+ return;
+
+ QString data = textEditor->selectedText();
+ if (!data.isEmpty()) {
+ QChar *uc = data.data();
+ QChar *e = uc + data.size();
+
+ for (; uc != e; ++uc) {
+ switch (uc->unicode()) {
+ case 0xfdd0: // QTextBeginningOfFrame
+ case 0xfdd1: // QTextEndOfFrame
+ case QChar::ParagraphSeparator:
+ case QChar::LineSeparator:
+ *uc = QLatin1Char('\n');
+ break;
+ case QChar::Nbsp:
+ *uc = QLatin1Char(' ');
+ break;
+ default:
+ ;
+ }
+ }
+ } else
+ data = textEditor->contents();
+
+ FileDataList lst = splitDiffToFiles(data.toLatin1());
+ QString username = m_settingsPage->username();
+ QString description;
+ QString comment;
+
+ View view(0);
+ if (!view.show(username, description, comment, lst))
+ return; // User canceled post
+
+ username = view.getUser();
+ description = view.getDescription();
+ comment = view.getComment();
+ data = view.getContent();
+
+ // Submit to codepaster
+ m_poster = new CustomPoster(m_settingsPage->serverUrl().toString());
+
+ // Copied from cpaster. Otherwise lineendings will screw up
+ if (!data.contains("\r\n")) {
+ if (data.contains('\n'))
+ data.replace('\n', "\r\n");
+ else if (data.contains('\r'))
+ data.replace('\r', "\r\n");
+ }
+ m_poster->post(description, comment, data, username);
+}
+
+void CodepasterPlugin::fetch()
+{
+ if (m_fetcher)
+ delete m_fetcher;
+ m_fetcher = new CustomFetcher(m_settingsPage->serverUrl().toString());
+
+ QDialog dialog;
+ Ui_PasteSelectDialog ui;
+ ui.setupUi(&dialog);
+
+ ui.listWidget->addItems(QStringList() << "Waiting for items");
+ ui.listWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ ui.listWidget->setFrameStyle(QFrame::NoFrame);
+ m_fetcher->list(ui.listWidget);
+
+ int result = dialog.exec();
+ if (!result)
+ return;
+ bool ok;
+ QStringList list = ui.pasteEdit->text().split(QLatin1Char(' '));
+ int pasteID = !list.isEmpty() ? list.first().toInt(&ok) : -1;
+ if (!ok || pasteID <= 0)
+ return;
+
+ delete m_fetcher;
+ m_fetcher = new CustomFetcher(m_settingsPage->serverUrl().toString());
+ m_fetcher->fetch(pasteID);
+}
+
+CustomFetcher::CustomFetcher(const QString &host)
+ : Fetcher(host)
+ , m_host(host)
+ , m_listWidget(0)
+ , m_id(-1)
+ , m_customError(false)
+{
+ // cpaster calls QCoreApplication::exit which we want to avoid here
+ disconnect(this, SIGNAL(requestFinished(int,bool))
+ ,this, SLOT(gotRequestFinished(int,bool)));
+ connect(this, SIGNAL(requestFinished(int,bool))
+ , SLOT(customRequestFinished(int,bool)));
+}
+
+void CustomFetcher::customRequestFinished(int, bool error)
+{
+ m_customError = error;
+ if (m_customError || hadError()) {
+ QMessageBox::warning(0, QLatin1String("CodePaster Error")
+ , QLatin1String("Could not fetch code")
+ , QMessageBox::Ok);
+ return;
+ }
+
+ QByteArray data = body();
+ if (!m_listWidget) {
+ QString title = QString::fromLatin1("Code Paster: %1").arg(m_id);
+ gCoreInstance->editorManager()->newFile(Core::Constants::K_DEFAULT_TEXT_EDITOR
+ , &title, data);
+ } else {
+ m_listWidget->clear();
+ QStringList lines = QString(data).split(QLatin1Char('\n'));
+ m_listWidget->addItems(lines);
+ m_listWidget = 0;
+ }
+}
+
+int CustomFetcher::fetch(int pasteID)
+{
+ m_id = pasteID;
+ return Fetcher::fetch(pasteID);
+}
+
+void CustomFetcher::list(QListWidget* list)
+{
+ m_listWidget = list;
+ QString url = QLatin1String("http://");
+ url += m_host;
+ url += QLatin1String("/?command=browse&format=raw");
+ Fetcher::fetch(url);
+}
+
+CustomPoster::CustomPoster(const QString &host
+ , bool copyToClipboard
+ , bool displayOutput)
+ : Poster(host)
+ , m_copy(copyToClipboard)
+ , m_output(displayOutput)
+{
+ // cpaster calls QCoreApplication::exit which we want to avoid here
+ disconnect(this, SIGNAL(requestFinished(int,bool))
+ ,this, SLOT(gotRequestFinished(int,bool)));
+ connect(this, SIGNAL(requestFinished(int,bool))
+ , SLOT(customRequestFinished(int,bool)));
+}
+
+void CustomPoster::customRequestFinished(int, bool error)
+{
+ if (!error) {
+ if (m_copy)
+ QApplication::clipboard()->setText(pastedUrl());
+ gCoreInstance->messageManager()->printToOutputPane(pastedUrl(), m_output);
+ } else
+ QMessageBox::warning(0, "Code Paster Error", "Some error occured while posting", QMessageBox::Ok);
+#if 0 // Figure out how to access
+ Core::Internal::MessageOutputWindow* messageWindow =
+ ExtensionSystem::PluginManager::instance()->getObject<Core::Internal::MessageOutputWindow>();
+ if (!messageWindow)
+ qDebug() << "Pasted at:" << pastedUrl();
+
+ messageWindow->append(pastedUrl());
+ messageWindow->setFocus();
+#endif
+}
+
+Q_EXPORT_PLUGIN(CodepasterPlugin)
diff --git a/src/plugins/cpaster/cpasterplugin.h b/src/plugins/cpaster/cpasterplugin.h
new file mode 100644
index 0000000000..394dff4226
--- /dev/null
+++ b/src/plugins/cpaster/cpasterplugin.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CodepasterPlugin_H
+#define CodepasterPlugin_H
+
+#include "settingspage.h"
+#include "fetcher.h"
+#include "poster.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/icorelistener.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QListWidget;
+QT_END_NAMESPACE
+
+namespace CodePaster {
+
+class CustomFetcher;
+class CustomPoster;
+
+class CodepasterPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ CodepasterPlugin();
+ ~CodepasterPlugin();
+
+ bool initialize(const QStringList &arguments
+ , QString *error_message);
+ void extensionsInitialized();
+
+public slots:
+ void post();
+ void fetch();
+
+private:
+
+ QAction *m_postAction;
+ QAction *m_fetchAction;
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ SettingsPage *m_settingsPage;
+ CustomFetcher *m_fetcher;
+ CustomPoster *m_poster;
+};
+
+class CustomFetcher : public Fetcher
+{
+ Q_OBJECT
+public:
+ CustomFetcher(const QString &host);
+
+ int fetch(int pasteID);
+ inline bool hadCustomError() { return m_customError; }
+
+ void list(QListWidget*);
+private slots:
+ void customRequestFinished(int id, bool error);
+
+private:
+ QString m_host;
+ QListWidget *m_listWidget;
+ int m_id;
+ bool m_customError;
+};
+
+class CustomPoster : public Poster
+{
+ Q_OBJECT
+public:
+ CustomPoster(const QString &host
+ , bool copyToClipboard = true
+ , bool displayOutput = true);
+
+private slots:
+ void customRequestFinished(int id, bool error);
+private:
+ bool m_copy;
+ bool m_output;
+};
+
+} // namespace CodePaster
+
+#endif
diff --git a/src/plugins/cpaster/pasteselect.ui b/src/plugins/cpaster/pasteselect.ui
new file mode 100644
index 0000000000..6906f135b7
--- /dev/null
+++ b/src/plugins/cpaster/pasteselect.ui
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodePaster::PasteSelectDialog</class>
+ <widget class="QDialog" name="CodePaster::PasteSelectDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>451</width>
+ <height>215</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Paste:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="pasteEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QListWidget" name="listWidget"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttons">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttons</sender>
+ <signal>accepted()</signal>
+ <receiver>CodePaster::PasteSelectDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>266</x>
+ <y>205</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttons</sender>
+ <signal>rejected()</signal>
+ <receiver>CodePaster::PasteSelectDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>334</x>
+ <y>205</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>listWidget</sender>
+ <signal>currentTextChanged(QString)</signal>
+ <receiver>pasteEdit</receiver>
+ <slot>setText(QString)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>247</x>
+ <y>123</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>308</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>listWidget</sender>
+ <signal>doubleClicked(QModelIndex)</signal>
+ <receiver>CodePaster::PasteSelectDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>90</x>
+ <y>86</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>3</x>
+ <y>81</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/cpaster/settingspage.cpp b/src/plugins/cpaster/settingspage.cpp
new file mode 100644
index 0000000000..95458eb41d
--- /dev/null
+++ b/src/plugins/cpaster/settingspage.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QSettings>
+#include <QtGui/QLineEdit>
+#include <QtGui/QFileDialog>
+#include <QtCore/QDebug>
+#include <QtCore/QVariant>
+
+using namespace CodePaster;
+
+SettingsPage::SettingsPage()
+{
+ Core::ICore *coreIFace = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (coreIFace)
+ m_settings = coreIFace->settings();
+
+ if (m_settings) {
+ m_settings->beginGroup("CodePaster");
+ m_username = m_settings->value("UserName", qgetenv("USER")).toString();
+ m_server = m_settings->value("Server", "<no url>").toUrl();
+ m_copy = m_settings->value("CopyToClipboard", true).toBool();
+ m_output = m_settings->value("DisplayOutput", true).toBool();
+ m_settings->endGroup();
+ }
+}
+
+QString SettingsPage::name() const
+{
+ return "General";
+}
+
+QString SettingsPage::category() const
+{
+ return "CodePaster";
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("CodePaster");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+ m_ui.userEdit->setText(m_username);
+ m_ui.serverEdit->setText(m_server.toString());
+ m_ui.clipboardBox->setChecked(m_copy);
+ m_ui.displayBox->setChecked(m_output);
+ return w;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_username = m_ui.userEdit->text();
+ m_server = QUrl(m_ui.serverEdit->text());
+ m_copy = m_ui.clipboardBox->isChecked();
+ m_output = m_ui.displayBox->isChecked();
+
+ if (!m_settings)
+ return;
+
+ m_settings->beginGroup("CodePaster");
+ m_settings->setValue("UserName", m_username);
+ m_settings->setValue("Server", m_server);
+ m_settings->setValue("CopyToClipboard", m_copy);
+ m_settings->setValue("DisplayOutput", m_output);
+ m_settings->endGroup();
+}
+
+QString SettingsPage::username() const
+{
+ return m_username;
+}
+
+QUrl SettingsPage::serverUrl() const
+{
+ return m_server;
+}
diff --git a/src/plugins/cpaster/settingspage.h b/src/plugins/cpaster/settingspage.h
new file mode 100644
index 0000000000..f80b290461
--- /dev/null
+++ b/src/plugins/cpaster/settingspage.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSPAGE_H
+#define SETTINGSPAGE_H
+
+#include <QtCore/QUrl>
+#include <QtGui/QWidget>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_settingspage.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace CodePaster {
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget* createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ QString username() const;
+ QUrl serverUrl() const;
+
+ bool copyToClipBoard() const;
+ bool displayOutput() const;
+
+private:
+ Ui_SettingsPage m_ui;
+ QSettings *m_settings;
+
+ QString m_username;
+ QUrl m_server;
+ bool m_copy;
+ bool m_output;
+};
+
+} //namespace CodePaster
+
+#endif
diff --git a/src/plugins/cpaster/settingspage.ui b/src/plugins/cpaster/settingspage.ui
new file mode 100644
index 0000000000..0a085c75bc
--- /dev/null
+++ b/src/plugins/cpaster/settingspage.ui
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodePaster::SettingsPage</class>
+ <widget class="QWidget" name="CodePaster::SettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>341</width>
+ <height>258</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>CodePaster Server:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="serverEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="userEdit"/>
+ </item>
+ <item row="2" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="clipboardBox">
+ <property name="text">
+ <string>Copy Paste URL to clipboard</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="displayBox">
+ <property name="text">
+ <string>Display Output Pane after sending a post</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>223</width>
+ <height>100</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/cppeditor/CppEditor.mimetypes.xml b/src/plugins/cppeditor/CppEditor.mimetypes.xml
new file mode 100644
index 0000000000..cd79d5f441
--- /dev/null
+++ b/src/plugins/cppeditor/CppEditor.mimetypes.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="text/x-csrc">
+ <sub-class-of type="text/plain"/>
+ <comment>C Source file</comment>
+ <comment xml:lang="bg">Изходен код на C</comment>
+ <comment xml:lang="ca">codi font en C</comment>
+ <comment xml:lang="cs">Zdrojový kód v C</comment>
+ <comment xml:lang="cy">Ffynhonnell Rhaglen C</comment>
+ <comment xml:lang="da">C-kildekode</comment>
+ <comment xml:lang="de">C-Quelltext</comment>
+ <comment xml:lang="el">πηγαίος κώδικας C</comment>
+ <comment xml:lang="eo">C-fontkodo</comment>
+ <comment xml:lang="es">código fuente en C</comment>
+ <comment xml:lang="eu">C iturburu-kodea</comment>
+ <comment xml:lang="fi">C-lähdekoodi</comment>
+ <comment xml:lang="fr">code source C</comment>
+ <comment xml:lang="hu">C-forráskód</comment>
+ <comment xml:lang="it">Codice sorgente C</comment>
+ <comment xml:lang="ja">C ソースコード</comment>
+ <comment xml:lang="ko">C 소스 코드</comment>
+ <comment xml:lang="lt">C pradinis kodas</comment>
+ <comment xml:lang="ms">Kod sumber C</comment>
+ <comment xml:lang="nb">C-kildekode</comment>
+ <comment xml:lang="nl">C-broncode</comment>
+ <comment xml:lang="nn">C-kjeldekode</comment>
+ <comment xml:lang="pl">Kod źródłowy w C</comment>
+ <comment xml:lang="pt">código fonte C</comment>
+ <comment xml:lang="pt_BR">Código fonte C</comment>
+ <comment xml:lang="ru">программа на Ñзыке C</comment>
+ <comment xml:lang="sq">Kod burues C</comment>
+ <comment xml:lang="sr">C изворни ко̂д</comment>
+ <comment xml:lang="sv">C-källkod</comment>
+ <comment xml:lang="uk">Вихідний код на мові C</comment>
+ <comment xml:lang="zh_CN">C æºä»£ç </comment>
+ <comment xml:lang="zh_TW">C æºä»£ç¢¼</comment>
+ <glob pattern="*.c"/>
+ </mime-type>
+
+ <!-- A C Header file is virtually undistinguishable from the C++ header -->
+ <mime-type type="text/x-chdr">
+ <sub-class-of type="text/x-csrc"/>
+ <comment>C Header file</comment>
+ <comment xml:lang="bg">Заглавен файл на C</comment>
+ <comment xml:lang="cs">HlaviÄka v C</comment>
+ <comment xml:lang="de">C-Header</comment>
+ <comment xml:lang="es">cabecera de código fuente en C</comment>
+ <comment xml:lang="eu">C goiburua</comment>
+ <comment xml:lang="fi">C-otsake</comment>
+ <comment xml:lang="fr">en-tête C</comment>
+ <comment xml:lang="hu">C fejléc</comment>
+ <comment xml:lang="it">Header C</comment>
+ <comment xml:lang="ko">C í—¤ë”</comment>
+ <comment xml:lang="nb">C-kildekodeheader</comment>
+ <comment xml:lang="nn">C-hovud</comment>
+ <comment xml:lang="pl">Plik nagłówkowy w C</comment>
+ <comment xml:lang="sv">C-huvud</comment>
+ <comment xml:lang="uk">Файл заголовків на C</comment>
+ <glob pattern="*.h"/>
+ </mime-type>
+
+ <!-- Those are used to find matching headers by the CppTools plugin,
+ so, they should match -->
+ <mime-type type="text/x-c++hdr">
+ <sub-class-of type="text/x-chdr"/>
+ <comment>C++ Header file</comment>
+ <comment>C++ header</comment>
+ <comment xml:lang="bg">Заглавен файл на C++</comment>
+ <comment xml:lang="cs">HlaviÄka v C++</comment>
+ <comment xml:lang="de">C++-Header</comment>
+ <comment xml:lang="es">cabecera de código fuente en C++</comment>
+ <comment xml:lang="eu">C++ goiburua</comment>
+ <comment xml:lang="fi">C++-otsake</comment>
+ <comment xml:lang="fr">en-tête C++</comment>
+ <comment xml:lang="hu">C++ fejléc</comment>
+ <comment xml:lang="it">Header C++</comment>
+ <comment xml:lang="nb">C++-kildekodeheader</comment>
+ <comment xml:lang="nn">C++-hovud</comment>
+ <comment xml:lang="pl">Plik nagłówkowy w C++</comment>
+ <comment xml:lang="sv">C++-huvud</comment>
+ <comment xml:lang="uk">Файл заголовків на C++</comment>
+ <glob pattern="*.h"/>
+ <glob pattern="*.hh"/>
+ <glob pattern="*.hxx"/>
+ <glob pattern="*.h++"/>
+ <glob pattern="*.H"/>
+ <glob pattern="*.hpp"/>
+ <glob pattern="*.hp"/>
+ <!-- Find include guards of header files without extension, for
+ example, STL ones like <string> -->
+ <magic priority="50">
+ <match value="#ifndef" type="string" offset="0:1000"/>
+ </magic>
+ </mime-type>
+
+ <mime-type type="text/x-c++src">
+ <comment>C++ Source file</comment>
+ <sub-class-of type="text/x-csrc"/>
+ <comment>C++ source code</comment>
+ <comment xml:lang="bg">Изходен код на C++</comment>
+ <comment xml:lang="ca">codi font en C++</comment>
+ <comment xml:lang="cs">Zdrojový kód v C++</comment>
+ <comment xml:lang="cy">Ffynhonnell Rhaglen C++</comment>
+ <comment xml:lang="da">C++-kildekode</comment>
+ <comment xml:lang="de">C++-Quelltext</comment>
+ <comment xml:lang="el">πηγαίος κώδικας C++</comment>
+ <comment xml:lang="eo">C++-fontkodo</comment>
+ <comment xml:lang="es">código fuente en C++</comment>
+ <comment xml:lang="eu">C++ iturburu-kodea</comment>
+ <comment xml:lang="fi">C++-lähdekoodi</comment>
+ <comment xml:lang="fr">code source C++</comment>
+ <comment xml:lang="hu">C++-forráskód</comment>
+ <comment xml:lang="it">Codice sorgente C++</comment>
+ <comment xml:lang="ja">C++ ソースコード</comment>
+ <comment xml:lang="ko">C++ 소스 코드</comment>
+ <comment xml:lang="lt">C++ pradinis kodas</comment>
+ <comment xml:lang="ms">Kod sumber C++</comment>
+ <comment xml:lang="nb">C++-kildekode</comment>
+ <comment xml:lang="nl">C++-broncode</comment>
+ <comment xml:lang="nn">C++-kjeldekode</comment>
+ <comment xml:lang="pl">Kod źródłowy w C++</comment>
+ <comment xml:lang="pt">código fonte C++</comment>
+ <comment xml:lang="pt_BR">Código fonte C++</comment>
+ <comment xml:lang="ru">программа на Ñзыке C++</comment>
+ <comment xml:lang="sq">Kod burues C++</comment>
+ <comment xml:lang="sr">C++ изворни ко̂д</comment>
+ <comment xml:lang="sv">C++-källkod</comment>
+ <comment xml:lang="uk">Вихідний код на мові C++</comment>
+ <comment xml:lang="zh_CN">C++ æºä»£ç </comment>
+ <comment xml:lang="zh_TW">C++ æºä»£ç¢¼</comment>
+ <glob pattern="*.cpp"/>
+ <glob pattern="*.cc"/>
+ <glob pattern="*.cxx"/>
+ <glob pattern="*.c++"/>
+ <glob pattern="*.C"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/cppeditor/CppEditor.pluginspec b/src/plugins/cppeditor/CppEditor.pluginspec
new file mode 100644
index 0000000000..119f0461a6
--- /dev/null
+++ b/src/plugins/cppeditor/CppEditor.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="CppEditor" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>C/C++ editor component.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="CppTools" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/cppeditor/CppEditor.qwp b/src/plugins/cppeditor/CppEditor.qwp
new file mode 100644
index 0000000000..6b921e9d07
--- /dev/null
+++ b/src/plugins/cppeditor/CppEditor.qwp
@@ -0,0 +1,23 @@
+<!DOCTYPE QtWorkbenchManifest>
+<qwp>
+ <pluginName>CppEditor</pluginName>
+ <author>Trolltech</author>
+ <requiredPluginList>
+ <requiredPlugin>
+ <name>TextEditor</name>
+ <provider></provider>
+ </requiredPlugin>
+ <requiredPlugin>
+ <name>Find</name>
+ <provider></provider>
+ </requiredPlugin>
+ </requiredPluginList>
+ <extendsInterfaceList>
+ <extendsInterface>
+ <name>Core::OptionsPageInterface</name>
+ </extendsInterface>
+ <extendsInterface>
+ <name>Core::WizardInterface</name>
+ </extendsInterface>
+ </extendsInterfaceList>
+</qwp>
diff --git a/src/plugins/cppeditor/CppEditor.tpa b/src/plugins/cppeditor/CppEditor.tpa
new file mode 100644
index 0000000000..17e530152a
--- /dev/null
+++ b/src/plugins/cppeditor/CppEditor.tpa
@@ -0,0 +1,16 @@
+<tpa>
+ <pluginName>CppEditor</pluginName>
+ <author>Trolltech AS</author>
+ <version>1.0</version>
+ <extendsInterfaceList>
+ <extendsInterface>
+ <name>EditorFactoryInterface</name>
+ </extendsInterface>
+ <extendsInterface>
+ <name>WizardInterface</name>
+ </extendsInterface>
+ <extendsInterface>
+ <name>OptionsPageInterface</name>
+ </extendsInterface>
+ </extendsInterfaceList>
+</tpa>
diff --git a/src/plugins/cppeditor/cppclasswizard.cpp b/src/plugins/cppeditor/cppclasswizard.cpp
new file mode 100644
index 0000000000..90fa126727
--- /dev/null
+++ b/src/plugins/cppeditor/cppclasswizard.cpp
@@ -0,0 +1,232 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppclasswizard.h"
+#include "cppeditorconstants.h"
+
+#include <utils/codegeneration.h>
+#include <utils/newclasswidget.h>
+
+#include <QtCore/QTextStream>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtGui/QComboBox>
+#include <QtGui/QCheckBox>
+#include <QtGui/QLabel>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QWizard>
+
+using namespace CppEditor;
+using namespace CppEditor::Internal;
+
+
+// ========= ClassNamePage =========
+
+ClassNamePage::ClassNamePage(const QString &sourceSuffix,
+ const QString &headerSuffix,
+ QWidget *parent) :
+ QWizardPage(parent),
+ m_isValid(false)
+{
+ setTitle(tr("Enter class name"));
+ setSubTitle(tr("The header and source file names will be derived from the class name"));
+
+ m_newClassWidget = new Core::Utils::NewClassWidget;
+ // Order, set extensions first before suggested name is derived
+ m_newClassWidget->setHeaderExtension(headerSuffix);
+ m_newClassWidget->setSourceExtension(sourceSuffix);
+ m_newClassWidget->setBaseClassInputVisible(true);
+ m_newClassWidget->setBaseClassChoices(QStringList() << QString()
+ << QLatin1String("QObject")
+ << QLatin1String("QWidget")
+ << QLatin1String("QMainWindow"));
+ m_newClassWidget->setBaseClassEditable(true);
+ m_newClassWidget->setFormInputVisible(false);
+ m_newClassWidget->setNamespacesEnabled(true);
+
+ connect(m_newClassWidget, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+
+ QVBoxLayout *pageLayout = new QVBoxLayout(this);
+ pageLayout->addWidget(m_newClassWidget);
+}
+
+void ClassNamePage::slotValidChanged()
+{
+ const bool validNow = m_newClassWidget->isValid();
+ if (m_isValid != validNow) {
+ m_isValid = validNow;
+ emit completeChanged();
+ }
+}
+
+CppClassWizardDialog::CppClassWizardDialog(const QString &sourceSuffix,
+ const QString &headerSuffix,
+ QWidget *parent) :
+ QWizard(parent),
+ m_classNamePage(new ClassNamePage(sourceSuffix, headerSuffix, this))
+{
+ Core::BaseFileWizard::setupWizard(this);
+ setWindowTitle(tr("C++ Class Wizard"));
+ addPage(m_classNamePage);
+}
+
+void CppClassWizardDialog::setPath(const QString &path)
+{
+ m_classNamePage->newClassWidget()->setPath(path);
+}
+
+CppClassWizardParameters CppClassWizardDialog::parameters() const
+{
+ CppClassWizardParameters rc;
+ const Core::Utils::NewClassWidget *ncw = m_classNamePage->newClassWidget();
+ rc.className = ncw->className();
+ rc.headerFile = ncw->headerFileName();
+ rc.sourceFile = ncw->sourceFileName();
+ rc.baseClass = ncw->baseClassName();
+ rc.path = ncw->path();
+ return rc;
+}
+
+// ========= CppClassWizard =========
+
+CppClassWizard::CppClassWizard(const Core::BaseFileWizardParameters &parameters,
+ Core::ICore *core, QObject *parent) :
+ Core::BaseFileWizard(parameters, core, parent)
+{
+}
+
+QString CppClassWizard::sourceSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::CPP_SOURCE_MIMETYPE));
+}
+
+QString CppClassWizard::headerSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::CPP_HEADER_MIMETYPE));
+}
+
+QWizard *CppClassWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ CppClassWizardDialog *wizard = new CppClassWizardDialog(sourceSuffix(), headerSuffix(), parent);
+ foreach (QWizardPage *p, extensionPages)
+ wizard->addPage(p);
+ wizard->setPath(defaultPath);
+ return wizard;
+}
+
+Core::GeneratedFiles CppClassWizard::generateFiles(const QWizard *w, QString *errorMessage) const
+{
+ const CppClassWizardDialog *wizard = qobject_cast<const CppClassWizardDialog *>(w);
+ const CppClassWizardParameters params = wizard->parameters();
+
+ const QString sourceFileName = Core::BaseFileWizard::buildFileName(params.path, params.sourceFile, sourceSuffix());
+ const QString headerFileName = Core::BaseFileWizard::buildFileName(params.path, params.headerFile, headerSuffix());
+
+ Core::GeneratedFile sourceFile(sourceFileName);
+ sourceFile.setEditorKind(QLatin1String(Constants::CPPEDITOR_KIND));
+
+ Core::GeneratedFile headerFile(headerFileName);
+ headerFile.setEditorKind(QLatin1String(Constants::CPPEDITOR_KIND));
+
+ QString header, source;
+ if (!generateHeaderAndSource(params, &header, &source)) {
+ *errorMessage = tr("Error while generating file contents.");
+ return Core::GeneratedFiles();
+ }
+ headerFile.setContents(header);
+ sourceFile.setContents(source);
+ return Core::GeneratedFiles() << headerFile << sourceFile;
+}
+
+
+bool CppClassWizard::generateHeaderAndSource(const CppClassWizardParameters &params,
+ QString *header, QString *source)
+{
+ // TODO:
+ // Quite a bit of this code has been copied from FormClassWizardParameters::generateCpp.
+ // Maybe more of it could be merged into Core::Utils.
+
+ const QString indent = QString(4, QLatin1Char(' '));
+
+ // Do we have namespaces?
+ QStringList namespaceList = params.className.split(QLatin1String("::"));
+ if (namespaceList.empty()) // Paranoia!
+ return false;
+
+ const QString unqualifiedClassName = namespaceList.takeLast();
+ const QString guard = Core::Utils::headerGuard(unqualifiedClassName);
+
+ // == Header file ==
+ QTextStream headerStr(header);
+ headerStr << "#ifndef " << guard
+ << "\n#define " << guard << '\n' << '\n';
+
+ const QRegExp qtClassExpr(QLatin1String("^Q[A-Z3].+"));
+ Q_ASSERT(qtClassExpr.isValid());
+ const bool superIsQtClass = qtClassExpr.exactMatch(params.baseClass);
+ if (superIsQtClass) {
+ Core::Utils::writeIncludeFileDirective(params.baseClass, true, headerStr);
+ headerStr << '\n';
+ }
+
+ const QString namespaceIndent = Core::Utils::writeOpeningNameSpaces(namespaceList, 0, headerStr);
+
+ // Class declaration
+ headerStr << namespaceIndent << "class " << unqualifiedClassName;
+ if (!params.baseClass.isEmpty())
+ headerStr << " : public " << params.baseClass << "\n";
+ else
+ headerStr << "\n";
+ headerStr << namespaceIndent << "{\n";
+ headerStr << namespaceIndent << "public:\n"
+ << namespaceIndent << indent << unqualifiedClassName << "();\n";
+ headerStr << namespaceIndent << "};\n\n";
+
+ Core::Utils::writeClosingNameSpaces(namespaceList, 0, headerStr);
+ headerStr << "#endif // "<< guard << '\n';
+
+
+ // == Source file ==
+ QTextStream sourceStr(source);
+ Core::Utils::writeIncludeFileDirective(params.headerFile, false, sourceStr);
+ Core::Utils::writeOpeningNameSpaces(namespaceList, 0, sourceStr);
+
+ // Constructor
+ sourceStr << '\n' << namespaceIndent << unqualifiedClassName << "::" << unqualifiedClassName << "()\n";
+ sourceStr << namespaceIndent << "{\n" << namespaceIndent << "}\n";
+
+ Core::Utils::writeClosingNameSpaces(namespaceList, indent, sourceStr);
+ return true;
+}
diff --git a/src/plugins/cppeditor/cppclasswizard.h b/src/plugins/cppeditor/cppclasswizard.h
new file mode 100644
index 0000000000..6f2055efd7
--- /dev/null
+++ b/src/plugins/cppeditor/cppclasswizard.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPCLASSWIZARD_H
+#define CPPCLASSWIZARD_H
+
+#include <coreplugin/basefilewizard.h>
+
+#include <QtCore/QStringList>
+#include <QtGui/QWizardPage>
+#include <QtGui/QWizard>
+
+QT_BEGIN_NAMESPACE
+class QCheckBox;
+class QComboBox;
+QT_END_NAMESPACE
+
+namespace Core {
+ namespace Utils {
+ class NewClassWidget;
+ }
+}
+
+namespace CppEditor {
+namespace Internal {
+
+class ClassNamePage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ ClassNamePage(const QString &sourceSuffix,
+ const QString &headerSuffix,
+ QWidget *parent = 0);
+
+ bool isComplete() const { return m_isValid; }
+ Core::Utils::NewClassWidget *newClassWidget() const { return m_newClassWidget; }
+
+private slots:
+ void slotValidChanged();
+
+private:
+ Core::Utils::NewClassWidget *m_newClassWidget;
+ bool m_isValid;
+};
+
+
+struct CppClassWizardParameters {
+ QString className;
+ QString headerFile;
+ QString sourceFile;
+ QString baseClass;
+ QString path;
+};
+
+class CppClassWizardDialog : public QWizard {
+ Q_DISABLE_COPY(CppClassWizardDialog)
+ Q_OBJECT
+public:
+ explicit CppClassWizardDialog(const QString &sourceSuffix,
+ const QString &headerSuffix,
+ QWidget *parent = 0);
+
+ void setPath(const QString &path);
+ CppClassWizardParameters parameters() const;
+
+private:
+ ClassNamePage *m_classNamePage;
+};
+
+
+class CppClassWizard : public Core::BaseFileWizard
+{
+ Q_OBJECT
+public:
+ explicit CppClassWizard(const Core::BaseFileWizardParameters &parameters,
+ Core::ICore *core, QObject *parent = 0);
+
+protected:
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+
+
+ virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+ QString sourceSuffix() const;
+ QString headerSuffix() const;
+
+private:
+ static bool generateHeaderAndSource(const CppClassWizardParameters &params,
+ QString *header, QString *source);
+
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPCLASSWIZARD_H
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
new file mode 100644
index 0000000000..708d825426
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -0,0 +1,815 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppeditor.h"
+#include "cppeditorconstants.h"
+#include "cppplugin.h"
+#include "cpphighlighter.h"
+
+#include <AST.h>
+#include <Token.h>
+#include <Scope.h>
+#include <Symbols.h>
+#include <Names.h>
+#include <Control.h>
+#include <CoreTypes.h>
+#include <Literals.h>
+#include <Semantic.h>
+#include <cplusplus/ExpressionUnderCursor.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/OverviewModel.h>
+#include <cplusplus/SimpleLexer.h>
+#include <cplusplus/TypeOfExpression.h>
+#include <cpptools/cppmodelmanagerinterface.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <texteditor/basetextdocument.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorconstants.h>
+#include <texteditor/textblockiterator.h>
+#include <indenter.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <QtCore/QTime>
+#include <QtCore/QTimer>
+#include <QtGui/QAction>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLayout>
+#include <QtGui/QMenu>
+#include <QtGui/QShortcut>
+#include <QtGui/QTextEdit>
+#include <QtGui/QComboBox>
+#include <QtGui/QTreeView>
+#include <QtGui/QHeaderView>
+
+using namespace CPlusPlus;
+using namespace CppEditor::Internal;
+
+namespace {
+
+class OverviewTreeView : public QTreeView
+{
+public:
+ OverviewTreeView(QWidget *parent = 0)
+ : QTreeView(parent)
+ {
+ // TODO: Disable the root for all items (with a custom delegate?)
+ setRootIsDecorated(false);
+ }
+
+ void sync()
+ {
+ expandAll();
+ setMinimumWidth(qMax(sizeHintForColumn(0), minimumSizeHint().width()));
+ }
+};
+
+} // end of anonymous namespace
+
+QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context)
+{
+ Name *symbolName = s->name();
+ if (! symbolName)
+ return 0; // nothing to do.
+
+ QVector<Name *> names;
+
+ for (Scope *scope = s->scope(); scope; scope = scope->enclosingScope()) {
+ if (scope->isClassScope() || scope->isNamespaceScope()) {
+ if (scope->owner() && scope->owner()->name()) {
+ Name *ownerName = scope->owner()->name();
+ if (QualifiedNameId *q = ownerName->asQualifiedNameId()) {
+ for (unsigned i = 0; i < q->nameCount(); ++i) {
+ names.prepend(q->nameAt(i));
+ }
+ } else {
+ names.prepend(ownerName);
+ }
+ }
+ }
+ }
+
+ if (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)
+{
+ Core::ICore *core = CppPlugin::core();
+ m_context << core->uniqueIDManager()->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
+ m_context << core->uniqueIDManager()->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
+ m_context << core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+}
+
+CPPEditor::CPPEditor(QWidget *parent) :
+ TextEditor::BaseTextEditor(parent),
+ m_core(CppPlugin::core())
+{
+ setParenthesesMatchingEnabled(true);
+ setMarksVisible(true);
+ setCodeFoldingVisible(true);
+ baseTextDocument()->setSyntaxHighlighter(new CPPHighlighter);
+// new QShortcut(QKeySequence("Ctrl+Alt+M"), this, SLOT(foo()), 0, Qt::WidgetShortcut);
+
+#ifdef WITH_TOKEN_MOVE_POSITION
+ new QShortcut(QKeySequence::MoveToPreviousWord, this, SLOT(moveToPreviousToken()),
+ /*ambiguousMember=*/ 0, Qt::WidgetShortcut);
+
+ new QShortcut(QKeySequence::MoveToNextWord, this, SLOT(moveToNextToken()),
+ /*ambiguousMember=*/ 0, Qt::WidgetShortcut);
+
+ new QShortcut(QKeySequence::DeleteStartOfWord, this, SLOT(deleteStartOfToken()),
+ /*ambiguousMember=*/ 0, Qt::WidgetShortcut);
+
+ new QShortcut(QKeySequence::DeleteEndOfWord, this, SLOT(deleteEndOfToken()),
+ /*ambiguousMember=*/ 0, Qt::WidgetShortcut);
+#endif
+
+ m_modelManager = m_core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
+
+ if (m_modelManager) {
+ connect(m_modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
+ this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
+ }
+}
+
+CPPEditor::~CPPEditor()
+{
+}
+
+TextEditor::BaseTextEditorEditable *CPPEditor::createEditableInterface()
+{
+ CPPEditorEditable *editable = new CPPEditorEditable(this);
+ createToolBar(editable);
+ return editable;
+}
+
+void CPPEditor::createToolBar(CPPEditorEditable *editable)
+{
+ m_methodCombo = new QComboBox;
+ m_methodCombo->setMinimumContentsLength(22);
+ m_methodCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ QTreeView *methodView = new OverviewTreeView();
+ methodView->header()->hide();
+ methodView->setItemsExpandable(false);
+ m_methodCombo->setView(methodView);
+ m_methodCombo->setMaxVisibleItems(20);
+
+ m_overviewModel = new OverviewModel(this);
+ m_methodCombo->setModel(m_overviewModel);
+
+ connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int)));
+ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex()));
+
+ connect(file(), SIGNAL(changed()), this, SLOT(updateFileName()));
+
+ QToolBar *toolBar = editable->toolBar();
+ QList<QAction*> actions = toolBar->actions();
+ toolBar->insertWidget(actions.first(), m_methodCombo);
+}
+
+int CPPEditor::previousBlockState(QTextBlock block) const
+{
+ block = block.previous();
+ if (block.isValid()) {
+ int state = block.userState();
+
+ if (state != -1)
+ return state;
+ }
+ return 0;
+}
+
+QTextCursor CPPEditor::moveToPreviousToken(QTextCursor::MoveMode mode) const
+{
+ SimpleLexer tokenize;
+ QTextCursor c(textCursor());
+ QTextBlock block = c.block();
+ int column = c.columnNumber();
+
+ for (; block.isValid(); block = block.previous()) {
+ const QString textBlock = block.text();
+ QList<SimpleToken> tokens = tokenize(textBlock, previousBlockState(block));
+
+ if (! tokens.isEmpty()) {
+ tokens.prepend(SimpleToken());
+
+ for (int index = tokens.size() - 1; index != -1; --index) {
+ const SimpleToken &tk = tokens.at(index);
+ if (tk.position() < column) {
+ c.setPosition(block.position() + tk.position(), mode);
+ return c;
+ }
+ }
+ }
+
+ column = INT_MAX;
+ }
+
+ c.movePosition(QTextCursor::Start, mode);
+ return c;
+}
+
+QTextCursor CPPEditor::moveToNextToken(QTextCursor::MoveMode mode) const
+{
+ SimpleLexer tokenize;
+ QTextCursor c(textCursor());
+ QTextBlock block = c.block();
+ int column = c.columnNumber();
+
+ for (; block.isValid(); block = block.next()) {
+ const QString textBlock = block.text();
+ QList<SimpleToken> tokens = tokenize(textBlock, previousBlockState(block));
+
+ if (! tokens.isEmpty()) {
+ for (int index = 0; index < tokens.size(); ++index) {
+ const SimpleToken &tk = tokens.at(index);
+ if (tk.position() > column) {
+ c.setPosition(block.position() + tk.position(), mode);
+ return c;
+ }
+ }
+ }
+
+ column = -1;
+ }
+
+ c.movePosition(QTextCursor::End, mode);
+ return c;
+}
+
+void CPPEditor::moveToPreviousToken()
+{
+ setTextCursor(moveToPreviousToken(QTextCursor::MoveAnchor));
+}
+
+void CPPEditor::moveToNextToken()
+{
+ setTextCursor(moveToNextToken(QTextCursor::MoveAnchor));
+}
+
+void CPPEditor::deleteStartOfToken()
+{
+ QTextCursor c = moveToPreviousToken(QTextCursor::KeepAnchor);
+ c.removeSelectedText();
+ setTextCursor(c);
+}
+
+void CPPEditor::deleteEndOfToken()
+{
+ QTextCursor c = moveToNextToken(QTextCursor::KeepAnchor);
+ c.removeSelectedText();
+ setTextCursor(c);
+}
+
+void CPPEditor::onDocumentUpdated(Document::Ptr doc)
+{
+ if (doc->fileName() != file()->fileName())
+ return;
+
+ m_overviewModel->rebuild(doc);
+ OverviewTreeView *treeView = static_cast<OverviewTreeView *>(m_methodCombo->view());
+ treeView->sync();
+ updateMethodBoxIndex();
+}
+
+void CPPEditor::updateFileName()
+{ }
+
+void CPPEditor::jumpToMethod(int)
+{
+ QModelIndex index = m_methodCombo->view()->currentIndex();
+ Symbol *symbol = m_overviewModel->symbolFromIndex(index);
+ if (! symbol)
+ return;
+
+ m_core->editorManager()->addCurrentPositionToNavigationHistory(true);
+ int line = symbol->line();
+ gotoLine(line);
+ m_core->editorManager()->addCurrentPositionToNavigationHistory();
+ setFocus();
+}
+
+void CPPEditor::updateMethodBoxIndex()
+{
+ int line = 0, column = 0;
+ convertPosition(position(), &line, &column);
+
+ QModelIndex lastIndex;
+
+ const int rc = m_overviewModel->rowCount(QModelIndex());
+ for (int row = 0; row < rc; ++row) {
+ const QModelIndex index = m_overviewModel->index(row, 0, QModelIndex());
+ Symbol *symbol = m_overviewModel->symbolFromIndex(index);
+ if (symbol->line() > unsigned(line))
+ break;
+ lastIndex = index;
+ }
+
+ if (lastIndex.isValid()) {
+ bool blocked = m_methodCombo->blockSignals(true);
+ m_methodCombo->setCurrentIndex(lastIndex.row());
+ (void) m_methodCombo->blockSignals(blocked);
+ }
+}
+
+static bool isCompatible(Name *name, Name *otherName)
+{
+ if (NameId *nameId = name->asNameId()) {
+ if (TemplateNameId *otherTemplId = otherName->asTemplateNameId())
+ return nameId->identifier()->isEqualTo(otherTemplId->identifier());
+ } else if (TemplateNameId *templId = name->asTemplateNameId()) {
+ if (NameId *otherNameId = otherName->asNameId())
+ return templId->identifier()->isEqualTo(otherNameId->identifier());
+ }
+
+ return name->isEqualTo(otherName);
+}
+
+static bool isCompatible(Function *definition, Symbol *declaration, QualifiedNameId *declarationName)
+{
+ Function *declTy = declaration->type()->asFunction();
+ if (! declTy)
+ return false;
+
+ Name *definitionName = definition->name();
+ if (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) {
+ Name *n = q->nameAt(q->nameCount() - i - 1);
+ 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)
+ return;
+
+ Document::Ptr doc = m_modelManager->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 (f) {
+ TypeOfExpression typeOfExpression;
+ typeOfExpression.setDocuments(m_modelManager->documents());
+ QList<TypeOfExpression::Result> resolvedSymbols = typeOfExpression(QString(), doc, lastSymbol);
+ const LookupContext &context = typeOfExpression.lookupContext();
+
+ QualifiedNameId *q = qualifiedNameIdForSymbol(f, context);
+ QList<Symbol *> symbols = context.resolve(q);
+
+ Symbol *declaration = 0;
+ foreach (declaration, symbols) {
+ if (isCompatible(f, declaration, q))
+ break;
+ }
+
+ if (! declaration && ! symbols.isEmpty())
+ declaration = symbols.first();
+
+ if (declaration)
+ openEditorAt(declaration);
+ } else if (lastSymbol->type()->isFunction()) {
+ if (Symbol *def = findDefinition(lastSymbol))
+ openEditorAt(def);
+ }
+}
+
+void CPPEditor::jumpToDefinition()
+{
+ if (!m_modelManager)
+ return;
+
+ // Find the last symbol up to the cursor position
+ int line = 0, column = 0;
+ convertPosition(position(), &line, &column);
+ Document::Ptr doc = m_modelManager->document(file()->fileName());
+ if (!doc)
+ return;
+ Symbol *lastSymbol = doc->findSymbolAt(line, column);
+ if (!lastSymbol)
+ return;
+
+ // Get the expression under the cursor
+ const int endOfName = endOfNameUnderCursor();
+ QTextCursor tc = textCursor();
+ tc.setPosition(endOfName);
+ ExpressionUnderCursor expressionUnderCursor;
+ const QString expression = expressionUnderCursor(tc);
+
+ // Evaluate the type of the expression
+ TypeOfExpression typeOfExpression;
+ typeOfExpression.setDocuments(m_modelManager->documents());
+ QList<TypeOfExpression::Result> resolvedSymbols =
+ typeOfExpression(expression, doc, lastSymbol);
+
+ if (!resolvedSymbols.isEmpty()) {
+ Symbol *symbol = resolvedSymbols.first().second;
+ if (symbol) {
+ Symbol *def = 0;
+ if (!lastSymbol->isFunction())
+ def = findDefinition(symbol);
+
+ if (def)
+ openEditorAt(def);
+ else
+ openEditorAt(symbol);
+
+ // This would jump to the type of a name
+#if 0
+ } else if (NamedType *namedType = firstType->asNamedType()) {
+ QList<Symbol *> candidates = context.resolve(namedType->name());
+ if (!candidates.isEmpty()) {
+ Symbol *s = candidates.takeFirst();
+ openEditorAt(s->fileName(), s->line(), s->column());
+ }
+#endif
+ }
+ } else {
+ qDebug() << "No results for expression:" << expression;
+ }
+}
+
+Symbol *CPPEditor::findDefinition(Symbol *lastSymbol)
+{
+ // Currently only functions are supported
+ if (!lastSymbol->type()->isFunction())
+ return 0;
+
+ QVector<Name *> qualifiedName;
+ Scope *scope = lastSymbol->scope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->isClassScope() || scope->isNamespaceScope()) {
+ if (scope->owner() && scope->owner()->name()) {
+ Name *scopeOwnerName = scope->owner()->name();
+ if (QualifiedNameId *q = scopeOwnerName->asQualifiedNameId()) {
+ for (unsigned i = 0; i < q->nameCount(); ++i) {
+ qualifiedName.prepend(q->nameAt(i));
+ }
+ } else {
+ qualifiedName.prepend(scopeOwnerName);
+ }
+ }
+ }
+ }
+
+ qualifiedName.append(lastSymbol->name());
+
+ Control control;
+ QualifiedNameId *q = control.qualifiedNameId(&qualifiedName[0], qualifiedName.size());
+ LookupContext context(&control);
+
+ const QMap<QString, Document::Ptr> documents = m_modelManager->documents();
+ foreach (Document::Ptr doc, documents) {
+ QList<Scope *> visibleScopes;
+ visibleScopes.append(doc->globalSymbols());
+ visibleScopes = context.expand(visibleScopes);
+ //qDebug() << "** doc:" << doc->fileName() << "visible scopes:" << visibleScopes.count();
+ foreach (Scope *visibleScope, visibleScopes) {
+ Symbol *symbol = 0;
+ if (NameId *nameId = q->unqualifiedNameId()->asNameId())
+ symbol = visibleScope->lookat(nameId->identifier());
+ else if (DestructorNameId *dtorId = q->unqualifiedNameId()->asDestructorNameId())
+ symbol = visibleScope->lookat(dtorId->identifier());
+ else if (TemplateNameId *templNameId = q->unqualifiedNameId()->asTemplateNameId())
+ symbol = visibleScope->lookat(templNameId->identifier());
+ else if (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(), lastSymbol, q))
+ continue;
+ return symbol;
+ }
+ }
+ }
+
+ return 0;
+}
+
+bool CPPEditor::isElectricCharacter(const QChar &ch) const
+{
+ if (ch == QLatin1Char('{') ||
+ ch == QLatin1Char('}') ||
+ ch == QLatin1Char('#')) {
+ return true;
+ }
+ return false;
+}
+
+// Indent a code line based on previous
+template <class Iterator>
+static void indentCPPBlock(const CPPEditor::TabSettings &ts,
+ const QTextBlock &block,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedChar)
+{
+ typedef typename SharedTools::Indenter<Iterator> Indenter;
+ Indenter &indenter = Indenter::instance();
+ indenter.setIndentSize(ts.m_indentSize);
+ indenter.setTabSize(ts.m_tabSize);
+
+ const TextEditor::TextBlockIterator current(block);
+ const int indent = indenter.indentForBottomLine(current, programBegin, programEnd, typedChar);
+ ts.indentLine(block, indent);
+}
+
+void CPPEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+{
+ const TextEditor::TextBlockIterator begin(doc->begin());
+ const TextEditor::TextBlockIterator end(block.next());
+
+ indentCPPBlock(tabSettings(), block, begin, end, typedChar);
+}
+
+void CPPEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+ QMenu *menu = createStandardContextMenu();
+
+ // Remove insert unicode control character
+ QAction *lastAction = menu->actions().last();
+ if (lastAction->menu() && QLatin1String(lastAction->menu()->metaObject()->className()) == QLatin1String("QUnicodeControlCharacterMenu"))
+ menu->removeAction(lastAction);
+
+ Core::IActionContainer *mcontext =
+ m_core->actionManager()->actionContainer(CppEditor::Constants::M_CONTEXT);
+ QMenu *contextMenu = mcontext->menu();
+
+ foreach (QAction *action, contextMenu->actions())
+ menu->addAction(action);
+
+ menu->exec(e->globalPos());
+ delete menu;
+}
+
+QList<int> CPPEditorEditable::context() const
+{
+ return m_context;
+}
+
+Core::IEditor *CPPEditorEditable::duplicate(QWidget *parent)
+{
+ CPPEditor *newEditor = new CPPEditor(parent);
+ newEditor->duplicateFrom(editor());
+ CppPlugin::instance()->initializeEditor(newEditor);
+ return newEditor->editableInterface();
+}
+
+const char *CPPEditorEditable::kind() const
+{
+ return CppEditor::Constants::CPPEDITOR_KIND;
+}
+
+void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ TextEditor::BaseTextEditor::setFontSettings(fs);
+ CPPHighlighter *highlighter = qobject_cast<CPPHighlighter*>(baseTextDocument()->syntaxHighlighter());
+ if (!highlighter)
+ return;
+
+ static QVector<QString> categories;
+ if (categories.isEmpty()) {
+ categories << QLatin1String(TextEditor::Constants::C_NUMBER)
+ << QLatin1String(TextEditor::Constants::C_STRING)
+ << QLatin1String(TextEditor::Constants::C_TYPE)
+ << QLatin1String(TextEditor::Constants::C_KEYWORD)
+ << QLatin1String(TextEditor::Constants::C_OPERATOR)
+ << QLatin1String(TextEditor::Constants::C_PREPROCESSOR)
+ << QLatin1String(TextEditor::Constants::C_LABEL)
+ << QLatin1String(TextEditor::Constants::C_COMMENT);
+ }
+
+ const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
+ highlighter->setFormats(formats.constBegin(), formats.constEnd());
+ highlighter->rehighlight();
+}
+
+
+void CPPEditor::unCommentSelection()
+{
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+
+ int pos = cursor.position();
+ int anchor = cursor.anchor();
+ int start = qMin(anchor, pos);
+ int end = qMax(anchor, pos);
+ bool anchorIsStart = (anchor == start);
+
+ QTextBlock startBlock = document()->findBlock(start);
+ QTextBlock endBlock = document()->findBlock(end);
+
+ if (end > start && endBlock.position() == end) {
+ --end;
+ endBlock = endBlock.previous();
+ }
+
+ bool doCStyleUncomment = false;
+ bool doCStyleComment = false;
+ bool doCppStyleUncomment = false;
+
+ bool hasSelection = cursor.hasSelection();
+
+ if (hasSelection) {
+ QString startText = startBlock.text();
+ int startPos = start - startBlock.position();
+ 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() - 2
+ && startText.at(startPos) == QLatin1Char('/')
+ && startText.at(startPos+1) == QLatin1Char('*'));
+
+
+ QString endText = endBlock.text();
+ int endPos = end - endBlock.position();
+ bool hasTrailingCharacters = !endText.mid(endPos).trimmed().isEmpty();
+ if ((endPos <= endText.length() - 2
+ && endText.at(endPos) == QLatin1Char('*')
+ && endText.at(endPos+1) == QLatin1Char('/'))) {
+ endPos += 2;
+ end += 2;
+ }
+
+ bool hasSelEnd = (endPos >= 2
+ && endText.at(endPos-2) == QLatin1Char('*')
+ && endText.at(endPos-1) == QLatin1Char('/'));
+
+ doCStyleUncomment = hasSelStart && hasSelEnd;
+ doCStyleComment = !doCStyleUncomment && (hasLeadingCharacters || hasTrailingCharacters);
+ }
+
+ if (doCStyleUncomment) {
+ cursor.setPosition(end);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2);
+ cursor.removeSelectedText();
+ cursor.setPosition(start);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
+ cursor.removeSelectedText();
+ } else if (doCStyleComment) {
+ cursor.setPosition(end);
+ cursor.insertText(QLatin1String("*/"));
+ cursor.setPosition(start);
+ cursor.insertText(QLatin1String("/*"));
+ } else {
+ endBlock = endBlock.next();
+ doCppStyleUncomment = true;
+ for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
+ QString text = block.text();
+ if (!text.trimmed().startsWith(QLatin1String("//"))) {
+ doCppStyleUncomment = false;
+ break;
+ }
+ }
+ for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
+ if (doCppStyleUncomment) {
+ QString text = block.text();
+ int i = 0;
+ while (i < text.size() - 1) {
+ if (text.at(i) == QLatin1Char('/')
+ && text.at(i + 1) == QLatin1Char('/')) {
+ cursor.setPosition(block.position() + i);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
+ cursor.removeSelectedText();
+ break;
+ }
+ if (!text.at(i).isSpace())
+ break;
+ ++i;
+ }
+ } else {
+ cursor.setPosition(block.position());
+ cursor.insertText(QLatin1String("//"));
+ }
+ }
+ }
+
+ // adjust selection when commenting out
+ if (hasSelection && !doCStyleUncomment && !doCppStyleUncomment) {
+ cursor = textCursor();
+ if (!doCStyleComment)
+ start = startBlock.position(); // move the double slashes into the selection
+ int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor();
+ if (anchorIsStart) {
+ cursor.setPosition(start);
+ cursor.setPosition(lastSelPos, QTextCursor::KeepAnchor);
+ } else {
+ cursor.setPosition(lastSelPos);
+ cursor.setPosition(start, QTextCursor::KeepAnchor);
+ }
+ setTextCursor(cursor);
+ }
+
+ cursor.endEditBlock();
+}
+
+int CPPEditor::endOfNameUnderCursor()
+{
+ int pos = position();
+ QChar chr = characterAt(pos);
+
+ // Skip to the start of a name
+ while (chr.isLetterOrNumber() || chr == QLatin1Char('_'))
+ chr = characterAt(++pos);
+
+ return pos;
+}
+
+bool CPPEditor::openEditorAt(Symbol *s)
+{
+ const QString fileName = QString::fromUtf8(s->fileName(), s->fileNameLength());
+ return TextEditor::BaseTextEditor::openEditorAt(fileName, s->line(), s->column());
+}
diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h
new file mode 100644
index 0000000000..404d8047ad
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPEDITOR_H
+#define CPPEDITOR_H
+
+#include "cppeditorenums.h"
+#include <cplusplus/CppDocument.h>
+#include <texteditor/basetexteditor.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QComboBox;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace CPlusPlus {
+class OverviewModel;
+class Symbol;
+}
+
+namespace CppTools {
+class CppModelManagerInterface;
+}
+
+namespace TextEditor {
+class FontSettings;
+}
+
+namespace CppEditor {
+namespace Internal {
+
+class CPPEditor;
+
+class CPPEditorEditable : public TextEditor::BaseTextEditorEditable
+{
+ Q_OBJECT
+public:
+ CPPEditorEditable(CPPEditor *);
+ QList<int> context() const;
+
+ bool duplicateSupported() const { return true; }
+ Core::IEditor *duplicate(QWidget *parent);
+ const char *kind() const;
+
+private:
+ QList<int> m_context;
+};
+
+class CPPEditor : public TextEditor::BaseTextEditor
+{
+ Q_OBJECT
+
+public:
+ typedef TextEditor::TabSettings TabSettings;
+
+ CPPEditor(QWidget *parent);
+ ~CPPEditor();
+
+ void unCommentSelection();
+
+public slots:
+ virtual void setFontSettings(const TextEditor::FontSettings &);
+ void switchDeclarationDefinition();
+ void jumpToDefinition();
+
+ void moveToPreviousToken();
+ void moveToNextToken();
+
+ void deleteStartOfToken();
+ void deleteEndOfToken();
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *e);
+ TextEditor::BaseTextEditorEditable *createEditableInterface();
+
+ // Rertuns true if key triggers anindent.
+ virtual bool isElectricCharacter(const QChar &ch) const;
+
+private slots:
+ void updateFileName();
+ void jumpToMethod(int index);
+ void updateMethodBoxIndex();
+
+ void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
+
+private:
+ CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol);
+ virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+
+ int previousBlockState(QTextBlock block) const;
+ QTextCursor moveToPreviousToken(QTextCursor::MoveMode mode) const;
+ QTextCursor moveToNextToken(QTextCursor::MoveMode mode) const;
+
+ void createToolBar(CPPEditorEditable *editable);
+
+ int endOfNameUnderCursor();
+
+ bool openEditorAt(CPlusPlus::Symbol *symbol);
+
+ Core::ICore *m_core;
+ CppTools::CppModelManagerInterface *m_modelManager;
+
+ QList<int> m_contexts;
+ QComboBox *m_methodCombo;
+ CPlusPlus::OverviewModel *m_overviewModel;
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPEDITOR_H
diff --git a/src/plugins/cppeditor/cppeditor.pri b/src/plugins/cppeditor/cppeditor.pri
new file mode 100644
index 0000000000..c4d6fdf753
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor.pri
@@ -0,0 +1,3 @@
+include(cppeditor_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(CppEditor)
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
new file mode 100644
index 0000000000..cb71e9a838
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -0,0 +1,22 @@
+TEMPLATE = lib
+TARGET = CppEditor
+DEFINES += CPPEDITOR_LIBRARY
+include(../../libs/utils/utils.pri)
+include(../../qworkbenchplugin.pri)
+include(cppeditor_dependencies.pri)
+HEADERS += cppplugin.h \
+ cppeditor.h \
+ cppeditoractionhandler.h \
+ cpphighlighter.h \
+ cppfilewizard.h \
+ cppeditorconstants.h \
+ cppeditorenums.h \
+ cppeditor_global.h \
+ cppclasswizard.h
+SOURCES += cppplugin.cpp \
+ cppeditoractionhandler.cpp \
+ cppeditor.cpp \
+ cpphighlighter.cpp \
+ cppfilewizard.cpp \
+ cppclasswizard.cpp
+RESOURCES += cppeditor.qrc
diff --git a/src/plugins/cppeditor/cppeditor.qrc b/src/plugins/cppeditor/cppeditor.qrc
new file mode 100644
index 0000000000..6ddcbac8bb
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/cppeditor" >
+ <file>images/qt_cpp.png</file>
+ <file>images/qt_h.png</file>
+ <file>CppEditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/cppeditor/cppeditor_dependencies.pri b/src/plugins/cppeditor/cppeditor_dependencies.pri
new file mode 100644
index 0000000000..0d56376efe
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor_dependencies.pri
@@ -0,0 +1,6 @@
+include(../../libs/utils/utils.pri)
+include(../../libs/cplusplus/cplusplus.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../../shared/indenter/indenter.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/cpptools/cpptools.pri)
diff --git a/src/plugins/cppeditor/cppeditor_global.h b/src/plugins/cppeditor/cppeditor_global.h
new file mode 100644
index 0000000000..6106383122
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditor_global.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPEDITOR_GLOBAL_H
+#define CPPEDITOR_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(CPPEDITOR_LIBRARY)
+# define CPPEDITOR_EXPORT Q_DECL_EXPORT
+#else
+# define CPPEDITOR_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // CPPEDITOR_GLOBAL_H
diff --git a/src/plugins/cppeditor/cppeditoractionhandler.cpp b/src/plugins/cppeditor/cppeditoractionhandler.cpp
new file mode 100644
index 0000000000..1ea013fb2a
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditoractionhandler.cpp
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "cppeditoractionhandler.h"
+#include "cppeditorconstants.h"
+#include "cppeditor.h"
+#include <QAction>
+
+using namespace CppEditor::Internal;
+
+CPPEditorActionHandler::CPPEditorActionHandler(Core::ICore *core,
+ const QString &context,
+ uint optionalActions)
+ : TextEditor::TextEditorActionHandler(core, context, optionalActions)
+{ }
+
+CPPEditorActionHandler::~CPPEditorActionHandler()
+{ }
+
+void CPPEditorActionHandler::createActions()
+{ TextEditor::TextEditorActionHandler::createActions(); }
+
+void CPPEditorActionHandler::updateActions(UpdateMode um)
+{ TextEditor::TextEditorActionHandler::updateActions(um); }
diff --git a/src/plugins/cppeditor/cppeditoractionhandler.h b/src/plugins/cppeditor/cppeditoractionhandler.h
new file mode 100644
index 0000000000..75c1102d22
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditoractionhandler.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPEDITORACTIONHANDLER_H
+#define CPPEDITORACTIONHANDLER_H
+
+#include <texteditor/texteditoractionhandler.h>
+
+namespace CppEditor {
+namespace Internal {
+
+class CPPEditorActionHandler : public TextEditor::TextEditorActionHandler
+{
+ Q_OBJECT
+
+public:
+ CPPEditorActionHandler(Core::ICore *core,
+ const QString &context,
+ uint optionalActions = None);
+ virtual ~CPPEditorActionHandler();
+
+ using TextEditor::TextEditorActionHandler::updateActions;
+
+protected:
+ virtual void createActions();
+ virtual void updateActions(UpdateMode um);
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPEDITORACTIONHANDLER_H
diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h
new file mode 100644
index 0000000000..0c29ec9630
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditorconstants.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPPLUGIN_GLOBAL_H
+#define CPPPLUGIN_GLOBAL_H
+
+namespace CppEditor {
+namespace Constants {
+
+const char * const FORMATCODE = "CppEditor.FormatCode";
+const char * const M_CONTEXT = "CppEditor.ContextMenu";
+const char * const C_CPPEDITOR = "C++ Editor";
+const char * const CPPEDITOR_KIND = "C++ Editor";
+const char * const SWITCH_DECLARATION_DEFINITION = "CppEditor.SwitchDeclarationDefinition";
+const char * const JUMP_TO_DEFINITION = "CppEditor.JumpToDefinition";
+
+const char * const HEADER_FILE_TYPE = "CppHeaderFiles";
+const char * const SOURCE_FILE_TYPE = "CppSourceFiles";
+
+const char * const MOVE_TO_PREVIOUS_TOKEN = "CppEditor.MoveToPreviousToken";
+const char * const MOVE_TO_NEXT_TOKEN = "CppEditor.MoveToNextToken";
+
+const char * const C_SOURCE_MIMETYPE = "text/x-csrc";
+const char * const C_HEADER_MIMETYPE = "text/x-chdr";
+const char * const CPP_SOURCE_MIMETYPE = "text/x-c++src";
+const char * const CPP_HEADER_MIMETYPE = "text/x-c++hdr";
+} // namespace Constants
+} // namespace CppEditor
+
+#endif // CPPPLUGIN_GLOBAL_H
diff --git a/src/plugins/cppeditor/cppeditorenums.h b/src/plugins/cppeditor/cppeditorenums.h
new file mode 100644
index 0000000000..85e6497215
--- /dev/null
+++ b/src/plugins/cppeditor/cppeditorenums.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPPLUGIN_ENUMS_H
+#define CPPPLUGIN_ENUMS_H
+
+namespace CppEditor {
+namespace Internal {
+
+enum FileType {
+ Header,
+ Source
+};
+
+enum CppFormats {
+ CppNumberFormat,
+ CppStringFormat,
+ CppTypeFormat,
+ CppKeywordFormat,
+ CppOperatorFormat,
+ CppPreprocessorFormat,
+ CppLabelFormat,
+ CppCommentFormat,
+ NumCppFormats
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPPLUGIN_ENUMS_H
diff --git a/src/plugins/cppeditor/cppfilewizard.cpp b/src/plugins/cppeditor/cppfilewizard.cpp
new file mode 100644
index 0000000000..a8e477f219
--- /dev/null
+++ b/src/plugins/cppeditor/cppfilewizard.cpp
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppfilewizard.h"
+#include "cppeditor.h"
+#include "cppeditorconstants.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+using namespace CppEditor;
+using namespace CppEditor::Internal;
+
+enum { debugWizard = 0 };
+
+CppFileWizard::CppFileWizard(const BaseFileWizardParameters &parameters,
+ FileType type,
+ Core::ICore *core,
+ QObject *parent) :
+ Core::StandardFileWizard(parameters, core, parent),
+ m_type(type)
+{
+}
+
+QString CppFileWizard::toAlphaNum(const QString &s)
+{
+ QString rc;
+ const int len = s.size();
+ const QChar underscore = QLatin1Char('_');
+
+ for (int i = 0; i < len; i++) {
+ const QChar c = s.at(i);
+ if (c == underscore || c.isLetterOrNumber())
+ rc += c;
+ }
+ return rc;
+}
+
+Core::GeneratedFiles CppFileWizard::generateFilesFromPath(const QString &path,
+ const QString &name,
+ QString * /*errorMessage*/) const
+
+{
+ const QString mimeType = m_type == Source ? QLatin1String(Constants::CPP_SOURCE_MIMETYPE) : QLatin1String(Constants::CPP_HEADER_MIMETYPE);
+ const QString fileName = Core::BaseFileWizard::buildFileName(path, name, preferredSuffix(mimeType));
+ Core::GeneratedFile file(fileName);
+ file.setEditorKind(QLatin1String(Constants::C_CPPEDITOR));
+ const QString cleanName = toAlphaNum(QFileInfo(name).baseName());
+
+ file.setContents(fileContents(m_type, fileName));
+ return Core::GeneratedFiles() << file;
+}
+
+QString CppFileWizard::fileContents(FileType type, const QString &fileName) const
+{
+ const QString baseName = QFileInfo(fileName).baseName();
+ QString contents;
+ QTextStream str(&contents);
+ switch (type) {
+ case Header: {
+ QString guard = toAlphaNum(baseName).toUpper();
+ guard += QLatin1String("_H");
+ str << QLatin1String("#ifndef ") << guard
+ << QLatin1String("\n#define ") << guard << QLatin1String("\n\n#endif // ")
+ << guard << QLatin1String("\n");
+ }
+ break;
+ case Source:
+ str << QLatin1String("#include \"") << baseName << '.' << preferredSuffix(QLatin1String(Constants::CPP_HEADER_MIMETYPE)) << QLatin1String("\"\n\n");
+ break;
+ }
+ return contents;
+}
diff --git a/src/plugins/cppeditor/cppfilewizard.h b/src/plugins/cppeditor/cppfilewizard.h
new file mode 100644
index 0000000000..551aac8688
--- /dev/null
+++ b/src/plugins/cppeditor/cppfilewizard.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPFILEWIZARD_H
+#define CPPFILEWIZARD_H
+
+#include "cppeditorenums.h"
+
+#include <coreplugin/basefilewizard.h>
+
+namespace CppEditor {
+namespace Internal {
+
+class CppFileWizard : public Core::StandardFileWizard
+{
+ Q_OBJECT
+
+public:
+ typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
+
+ explicit CppFileWizard(const BaseFileWizardParameters &parameters,
+ FileType type,
+ Core::ICore *core, QObject *parent = 0);
+
+protected:
+ static QString toAlphaNum(const QString &s);
+ QString fileContents(FileType type, const QString &baseName) const;
+
+protected:
+ Core::GeneratedFiles generateFilesFromPath(const QString &path,
+ const QString &fileName,
+ QString *errorMessage) const;
+private:
+ const FileType m_type;
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPFILEWIZARD_H
diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp
new file mode 100644
index 0000000000..4bd823c0c8
--- /dev/null
+++ b/src/plugins/cppeditor/cpphighlighter.cpp
@@ -0,0 +1,303 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cpphighlighter.h"
+
+#include <Token.h>
+#include <cplusplus/SimpleLexer.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtGui/QTextDocument>
+#include <QtCore/QDebug>
+
+using namespace CppEditor::Internal;
+using namespace TextEditor;
+using namespace CPlusPlus;
+
+CPPHighlighter::CPPHighlighter(QTextDocument *document) :
+ QSyntaxHighlighter(document)
+{
+ visualSpaceFormat.setForeground(Qt::lightGray);
+}
+
+void CPPHighlighter::highlightBlock(const QString &text)
+{
+ QTextCharFormat emptyFormat;
+
+ const int previousState = previousBlockState();
+ int state = 0, braceDepth = 0;
+ if (previousState != -1) {
+ state = previousState & 0xff;
+ braceDepth = previousState >> 8;
+ }
+
+ SimpleLexer tokenize;
+ tokenize.setQtMocRunEnabled(false);
+
+ int initialState = state;
+ const QList<SimpleToken> tokens = tokenize(text, initialState);
+ state = tokenize.state(); // refresh the state
+
+ if (tokens.isEmpty()) {
+ setCurrentBlockState(previousState);
+ if (TextBlockUserData *userData = TextEditDocumentLayout::testUserData(currentBlock())) {
+ userData->setClosingCollapseMode(TextBlockUserData::NoClosingCollapse);
+ userData->setCollapseMode(TextBlockUserData::NoCollapse);
+ }
+ TextEditDocumentLayout::clearParentheses(currentBlock());
+ return;
+ }
+
+ const int firstNonSpace = tokens.first().position();
+
+ Parentheses parentheses;
+ parentheses.reserve(20); // assume wizard level ;-)
+
+ bool highlightAsPreprocessor = false;
+
+ for (int i = 0; i < tokens.size(); ++i) {
+ const SimpleToken &tk = tokens.at(i);
+
+ int previousTokenEnd = 0;
+ if (i != 0) {
+ // mark the whitespaces
+ previousTokenEnd = tokens.at(i - 1).position() +
+ tokens.at(i - 1).length();
+ }
+
+ if (previousTokenEnd != tk.position()) {
+ setFormat(previousTokenEnd, tk.position() - previousTokenEnd,
+ visualSpaceFormat);
+ }
+
+ 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))
+ ++braceDepth;
+ } 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 (--braceDepth < 0)
+ braceDepth = 0;
+ }
+ }
+
+ bool highlightCurrentWordAsPreprocessor = highlightAsPreprocessor;
+ if (highlightAsPreprocessor)
+ highlightAsPreprocessor = false;
+
+ if (i == 0 && tk.is(T_POUND)) {
+ setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
+ highlightAsPreprocessor = true;
+ } else if (highlightCurrentWordAsPreprocessor &&
+ (tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(tk.text()))
+ setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
+ else if (tk.is(T_INT_LITERAL) || tk.is(T_FLOAT_LITERAL))
+ setFormat(tk.position(), tk.length(), m_formats[CppNumberFormat]);
+ else if (tk.is(T_STRING_LITERAL) || tk.is(T_CHAR_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))
+ setFormat(tk.position(), tk.length(), m_formats[CppStringFormat]);
+ else if (tk.is(T_WIDE_STRING_LITERAL) || tk.is(T_WIDE_CHAR_LITERAL))
+ setFormat(tk.position(), tk.length(), m_formats[CppStringFormat]);
+ else if (tk.is(T_COMMENT)) {
+ setFormat(tk.position(), tk.length(), m_formats[CppCommentFormat]);
+ // we need to insert a close comment parenthesis, if
+ // - the line starts in a C Comment (initalState != 0)
+ // - the first token of the line is a T_COMMENT (i == 0 && tk.is(T_COMMENT))
+ // - is not a continuation line (tokens.size() > 1 || ! state)
+ if (initialState && i == 0 && (tokens.size() > 1 || ! state)) {
+ --braceDepth;
+
+ const int tokenEnd = tk.position() + tk.length() - 1;
+ parentheses.append(Parenthesis(Parenthesis::Closed, QLatin1Char('-'), tokenEnd));
+
+ // clear the initial state.
+ initialState = 0;
+ }
+ } else if (tk.isKeyword() || isQtKeyword(tk.text()))
+ setFormat(tk.position(), tk.length(), m_formats[CppKeywordFormat]);
+ else if (tk.isOperator())
+ setFormat(tk.position(), tk.length(), m_formats[CppOperatorFormat]);
+ else if (i == 0 && tokens.size() > 1 && tk.is(T_IDENTIFIER) && tokens.at(1).is(T_COLON))
+ setFormat(tk.position(), tk.length(), m_formats[CppLabelFormat]);
+ else if (tk.is(T_IDENTIFIER))
+ highlightWord(tk.text(), tk.position(), tk.length());
+ }
+
+ // mark the trailing white spaces
+ if (! tokens.isEmpty()) {
+ const SimpleToken tk = tokens.last();
+ const int lastTokenEnd = tk.position() + tk.length();
+ if (text.length() > lastTokenEnd)
+ setFormat(lastTokenEnd, text.length() - lastTokenEnd, visualSpaceFormat);
+ }
+
+ if (TextBlockUserData *userData = TextEditDocumentLayout::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;
+ TextEditDocumentLayout::userData(currentBlock())->setCollapseMode(collapseMode);
+ }
+
+
+ int cc = Parenthesis::closeCollapseAtPos(parentheses);
+ if (cc >= 0) {
+ TextBlockUserData *userData = TextEditDocumentLayout::userData(currentBlock());
+ userData->setClosingCollapseMode(TextBlockUserData::ClosingCollapse);
+ QString trailingText = text.mid(cc+1).simplified();
+ if (trailingText.isEmpty() || trailingText == QLatin1String(";")) {
+ userData->setClosingCollapseMode(TextBlockUserData::ClosingCollapseAtEnd);
+ }
+ }
+
+ TextEditDocumentLayout::setParentheses(currentBlock(), parentheses);
+
+ setCurrentBlockState((braceDepth << 8) | tokenize.state());
+}
+
+
+bool CPPHighlighter::isPPKeyword(const QStringRef &text) const
+{
+ switch (text.length())
+ {
+ case 2:
+ if (text.at(0) == 'i' && text.at(1) == 'f')
+ return true;
+ break;
+
+ case 4:
+ if (text.at(0) == 'e' && text == QLatin1String("elif"))
+ return true;
+ else if (text.at(0) == 'e' && text == QLatin1String("else"))
+ return true;
+ break;
+
+ case 5:
+ if (text.at(0) == 'i' && text == QLatin1String("ifdef"))
+ return true;
+ else if (text.at(0) == 'u' && text == QLatin1String("undef"))
+ return true;
+ else if (text.at(0) == 'e' && text == QLatin1String("endif"))
+ return true;
+ else if (text.at(0) == 'e' && text == QLatin1String("error"))
+ return true;
+ break;
+
+ case 6:
+ if (text.at(0) == 'i' && text == QLatin1String("ifndef"))
+ return true;
+ else if (text.at(0) == 'd' && text == QLatin1String("define"))
+ return true;
+ else if (text.at(0) == 'p' && text == QLatin1String("pragma"))
+ return true;
+ break;
+
+ case 7:
+ if (text.at(0) == 'i' && text == QLatin1String("include"))
+ return true;
+ else if (text.at(0) == 'w' && text == QLatin1String("warning"))
+ return true;
+ break;
+
+ case 12:
+ if (text.at(0) == 'i' && text == QLatin1String("include_next"))
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool CPPHighlighter::isQtKeyword(const QStringRef &text) const
+{
+ switch (text.length()) {
+ case 4:
+ if (text.at(0) == 'e' && text == QLatin1String("emit"))
+ return true;
+ else if (text.at(0) == 'S' && text == QLatin1String("SLOT"))
+ return true;
+ break;
+
+ case 5:
+ if (text.at(0) == 's' && text == QLatin1String("slots"))
+ return true;
+ break;
+
+ case 6:
+ if (text.at(0) == 'S' && text == QLatin1String("SIGNAL"))
+ return true;
+ break;
+
+ case 7:
+ if (text.at(0) == 's' && text == QLatin1String("signals"))
+ return true;
+ else if (text.at(0) == 'f' && text == QLatin1String("foreach"))
+ return true;
+ else if (text.at(0) == 'f' && text == QLatin1String("forever"))
+ return true;
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+void CPPHighlighter::highlightWord(QStringRef word, int position, int length)
+{
+ // try to highlight Qt 'identifiers' like QObject and Q_PROPERTY
+ // but don't highlight words like 'Query'
+ if (word.length() > 1
+ && word.at(0) == QLatin1Char('Q')
+ && (word.at(1).isUpper()
+ || word.at(1) == QLatin1Char('_')
+ || word.at(1) == QLatin1Char('t'))) {
+ setFormat(position, length, m_formats[CppTypeFormat]);
+ }
+}
diff --git a/src/plugins/cppeditor/cpphighlighter.h b/src/plugins/cppeditor/cpphighlighter.h
new file mode 100644
index 0000000000..cdfc2d8360
--- /dev/null
+++ b/src/plugins/cppeditor/cpphighlighter.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPHIGHLIGHTER_H
+#define CPPHIGHLIGHTER_H
+
+#include "cppeditorenums.h"
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCharFormat>
+#include <QtCore/QtAlgorithms>
+
+namespace CppEditor {
+namespace Internal {
+
+class CPPEditor;
+
+class CPPHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+
+public:
+ CPPHighlighter(QTextDocument *document = 0);
+
+ virtual void highlightBlock(const QString &text);
+
+ // Set formats from a sequence of type QTextCharFormat
+ template <class InputIterator>
+ void setFormats(InputIterator begin, InputIterator end) {
+ qCopy(begin, end, m_formats);
+ }
+
+private:
+ void highlightWord(QStringRef word, int position, int length);
+ bool isPPKeyword(const QStringRef &text) const;
+ bool isQtKeyword(const QStringRef &text) const;
+
+ QTextCharFormat m_formats[NumCppFormats];
+ QTextCharFormat visualSpaceFormat;
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPHIGHLIGHTER_H
diff --git a/src/plugins/cppeditor/cppplugin.cpp b/src/plugins/cppeditor/cppplugin.cpp
new file mode 100644
index 0000000000..576624f5b4
--- /dev/null
+++ b/src/plugins/cppeditor/cppplugin.cpp
@@ -0,0 +1,258 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppplugin.h"
+#include "cppeditor.h"
+#include "cppeditorconstants.h"
+#include "cppeditorenums.h"
+#include "cppfilewizard.h"
+#include "cppclasswizard.h"
+#include "cppeditoractionhandler.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/icommand.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/completionsupport.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/storagesettings.h>
+#include <texteditor/texteditorsettings.h>
+#include <cpptools/cpptoolsconstants.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+static const char *headerSuffixKeyC = "CppEditor/HeaderSuffix";
+static const char *sourceSuffixKeyC = "CppEditor/SourceSuffix";
+
+using namespace CppEditor::Internal;
+
+///////////////////////////////// CppPluginEditorFactory //////////////////////////////////
+
+CppPluginEditorFactory::CppPluginEditorFactory(CppPlugin *owner) :
+ m_kind(QLatin1String(CppEditor::Constants::CPPEDITOR_KIND)),
+ m_owner(owner)
+{
+ m_mimeTypes << QLatin1String(CppEditor::Constants::C_SOURCE_MIMETYPE)
+ << QLatin1String(CppEditor::Constants::C_HEADER_MIMETYPE)
+ << QLatin1String(CppEditor::Constants::CPP_SOURCE_MIMETYPE)
+ << QLatin1String(CppEditor::Constants::CPP_HEADER_MIMETYPE);
+ Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
+ iconProvider->registerIconForSuffix(QIcon(":/cppeditor/images/qt_cpp.png"),
+ QLatin1String("cpp"));
+ iconProvider->registerIconForSuffix(QIcon(":/cppeditor/images/qt_h.png"),
+ QLatin1String("h"));
+}
+
+QString CppPluginEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *CppPluginEditorFactory::open(const QString &fileName)
+{
+ Core::IEditor *iface = m_owner->m_core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *CppPluginEditorFactory::createEditor(QWidget *parent)
+{
+ CPPEditor *editor = new CPPEditor(parent);
+ editor->setRevisionsVisible(true);
+ editor->setMimeType(CppEditor::Constants::CPP_SOURCE_MIMETYPE);
+ m_owner->initializeEditor(editor);
+ return editor->editableInterface();
+}
+
+QStringList CppPluginEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
+
+///////////////////////////////// CppPlugin //////////////////////////////////
+
+CppPlugin *CppPlugin::m_instance = 0;
+
+CppPlugin::CppPlugin() :
+ m_core(0),
+ m_actionHandler(0),
+ m_factory(0)
+{
+ m_instance = this;
+}
+
+CppPlugin::~CppPlugin()
+{
+ removeObject(m_factory);
+ delete m_factory;
+ delete m_actionHandler;
+ m_instance = 0;
+}
+
+CppPlugin *CppPlugin::instance()
+{
+ return m_instance;
+}
+
+Core::ICore *CppPlugin::core()
+{
+ return m_instance->m_core;
+}
+
+void CppPlugin::initializeEditor(CPPEditor *editor)
+{
+ // common actions
+ m_actionHandler->setupActions(editor);
+
+ // settings
+ TextEditor::TextEditorSettings *settings = TextEditor::TextEditorSettings::instance();
+ connect(settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
+ editor, SLOT(setFontSettings(TextEditor::FontSettings)));
+ connect(settings, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
+ editor, SLOT(setTabSettings(TextEditor::TabSettings)));
+ connect(settings, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)),
+ editor, SLOT(setStorageSettings(TextEditor::StorageSettings)));
+ connect(settings, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)),
+ editor, SLOT(setDisplaySettings(TextEditor::DisplaySettings)));
+
+ // tab settings rely on font settings
+ editor->setFontSettings(settings->fontSettings());
+ editor->setTabSettings(settings->tabSettings());
+ editor->setStorageSettings(settings->storageSettings());
+ editor->setDisplaySettings(settings->displaySettings());
+
+ // auto completion
+ connect(editor, SIGNAL(requestAutoCompletion(ITextEditable*, bool)),
+ TextEditor::Internal::CompletionSupport::instance(core()), SLOT(autoComplete(ITextEditable*, bool)));
+}
+
+bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ typedef TextEditor::TextEditorActionHandler TextEditorActionHandler;
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!m_core->mimeDatabase()->addMimeTypes(QLatin1String(":/cppeditor/CppEditor.mimetypes.xml"), errorMessage))
+ return false;
+
+ m_factory = new CppPluginEditorFactory(this);
+ addObject(m_factory);
+
+ CppFileWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+
+ wizardParameters.setCategory(QLatin1String("C++"));
+ wizardParameters.setTrCategory(tr("C++"));
+ wizardParameters.setDescription(tr("Creates a new C++ header file."));
+ wizardParameters.setName(tr("C++ Header File"));
+ addAutoReleasedObject(new CppFileWizard(wizardParameters, Header, m_core));
+
+ wizardParameters.setDescription(tr("Creates a new C++ source file."));
+ wizardParameters.setName(tr("C++ Source File"));
+ addAutoReleasedObject(new CppFileWizard(wizardParameters, Source, m_core));
+
+ wizardParameters.setKind(Core::IWizard::ClassWizard);
+ wizardParameters.setName(tr("C++ Class"));
+ wizardParameters.setDescription(tr("Creates a header and a source file for a new class."));
+ addAutoReleasedObject(new CppClassWizard(wizardParameters, m_core));
+
+ QList<int> context;
+ context << m_core->uniqueIDManager()->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
+
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ am->createMenu(CppEditor::Constants::M_CONTEXT);
+
+ Core::ICommand *cmd;
+
+ QAction *jumpToDefinition = new QAction(tr("Follow Symbol under Cursor"), this);
+ cmd = am->registerAction(jumpToDefinition,
+ Constants::JUMP_TO_DEFINITION, context);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F2));
+ connect(jumpToDefinition, SIGNAL(triggered()),
+ this, SLOT(jumpToDefinition()));
+ am->actionContainer(CppEditor::Constants::M_CONTEXT)->addAction(cmd);
+ am->actionContainer(CppTools::Constants::M_TOOLS_CPP)->addAction(cmd);
+
+ QAction *switchDeclarationDefinition = new QAction(tr("Switch between Method Declaration/Definition"), this);
+ cmd = am->registerAction(switchDeclarationDefinition,
+ Constants::SWITCH_DECLARATION_DEFINITION, context);
+ cmd->setDefaultKeySequence(QKeySequence("Shift+F2"));
+ connect(switchDeclarationDefinition, SIGNAL(triggered()),
+ this, SLOT(switchDeclarationDefinition()));
+ am->actionContainer(CppEditor::Constants::M_CONTEXT)->addAction(cmd);
+ am->actionContainer(CppTools::Constants::M_TOOLS_CPP)->addAction(cmd);
+
+ m_actionHandler = new CPPEditorActionHandler(m_core,
+ CppEditor::Constants::C_CPPEDITOR,
+ TextEditor::TextEditorActionHandler::Format
+ | TextEditor::TextEditorActionHandler::UnCommentSelection
+ | TextEditor::TextEditorActionHandler::UnCollapseAll);
+
+ // Check Suffixes
+ if (const QSettings *settings = m_core->settings()) {
+ const QString headerSuffixKey = QLatin1String(headerSuffixKeyC);
+ if (settings->contains(headerSuffixKey)) {
+ const QString headerSuffix = settings->value(headerSuffixKey, QString()).toString();
+ if (!headerSuffix.isEmpty())
+ m_core->mimeDatabase()->setPreferredSuffix(QLatin1String(Constants::CPP_HEADER_MIMETYPE), headerSuffix);
+ const QString sourceSuffix = settings->value(QLatin1String(sourceSuffixKeyC), QString()).toString();
+ if (!sourceSuffix.isEmpty())
+ m_core->mimeDatabase()->setPreferredSuffix(QLatin1String(Constants::CPP_SOURCE_MIMETYPE), sourceSuffix);
+ }
+ }
+ return true;
+}
+
+void CppPlugin::extensionsInitialized()
+{
+ m_actionHandler->initializeActions();
+}
+
+void CppPlugin::switchDeclarationDefinition()
+{
+ CPPEditor *editor = qobject_cast<CPPEditor*>(m_core->editorManager()->currentEditor()->widget());
+ if (editor) {
+ editor->switchDeclarationDefinition();
+ }
+}
+
+void CppPlugin::jumpToDefinition()
+{
+ CPPEditor *editor = qobject_cast<CPPEditor*>(m_core->editorManager()->currentEditor()->widget());
+ if (editor) {
+ editor->jumpToDefinition();
+ }
+}
+
+Q_EXPORT_PLUGIN(CppPlugin)
diff --git a/src/plugins/cppeditor/cppplugin.h b/src/plugins/cppeditor/cppplugin.h
new file mode 100644
index 0000000000..8bc4e8d61e
--- /dev/null
+++ b/src/plugins/cppeditor/cppplugin.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPPLUGIN_H
+#define CPPPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QStringList>
+
+#include <extensionsystem/iplugin.h>
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+namespace Core {
+class ICore;
+class IWizard;
+}
+
+namespace TextEditor {
+class TextEditorActionHandler;
+} // namespace TextEditor
+
+namespace CppEditor {
+namespace Internal {
+
+class CPPEditor;
+class CPPEditorActionHandler;
+class CppPluginEditorFactory;
+
+class CppPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ CppPlugin();
+ ~CppPlugin();
+
+ static CppPlugin *instance();
+ static Core::ICore *core();
+
+ bool initialize(const QStringList &arguments, QString *error_message = 0);
+ void extensionsInitialized();
+
+ // Connect editor to settings changed signals.
+ void initializeEditor(CPPEditor *editor);
+
+private slots:
+ void switchDeclarationDefinition();
+ void jumpToDefinition();
+
+private:
+ friend class CppPluginEditorFactory;
+ Core::IEditor *createEditor(QWidget *parent);
+
+ static CppPlugin *m_instance;
+
+ Core::ICore *m_core;
+ CPPEditorActionHandler *m_actionHandler;
+ CppPluginEditorFactory *m_factory;
+};
+
+class CppPluginEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ CppPluginEditorFactory(CppPlugin *owner);
+
+ virtual QStringList mimeTypes() const;
+
+ Core::IEditor *createEditor(QWidget *parent);
+
+ virtual QString kind() const;
+ Core::IFile *open(const QString &fileName);
+
+private:
+ const QString m_kind;
+ CppPlugin *m_owner;
+ QStringList m_mimeTypes;
+};
+
+} // namespace Internal
+} // namespace CppEditor
+
+#endif // CPPPLUGIN_H
diff --git a/src/plugins/cppeditor/images/qt_cpp.png b/src/plugins/cppeditor/images/qt_cpp.png
new file mode 100644
index 0000000000..73fd1642b3
--- /dev/null
+++ b/src/plugins/cppeditor/images/qt_cpp.png
Binary files differ
diff --git a/src/plugins/cppeditor/images/qt_h.png b/src/plugins/cppeditor/images/qt_h.png
new file mode 100644
index 0000000000..dec0475219
--- /dev/null
+++ b/src/plugins/cppeditor/images/qt_h.png
Binary files differ
diff --git a/src/plugins/cpptools/CppTools.pluginspec b/src/plugins/cpptools/CppTools.pluginspec
new file mode 100644
index 0000000000..ca4a8a0e52
--- /dev/null
+++ b/src/plugins/cpptools/CppTools.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="CppTools" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Tools for analyzing C/C++ code.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
new file mode 100644
index 0000000000..5950477184
--- /dev/null
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -0,0 +1,1040 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppcodecompletion.h"
+#include "cppmodelmanager.h"
+
+#include <Control.h>
+#include <AST.h>
+#include <ASTVisitor.h>
+#include <CoreTypes.h>
+#include <Literals.h>
+#include <Names.h>
+#include <NameVisitor.h>
+#include <Symbols.h>
+#include <SymbolVisitor.h>
+#include <Scope.h>
+#include <TranslationUnit.h>
+#include <cplusplus/ResolveExpression.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/ExpressionUnderCursor.h>
+#include <cplusplus/TokenUnderCursor.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/itexteditable.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QMap>
+#include <QtCore/QFile>
+#include <QtGui/QAction>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLabel>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QApplication>
+
+using namespace CPlusPlus;
+
+namespace CppTools {
+namespace Internal {
+
+class FunctionArgumentWidget : public QLabel {
+public:
+ FunctionArgumentWidget(Core::ICore *core);
+ void showFunctionHint(Function *functionSymbol);
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *e);
+
+private:
+ void update();
+ void close();
+ void updateHintText();
+
+ int m_startpos;
+ int m_currentarg;
+
+ TextEditor::ITextEditor *m_editor;
+
+ QFrame *m_popupFrame;
+ Function *m_item;
+};
+
+class ConvertToCompletionItem: protected NameVisitor
+{
+ // The completion collector.
+ CppCodeCompletion *_collector;
+
+ // The completion item.
+ TextEditor::CompletionItem _item;
+
+ // The current symbol.
+ Symbol *_symbol;
+
+ // The pretty printer.
+ Overview overview;
+
+public:
+ ConvertToCompletionItem(CppCodeCompletion *collector)
+ : _collector(collector),
+ _item(0),
+ _symbol(0)
+ { }
+
+ TextEditor::CompletionItem operator()(Symbol *symbol)
+ {
+ if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
+ return 0;
+
+ TextEditor::CompletionItem previousItem = switchCompletionItem(0);
+ Symbol *previousSymbol = switchSymbol(symbol);
+ accept(symbol->identity());
+ if (_item)
+ _item.m_data = QVariant::fromValue(symbol);
+ (void) switchSymbol(previousSymbol);
+ return switchCompletionItem(previousItem);
+ }
+
+protected:
+ Symbol *switchSymbol(Symbol *symbol)
+ {
+ Symbol *previousSymbol = _symbol;
+ _symbol = symbol;
+ return previousSymbol;
+ }
+
+ TextEditor::CompletionItem switchCompletionItem(TextEditor::CompletionItem item)
+ {
+ TextEditor::CompletionItem previousItem = _item;
+ _item = item;
+ return previousItem;
+ }
+
+ TextEditor::CompletionItem newCompletionItem(Name *name)
+ {
+ TextEditor::CompletionItem item(_collector);
+ item.m_text = overview.prettyName(name);
+ item.m_icon = _collector->iconForSymbol(_symbol);
+ return item;
+ }
+
+ virtual void visit(NameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(TemplateNameId *name)
+ {
+ _item = newCompletionItem(name);
+ _item.m_text = QLatin1String(name->identifier()->chars());
+ }
+
+ virtual void visit(DestructorNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(OperatorNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(ConversionNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(QualifiedNameId *name)
+ { _item = newCompletionItem(name->unqualifiedNameId()); }
+};
+
+
+} // namespace Internal
+} // namespace CppTools
+
+
+
+using namespace CppTools::Internal;
+
+FunctionArgumentWidget::FunctionArgumentWidget(Core::ICore *core)
+ : m_item(0)
+{
+ QObject *editorObject = core->editorManager()->currentEditor();
+ m_editor = qobject_cast<TextEditor::ITextEditor *>(editorObject);
+
+ m_popupFrame = new QFrame(0, Qt::ToolTip|Qt::WindowStaysOnTopHint);
+ m_popupFrame->setFocusPolicy(Qt::NoFocus);
+ m_popupFrame->setAttribute(Qt::WA_DeleteOnClose);
+
+ setFrameStyle(QFrame::Box);
+ setFrameShadow(QFrame::Plain);
+
+ setParent(m_popupFrame);
+ setFocusPolicy(Qt::NoFocus);
+
+ QVBoxLayout *layout = new QVBoxLayout();
+ layout->addWidget(this);
+ layout->setMargin(0);
+ m_popupFrame->setLayout(layout);
+
+ QPalette pal = palette();
+ setAutoFillBackground(true);
+ pal.setColor(QPalette::Background, QColor(255, 255, 220));
+ setPalette(pal);
+
+ setTextFormat(Qt::RichText);
+ setMargin(1);
+}
+
+void FunctionArgumentWidget::showFunctionHint(Function *functionSymbol)
+{
+ m_item = functionSymbol;
+ m_startpos = m_editor->position();
+
+ // update the text
+ m_currentarg = -1;
+ update();
+
+ QPoint pos = m_editor->cursorRect().topLeft();
+ pos.setY(pos.y() - sizeHint().height());
+ m_popupFrame->move(pos);
+ m_popupFrame->show();
+
+ QCoreApplication::instance()->installEventFilter(this);
+}
+
+void FunctionArgumentWidget::update()
+{
+ int curpos = m_editor->position();
+ if (curpos < m_startpos) {
+ close();
+ return;
+ }
+
+ QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
+ int argnr = 0;
+ int parcount = 0;
+ SimpleLexer tokenize;
+ QList<SimpleToken> tokens = tokenize(str);
+ for (int i = 0; i < tokens.count(); ++i) {
+ const SimpleToken &tk = tokens.at(i);
+ if (tk.is(T_LPAREN))
+ ++parcount;
+ else if (tk.is(T_RPAREN))
+ --parcount;
+ else if (! parcount && tk.is(T_COMMA))
+ ++argnr;
+ }
+
+ if (m_currentarg != argnr) {
+ m_currentarg = argnr;
+ updateHintText();
+ }
+
+ if (parcount < 0)
+ close();
+}
+
+bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::KeyRelease:
+ {
+ if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
+ close();
+ return false;
+ }
+ update();
+ break;
+ }
+ case QEvent::WindowDeactivate:
+ case QEvent::Leave:
+ case QEvent::FocusOut:
+ {
+ if (obj != m_editor->widget())
+ break;
+ }
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::Wheel:
+ close();
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void FunctionArgumentWidget::close()
+{
+ m_popupFrame->close();
+}
+
+void FunctionArgumentWidget::updateHintText()
+{
+ Overview overview;
+ overview.setShowReturnTypes(true);
+ overview.setShowArgumentNames(true);
+ overview.setMarkArgument(m_currentarg + 1);
+ QString text = overview(m_item->type(), m_item->name());
+ setText(text);
+}
+
+CppCodeCompletion::CppCodeCompletion(CppModelManager *manager, Core::ICore *core)
+ : ICompletionCollector(manager),
+ m_core(core),
+ m_manager(manager),
+ m_forcedCompletion(false),
+ m_completionOperator(T_EOF_SYMBOL)
+{ }
+
+QIcon CppCodeCompletion::iconForSymbol(Symbol *symbol) const
+{ return m_icons.iconForSymbol(symbol); }
+
+/*
+ Searches beckward for an access operator.
+*/
+static int startOfOperator(TextEditor::ITextEditable *editor,
+ int pos, unsigned *kind,
+ bool wantFunctionCall)
+{
+ const QChar ch = pos > -1 ? editor->characterAt(pos - 1) : QChar();
+ const QChar ch2 = pos > 0 ? editor->characterAt(pos - 2) : QChar();
+ const QChar ch3 = pos > 1 ? editor->characterAt(pos - 3) : QChar();
+
+ int start = pos;
+
+ if (ch2 != QLatin1Char('.') && ch == QLatin1Char('.')) {
+ if (kind)
+ *kind = T_DOT;
+ --start;
+ } else if (wantFunctionCall && ch == QLatin1Char('(')) {
+ if (kind)
+ *kind = T_LPAREN;
+ --start;
+ } else if (ch2 == QLatin1Char(':') && ch == QLatin1Char(':')) {
+ if (kind)
+ *kind = T_COLON_COLON;
+ start -= 2;
+ } else if (ch2 == QLatin1Char('-') && ch == QLatin1Char('>')) {
+ if (kind)
+ *kind = T_ARROW;
+ start -= 2;
+ } else if (ch2 == QLatin1Char('.') && ch == QLatin1Char('*')) {
+ if (kind)
+ *kind = T_DOT_STAR;
+ start -= 2;
+ } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>') && ch == QLatin1Char('*')) {
+ if (kind)
+ *kind = T_ARROW_STAR;
+ start -= 3;
+ }
+
+ if (start != pos) {
+ TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
+ QTextCursor tc(edit->textCursor());
+ tc.setPosition(pos);
+ static CPlusPlus::TokenUnderCursor tokenUnderCursor;
+ const SimpleToken tk = tokenUnderCursor(tc);
+ if (tk.is(T_COMMENT) || tk.isLiteral()) {
+ if (kind)
+ *kind = T_EOF_SYMBOL;
+ return pos;
+ }
+ }
+
+ return start;
+}
+
+bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor)
+{
+ if (! m_manager->isCppEditor(editor)) // ### remove me
+ return false;
+
+ const int pos = editor->position();
+ if (startOfOperator(editor, pos, /*token =*/ 0,
+ /*want function call=*/ true) != pos)
+ return true;
+
+ return false;
+}
+
+int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
+{
+ TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
+ if (! edit)
+ return -1;
+
+ m_editor = editor;
+ m_startPosition = findStartOfName(editor);
+ m_completionOperator = T_EOF_SYMBOL;
+
+ int endOfExpression = m_startPosition;
+
+ // Skip whitespace preceding this position
+ while (editor->characterAt(endOfExpression - 1).isSpace())
+ --endOfExpression;
+
+ endOfExpression = startOfOperator(editor, endOfExpression,
+ &m_completionOperator,
+ /*want function call =*/ editor->position() == endOfExpression);
+
+ Core::IFile *file = editor->file();
+ QString fileName = file->fileName();
+
+ int line = 0, column = 0;
+ edit->convertPosition(editor->position(), &line, &column);
+ // qDebug() << "line:" << line << "column:" << column;
+
+ ExpressionUnderCursor expressionUnderCursor;
+ QString expression;
+
+ if (m_completionOperator) {
+ QTextCursor tc(edit->document());
+ tc.setPosition(endOfExpression);
+ expression = expressionUnderCursor(tc);
+ if (m_completionOperator == T_LPAREN) {
+ if (expression.endsWith(QLatin1String("SIGNAL")))
+ m_completionOperator = T_SIGNAL;
+ else if (expression.endsWith(QLatin1String("SLOT")))
+ m_completionOperator = T_SLOT;
+ }
+ }
+
+ //if (! expression.isEmpty())
+ //qDebug() << "***** expression:" << expression;
+
+ if (Document::Ptr thisDocument = m_manager->document(fileName)) {
+ Symbol *symbol = thisDocument->findSymbolAt(line, column);
+
+ typeOfExpression.setDocuments(m_manager->documents());
+
+ QList<TypeOfExpression::Result> resolvedTypes = typeOfExpression(expression, thisDocument, symbol);
+ LookupContext context = typeOfExpression.lookupContext();
+
+ if (!typeOfExpression.expressionAST() && (! m_completionOperator ||
+ m_completionOperator == T_COLON_COLON)) {
+ if (!m_completionOperator) {
+ addKeywords();
+ addMacros(context);
+ }
+
+ const QList<Scope *> scopes = context.expand(context.visibleScopes());
+ foreach (Scope *scope, scopes) {
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ addCompletionItem(scope->symbolAt(i));
+ }
+ }
+ return m_startPosition;
+ }
+
+ // qDebug() << "found" << resolvedTypes.count() << "symbols for expression:" << expression;
+
+ if (resolvedTypes.isEmpty() && (m_completionOperator == T_SIGNAL ||
+ m_completionOperator == T_SLOT)) {
+ // Apply signal/slot completion on 'this'
+ expression = QLatin1String("this");
+ resolvedTypes = typeOfExpression(expression, thisDocument, symbol);
+ context = typeOfExpression.lookupContext();
+ }
+
+ if (! resolvedTypes.isEmpty()) {
+ FullySpecifiedType exprTy = resolvedTypes.first().first;
+
+ if (exprTy->isReferenceType())
+ exprTy = exprTy->asReferenceType()->elementType();
+
+ if (m_completionOperator == T_LPAREN && completeFunction(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) &&
+ completeMember(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } else if (m_completionOperator == T_COLON_COLON && completeScope(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } else if (m_completionOperator == T_SIGNAL && completeSignal(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } else if (m_completionOperator == T_SLOT && completeSlot(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ }
+ }
+ }
+
+ // nothing to do.
+ return -1;
+}
+
+bool CppCodeCompletion::completeFunction(FullySpecifiedType exprTy,
+ const QList<TypeOfExpression::Result> &resolvedTypes,
+ const LookupContext &)
+{
+ ConvertToCompletionItem toCompletionItem(this);
+ Overview o;
+ o.setShowReturnTypes(true);
+ o.setShowArgumentNames(true);
+
+ if (Class *klass = exprTy->asClass()) {
+ for (unsigned i = 0; i < klass->memberCount(); ++i) {
+ Symbol *member = klass->memberAt(i);
+ if (! member->type()->isFunction())
+ continue;
+ else if (! member->identity())
+ continue;
+ else if (! member->identity()->isEqualTo(klass->identity()))
+ continue;
+ if (TextEditor::CompletionItem item = toCompletionItem(member)) {
+ item.m_text = o(member->type(), member->name());
+ m_completions.append(item);
+ }
+ }
+ } else {
+ QSet<QString> signatures;
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ FullySpecifiedType ty = p.first;
+ if (Function *fun = ty->asFunction()) {
+ if (TextEditor::CompletionItem item = toCompletionItem(fun)) {
+ QString signature;
+ signature += overview.prettyName(fun->name());
+ signature += overview.prettyType(fun->type());
+ if (signatures.contains(signature))
+ continue;
+ signatures.insert(signature);
+
+ item.m_text = o(ty, fun->name());
+ m_completions.append(item);
+ }
+ }
+ }
+ }
+
+ return ! m_completions.isEmpty();
+}
+
+bool CppCodeCompletion::completeMember(FullySpecifiedType,
+ const QList<TypeOfExpression::Result> &results,
+ const LookupContext &context)
+{
+ Q_ASSERT(! results.isEmpty());
+
+ QList<Symbol *> classObjectCandidates;
+
+ TypeOfExpression::Result p = results.first();
+
+ if (m_completionOperator == T_ARROW) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType()) {
+ ResolveExpression resolveExpression(context);
+
+ Name *className = namedTy->name();
+ const QList<Symbol *> candidates =
+ context.resolveClass(className, context.visibleScopes(p));
+
+ foreach (Symbol *classObject, candidates) {
+ const QList<TypeOfExpression::Result> overloads =
+ resolveExpression.resolveArrowOperator(p, namedTy,
+ classObject->asClass());
+
+ foreach (TypeOfExpression::Result r, overloads) {
+ FullySpecifiedType ty = r.first;
+ Function *funTy = ty->asFunction();
+ if (! funTy)
+ continue;
+
+ ty = funTy->returnType();
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+ const QList<Symbol *> classes =
+ context.resolveClass(namedTy->name(),
+ context.visibleScopes(p));
+
+ foreach (Symbol *c, classes) {
+ if (! classObjectCandidates.contains(c))
+ classObjectCandidates.append(c);
+ }
+ }
+ }
+ }
+ }
+ } else if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+ const QList<Symbol *> classes =
+ context.resolveClass(namedTy->name(),
+ context.visibleScopes(p));
+
+ foreach (Symbol *c, classes) {
+ if (! classObjectCandidates.contains(c))
+ classObjectCandidates.append(c);
+ }
+ }
+ }
+ } else if (m_completionOperator == T_DOT) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ NamedType *namedTy = 0;
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ // Replace . with ->
+ int length = m_editor->position() - m_startPosition + 1;
+ m_editor->setCurPos(m_startPosition - 1);
+ m_editor->replace(length, QLatin1String("->"));
+ m_startPosition++;
+ namedTy = ptrTy->elementType()->asNamedType();
+ } else {
+ namedTy = ty->asNamedType();
+ if (! namedTy) {
+ Function *fun = ty->asFunction();
+ if (fun && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()))
+ namedTy = fun->returnType()->asNamedType();
+ }
+ }
+
+ if (namedTy) {
+ const QList<Symbol *> classes =
+ context.resolveClass(namedTy->name(),
+ context.visibleScopes(p));
+
+ foreach (Symbol *c, classes) {
+ if (! classObjectCandidates.contains(c))
+ classObjectCandidates.append(c);
+ }
+ }
+ }
+
+ completeClass(classObjectCandidates, context, /*static lookup = */ false);
+ if (! m_completions.isEmpty())
+ return true;
+
+ return false;
+}
+
+bool CppCodeCompletion::completeScope(FullySpecifiedType exprTy,
+ const QList<TypeOfExpression::Result> &resolvedTypes,
+ const LookupContext &context)
+{
+ // Search for a class or a namespace.
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ if (p.first->isClass() || p.first->isNamespace()) {
+ exprTy = p.first;
+ break;
+ }
+ }
+
+ if (exprTy->asNamespace()) {
+ QList<Symbol *> candidates;
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ if (Namespace *ns = p.first->asNamespace())
+ candidates.append(ns);
+ }
+ completeNamespace(candidates, context);
+ } else if (exprTy->isClass()) {
+ QList<Symbol *> candidates;
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ if (Class *k = p.first->asClass())
+ candidates.append(k);
+ }
+ completeClass(candidates, context);
+ }
+
+ return ! m_completions.isEmpty();
+}
+
+void CppCodeCompletion::addKeywords()
+{
+ // keyword completion items.
+ for (int i = T_FIRST_KEYWORD; i < T_FIRST_QT_KEYWORD; ++i) {
+ TextEditor::CompletionItem item(this);
+ item.m_text = QLatin1String(Token::name(i));
+ item.m_icon = m_icons.keywordIcon();
+ m_completions.append(item);
+ }
+}
+
+void CppCodeCompletion::addMacros(const LookupContext &context)
+{
+ // macro completion items.
+ QSet<QByteArray> macroNames;
+ QSet<QString> processed;
+ QList<QString> todo;
+ todo.append(context.thisDocument()->fileName());
+ while (! todo.isEmpty()) {
+ QString fn = todo.last();
+ todo.removeLast();
+ if (processed.contains(fn))
+ continue;
+ processed.insert(fn);
+ if (Document::Ptr doc = context.document(fn)) {
+ macroNames += doc->macroNames();
+ todo += doc->includedFiles();
+ }
+ }
+
+ foreach (const QByteArray macroName, macroNames) {
+ TextEditor::CompletionItem item(this);
+ item.m_text = QString::fromLatin1(macroName.constData(), macroName.length());
+ item.m_icon = m_icons.macroIcon();
+ m_completions.append(item);
+ }
+}
+
+void CppCodeCompletion::addCompletionItem(Symbol *symbol)
+{
+ ConvertToCompletionItem toCompletionItem(this);
+ if (TextEditor::CompletionItem item = toCompletionItem(symbol))
+ m_completions.append(item);
+}
+
+void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
+ const LookupContext &context)
+{
+ QList<Scope *> todo;
+ QList<Scope *> visibleScopes = context.visibleScopes();
+ foreach (Symbol *candidate, candidates) {
+ if (Namespace *ns = candidate->asNamespace())
+ context.expand(ns->members(), visibleScopes, &todo);
+ }
+
+ foreach (Scope *scope, todo) {
+ addCompletionItem(scope->owner());
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ addCompletionItem(scope->symbolAt(i));
+ }
+ }
+}
+
+void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates,
+ const LookupContext &context,
+ bool staticLookup)
+{
+ if (candidates.isEmpty())
+ return;
+
+ Class *klass = candidates.first()->asClass();
+
+ QList<Scope *> todo;
+ context.expand(klass->members(), context.visibleScopes(), &todo);
+
+ foreach (Scope *scope, todo) {
+ addCompletionItem(scope->owner());
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+
+ if (symbol->type().isFriend())
+ continue;
+ else if (! staticLookup && (symbol->isTypedef() ||
+ symbol->isEnum() ||
+ symbol->isClass()))
+ continue;
+
+ addCompletionItem(symbol);
+ }
+ }
+}
+
+bool CppCodeCompletion::completeQtMethod(CPlusPlus::FullySpecifiedType,
+ const QList<TypeOfExpression::Result> &results,
+ const LookupContext &context,
+ bool wantSignals)
+{
+ if (results.isEmpty())
+ return false;
+
+ ConvertToCompletionItem toCompletionItem(this);
+ Overview o;
+ o.setShowReturnTypes(false);
+ o.setShowArgumentNames(false);
+ o.setShowFunctionSignatures(true);
+
+ QSet<QString> signatures;
+ foreach (TypeOfExpression::Result p, results) {
+ FullySpecifiedType ty = p.first;
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+ if (PointerType *ptrTy = ty->asPointerType())
+ ty = ptrTy->elementType();
+ else
+ continue; // not a pointer or a reference to a pointer.
+
+ NamedType *namedTy = ty->asNamedType();
+ if (! namedTy) // not a class name.
+ continue;
+
+ const QList<Scope *> visibleScopes = context.visibleScopes(p);
+
+ const QList<Symbol *> classObjects =
+ context.resolveClass(namedTy->name(), visibleScopes);
+
+ if (classObjects.isEmpty())
+ continue;
+
+ Class *klass = classObjects.first()->asClass();
+
+ QList<Scope *> todo;
+ context.expand(klass->members(), visibleScopes, &todo);
+
+ foreach (Scope *scope, todo) {
+ if (! scope->isClassScope())
+ continue;
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *member = scope->symbolAt(i);
+ Function *fun = member->type()->asFunction();
+ if (! fun)
+ continue;
+ if (wantSignals && ! fun->isSignal())
+ continue;
+ else if (! wantSignals && ! fun->isSlot())
+ continue;
+ if (TextEditor::CompletionItem item = toCompletionItem(fun)) {
+ unsigned count = fun->argumentCount();
+ while (true) {
+ TextEditor::CompletionItem i = item;
+
+ QString signature;
+ signature += overview.prettyName(fun->name());
+ signature += QLatin1Char('(');
+ for (unsigned i = 0; i < count; ++i) {
+ Symbol *arg = fun->argumentAt(i);
+ if (i != 0)
+ signature += QLatin1Char(',');
+ signature += o.prettyType(arg->type());
+ }
+ signature += QLatin1Char(')');
+
+ const QByteArray normalized =
+ QMetaObject::normalizedSignature(signature.toLatin1());
+
+ signature = QString::fromLatin1(normalized, normalized.size());
+
+ if (! signatures.contains(signature)) {
+ signatures.insert(signature);
+
+ i.m_text = signature; // fix the completion item.
+ m_completions.append(i);
+ }
+
+ if (count && fun->argumentAt(count - 1)->asArgument()->hasInitializer())
+ --count;
+ else
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ! m_completions.isEmpty();
+}
+
+void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
+{
+ const int length = m_editor->position() - m_startPosition;
+
+ if (length == 0)
+ *completions = m_completions;
+ else if (length > 0) {
+ const QString key = m_editor->textAt(m_startPosition, length);
+
+ if (m_completionOperator != T_LPAREN) {
+ /*
+ * This code builds a regular expression in order to more intelligently match
+ * camel-case style. This means upper-case characters will be rewritten as follows:
+ *
+ * A => [a-z0-9_]*A (for any but the first capital letter)
+ *
+ * Meaning it allows any sequence of lower-case characters to preceed an
+ * upper-case character. So for example gAC matches getActionController.
+ *
+ * The match is case-sensitive as soon as at least one upper-case character is
+ * present.
+ */
+ QString keyRegExp;
+ keyRegExp += QLatin1Char('^');
+ bool first = true;
+ Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
+ foreach (const QChar &c, key) {
+ if (c.isLower()) {
+ keyRegExp.append(c);
+ } else if (c.isUpper()) {
+ sensitivity = Qt::CaseSensitive;
+ if (!first) {
+ keyRegExp.append("[a-z0-9_]*");
+ }
+ keyRegExp.append(c);
+ } else {
+ keyRegExp.append(QRegExp::escape(c));
+ }
+ first = false;
+ }
+ const QRegExp regExp(keyRegExp, sensitivity);
+
+ foreach (TextEditor::CompletionItem item, m_completions) {
+ if (regExp.indexIn(item.m_text) == 0) {
+ item.m_relevance = (key.length() > 0 &&
+ item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
+ (*completions) << item;
+ }
+ }
+ } else if (m_completionOperator == T_LPAREN ||
+ m_completionOperator == T_SIGNAL ||
+ m_completionOperator == T_SLOT) {
+ foreach (TextEditor::CompletionItem item, m_completions) {
+ if (item.m_text.startsWith(key, Qt::CaseInsensitive)) {
+ (*completions) << item;
+ }
+ }
+ }
+ }
+}
+
+void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
+{
+ Symbol *symbol = 0;
+
+ if (item.m_data.isValid())
+ symbol = item.m_data.value<Symbol *>();
+
+ // qDebug() << "*** complete symbol:" << symbol->fileName() << symbol->line();
+
+ if (m_completionOperator == T_LPAREN) {
+ if (symbol) {
+ Function *function = symbol->type()->asFunction();
+ Q_ASSERT(function != 0);
+
+ m_functionArgumentWidget = new FunctionArgumentWidget(m_core);
+ m_functionArgumentWidget->showFunctionHint(function);
+ }
+ } else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ QString toInsert = item.m_text;
+ toInsert += QLatin1Char(')');
+ // Insert the remainder of the name
+ int length = m_editor->position() - m_startPosition;
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(length, toInsert);
+ } else {
+ QString toInsert = item.m_text;
+
+ //qDebug() << "current symbol:" << overview.prettyName(symbol->name())
+ //<< overview.prettyType(symbol->type());
+
+ if (symbol) {
+ if (Function *function = symbol->type()->asFunction()) {
+ // If the member is a function, automatically place the opening parenthesis,
+ // except when it might take template parameters.
+ if (!function->returnType().isValid()
+ && (function->identity() && !function->identity()->isDestructorNameId())) {
+ // Don't insert any magic, since the user might have just wanted to select the class
+
+ } else if (function->templateParameterCount() != 0) {
+ // If there are no arguments, then we need the template specification
+ if (function->argumentCount() == 0) {
+ toInsert.append(QLatin1Char('<'));
+ }
+ } else {
+ toInsert.append(QLatin1Char('('));
+
+ // If the function takes no arguments, automatically place the closing parenthesis
+ if (function->argumentCount() == 0 || (function->argumentCount() == 1 &&
+ function->argumentAt(0)->type()->isVoidType())) {
+ toInsert.append(QLatin1Char(')'));
+
+ // If the function doesn't return anything, automatically place the semicolon,
+ // unless we're doing a scope completion (then it might be function definition).
+ if (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON) {
+ toInsert.append(QLatin1Char(';'));
+ }
+ }
+ }
+ }
+ }
+
+ // Insert the remainder of the name
+ int length = m_editor->position() - m_startPosition;
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(length, toInsert);
+ }
+}
+
+bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
+{
+ if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ return false;
+ } else if (completionItems.count() == 1) {
+ complete(completionItems.first());
+ return true;
+ } else if (m_completionOperator != T_LPAREN) {
+ // Compute common prefix
+ QString firstKey = completionItems.first().m_text;
+ QString lastKey = completionItems.last().m_text;
+ const int length = qMin(firstKey.length(), lastKey.length());
+ firstKey.truncate(length);
+ lastKey.truncate(length);
+
+ while (firstKey != lastKey) {
+ firstKey.chop(1);
+ lastKey.chop(1);
+ }
+
+ int typedLength = m_editor->position() - m_startPosition;
+ if (!firstKey.isEmpty() && firstKey.length() > typedLength) {
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(typedLength, firstKey);
+ }
+ }
+
+ return false;
+}
+
+void CppCodeCompletion::cleanup()
+{
+ m_completions.clear();
+}
+
+int CppCodeCompletion::findStartOfName(const TextEditor::ITextEditor *editor)
+{
+ int pos = editor->position();
+ QChar chr;
+
+ // Skip to the start of a name
+ do {
+ chr = editor->characterAt(--pos);
+ } while (chr.isLetterOrNumber() || chr == QLatin1Char('_'));
+
+ return pos + 1;
+}
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
new file mode 100644
index 0000000000..4977393521
--- /dev/null
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPCODECOMPLETION_H
+#define CPPCODECOMPLETION_H
+
+// Qt
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+// C++ front-end
+#include <ASTfwd.h>
+#include <FullySpecifiedType.h>
+#include <cplusplus/Icons.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/TypeOfExpression.h>
+
+// Qt Creator
+#include <texteditor/icompletioncollector.h>
+
+namespace Core {
+class ICore;
+}
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+class FunctionArgumentWidget;
+
+class CppCodeCompletion : public TextEditor::ICompletionCollector
+{
+ Q_OBJECT
+public:
+ CppCodeCompletion(CppModelManager *manager, Core::ICore *core);
+
+ bool triggersCompletion(TextEditor::ITextEditable *editor);
+ int startCompletion(TextEditor::ITextEditable *editor);
+ void completions(QList<TextEditor::CompletionItem> *completions);
+
+ void complete(const TextEditor::CompletionItem &item);
+ bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
+ void cleanup();
+
+ QIcon iconForSymbol(CPlusPlus::Symbol *symbol) const;
+
+private:
+ void addKeywords();
+ void addMacros(const CPlusPlus::LookupContext &context);
+ void addCompletionItem(CPlusPlus::Symbol *symbol);
+
+ bool completeFunction(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context);
+
+ bool completeMember(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context);
+
+ bool completeScope(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context);
+
+ void completeNamespace(const QList<CPlusPlus::Symbol *> &candidates,
+ const CPlusPlus::LookupContext &context);
+
+ void completeClass(const QList<CPlusPlus::Symbol *> &candidates,
+ const CPlusPlus::LookupContext &context,
+ bool staticLookup = true);
+
+ bool completeQtMethod(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context,
+ bool wantSignals);
+
+ bool completeSignal(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &results,
+ const CPlusPlus::LookupContext &context)
+ { return completeQtMethod(exprTy, results, context, true); }
+
+ bool completeSlot(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &results,
+ const CPlusPlus::LookupContext &context)
+ { return completeQtMethod(exprTy, results, context, false); }
+
+ static int findStartOfName(const TextEditor::ITextEditor *editor);
+
+ QList<TextEditor::CompletionItem> m_completions;
+
+ TextEditor::ITextEditable *m_editor;
+ int m_startPosition; // Position of the cursor from which completion started
+
+ Core::ICore *m_core;
+ CppModelManager *m_manager;
+
+ bool m_forcedCompletion;
+
+ CPlusPlus::Icons m_icons;
+ CPlusPlus::Overview overview;
+ CPlusPlus::TypeOfExpression typeOfExpression;
+
+ unsigned m_completionOperator;
+
+ QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+Q_DECLARE_METATYPE(CPlusPlus::Symbol *)
+
+#endif // CPPCODECOMPLETION_H
diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp
new file mode 100644
index 0000000000..dc9bb96661
--- /dev/null
+++ b/src/plugins/cpptools/cpphoverhandler.cpp
@@ -0,0 +1,243 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cpphoverhandler.h"
+#include "cppmodelmanager.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <texteditor/itexteditor.h>
+#include <debugger/debuggerconstants.h>
+
+#include <CoreTypes.h>
+#include <FullySpecifiedType.h>
+#include <Literals.h>
+#include <Names.h>
+#include <Scope.h>
+#include <Symbol.h>
+#include <Symbols.h>
+#include <cplusplus/ExpressionUnderCursor.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/TypeOfExpression.h>
+
+#include <QtGui/QToolTip>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+#include <QtHelp/QHelpEngineCore>
+#include <QtCore/QtCore>
+
+using namespace CppTools::Internal;
+
+CppHoverHandler::CppHoverHandler(CppModelManager *manager, QObject *parent)
+ : QObject(parent), m_manager(manager)
+{
+ QFileInfo fi(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings()->fileName());
+ m_helpEngine = new QHelpEngineCore(fi.absolutePath()
+ + QLatin1String("/helpcollection.qhc"), this);
+ //m_helpEngine->setAutoSaveFilter(false);
+ m_helpEngine->setupData();
+ m_helpEngine->setCurrentFilter(tr("Unfiltered"));
+}
+
+void CppHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos)
+{
+ updateHelpIdAndTooltip(editor, pos);
+}
+
+void CppHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos)
+{
+ const int dbgcontext = m_manager->core()->
+ uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_GDBDEBUGGER);
+
+ if (m_manager->core()->hasContext(dbgcontext))
+ return;
+
+ if (! editor)
+ return;
+
+ updateHelpIdAndTooltip(editor, pos);
+
+ if (m_toolTip.isEmpty())
+ QToolTip::hideText();
+ else {
+ const QPoint pnt = point - QPoint(0,
+#ifdef Q_WS_WIN
+ 24
+#else
+ 16
+#endif
+ );
+
+ QToolTip::showText(pnt, m_toolTip);
+ }
+}
+
+static QString buildHelpId(const CPlusPlus::FullySpecifiedType &type,
+ const CPlusPlus::Symbol *symbol)
+{
+ using namespace CPlusPlus;
+
+ Name *name = 0;
+ Scope *scope = 0;
+
+ if (const Function *f = type->asFunction()) {
+ name = f->name();
+ scope = f->scope();
+ } else if (const Class *c = type->asClass()) {
+ name = c->name();
+ scope = c->scope();
+ } else if (const Enum *e = type->asEnum()) {
+ name = e->name();
+ scope = e->scope();
+ } else if (const NamedType *t = type->asNamedType()) {
+ name = t->name();
+ } else if (const Declaration *d = symbol->asDeclaration()) {
+ if (d->scope() && d->scope()->owner()->isEnum()) {
+ name = d->name();
+ scope = d->scope();
+ }
+ }
+
+ Overview overview;
+ overview.setShowArgumentNames(false);
+ overview.setShowReturnTypes(false);
+
+ QStringList qualifiedNames;
+ qualifiedNames.prepend(overview.prettyName(name));
+
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner() && scope->owner()->name() && !scope->isEnumScope()) {
+ Name *name = scope->owner()->name();
+ Identifier *id = 0;
+ if (NameId *nameId = name->asNameId()) {
+ id = nameId->identifier();
+ } else if (TemplateNameId *nameId = name->asTemplateNameId()) {
+ id = nameId->identifier();
+ }
+ if (id)
+ qualifiedNames.prepend(QString::fromLatin1(id->chars(), id->size()));
+ }
+ }
+
+ return qualifiedNames.join(QLatin1String("::"));
+}
+
+void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos)
+{
+ using namespace CPlusPlus;
+
+ m_helpId.clear();
+ m_toolTip.clear();
+
+ QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(editor->widget());
+ if (!edit)
+ return;
+
+ QTextCursor tc(edit->document());
+ tc.setPosition(pos);
+
+ const int lineNumber = tc.block().blockNumber() + 1;
+
+ QString fileName = editor->file()->fileName();
+ Document::Ptr doc = m_manager->document(fileName);
+ if (doc) {
+ foreach (Document::DiagnosticMessage m, doc->diagnosticMessages()) {
+ if (m.line() == lineNumber) {
+ m_toolTip = m.text();
+ break;
+ }
+ }
+ }
+
+ if (m_toolTip.isEmpty()) {
+ // Move to the end of a qualified name
+ bool stop = false;
+ while (!stop) {
+ const QChar ch = editor->characterAt(tc.position());
+ if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
+ tc.setPosition(tc.position() + 1);
+ else if (ch == QLatin1Char(':') && editor->characterAt(tc.position() + 1) == QLatin1Char(':')) {
+ tc.setPosition(tc.position() + 2);
+ } else {
+ stop = true;
+ }
+ }
+
+ // Fetch the expression's code.
+ ExpressionUnderCursor expressionUnderCursor;
+ const QString expression = expressionUnderCursor(tc);
+
+ if (doc) {
+ // 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);
+
+ TypeOfExpression typeOfExpression;
+ typeOfExpression.setDocuments(m_manager->documents());
+ QList<TypeOfExpression::Result> types = typeOfExpression(expression, doc, lastSymbol);
+
+ if (!types.isEmpty()) {
+ FullySpecifiedType firstType = types.first().first;
+ FullySpecifiedType docType = firstType;
+
+ if (const PointerType *pt = firstType->asPointerType()) {
+ docType = pt->elementType();
+ } else if (const ReferenceType *rt = firstType->asReferenceType()) {
+ docType = rt->elementType();
+ }
+
+
+ m_helpId = buildHelpId(docType, types.first().second);
+ QString displayName = buildHelpId(firstType, types.first().second);
+
+ if (!firstType->isClass() && !firstType->isNamedType()) {
+ Overview overview;
+ overview.setShowArgumentNames(true);
+ overview.setShowReturnTypes(true);
+ m_toolTip = overview.prettyType(firstType, displayName);
+ } else {
+ m_toolTip = m_helpId;
+ }
+ }
+ }
+ }
+
+ if (!m_helpId.isEmpty() && !m_helpEngine->linksForIdentifier(m_helpId).isEmpty()) {
+ m_toolTip = QString(QLatin1String("<table><tr><td valign=middle><nobr>%1</td>"
+ "<td><img src=\":/cpptools/images/f1.svg\"></td></tr></table>")).arg(Qt::escape(m_toolTip));
+ editor->setContextHelpId(m_helpId);
+ } else if (!m_toolTip.isEmpty()) {
+ m_toolTip = QString(QLatin1String("<nobr>%1")).arg(Qt::escape(m_toolTip));
+ }
+}
diff --git a/src/plugins/cpptools/cpphoverhandler.h b/src/plugins/cpptools/cpphoverhandler.h
new file mode 100644
index 0000000000..ca828c35db
--- /dev/null
+++ b/src/plugins/cpptools/cpphoverhandler.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPHOVERHANDLER_H
+#define CPPHOVERHANDLER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+
+QT_BEGIN_NAMESPACE
+class QHelpEngineCore;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+
+class CppHoverHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ CppHoverHandler(CppModelManager *manager, QObject *parent);
+
+public slots:
+ void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos);
+ void updateContextHelpId(TextEditor::ITextEditor *editor, int pos);
+
+private:
+ void updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos);
+
+ CppModelManager *m_manager;
+ QHelpEngineCore *m_helpEngine;
+ QString m_helpId;
+ QString m_toolTip;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+#endif // CPPHOVERHANDLER_H
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
new file mode 100644
index 0000000000..6ec5391267
--- /dev/null
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -0,0 +1,740 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#define _SCL_SECURE_NO_WARNINGS 1
+#include "pp.h"
+
+#include "cppmodelmanager.h"
+#include "cpphoverhandler.h"
+#include "cpptoolsconstants.h"
+#include "cpptoolseditorsupport.h"
+
+#include <qtconcurrent/runextensions.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/session.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+
+#include <TranslationUnit.h>
+#include <Semantic.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <Names.h>
+#include <NameVisitor.h>
+#include <TypeVisitor.h>
+#include <Lexer.h>
+#include <Token.h>
+
+#include <QPlainTextEdit>
+#include <QTime>
+#include <QDebug>
+
+using namespace CPlusPlus;
+
+namespace CppTools {
+namespace Internal {
+
+static const char pp_configuration_file[] = "<configuration>";
+
+static const char pp_configuration[] =
+ "# 1 \"<configuration>\"\n"
+ "#define __GNUC_MINOR__ 0\n"
+ "#define __GNUC__ 4\n"
+ "#define __GNUG__ 4\n"
+ "#define __STDC_HOSTED__ 1\n"
+ "#define __VERSION__ \"4.0.1 (fake)\"\n"
+ "#define __cplusplus 1\n"
+
+ "#define __extension__\n"
+ "#define __context__\n"
+ "#define __range__\n"
+ "#define __asm(a...)\n"
+ "#define __asm__(a...)\n"
+ "#define restrict\n"
+ "#define __restrict\n"
+
+ // ### add macros for win32
+ "#define __cdecl\n"
+ "#define QT_WA(x) x\n"
+ "#define API\n"
+ "#define WINAPI\n"
+ "#define CALLBACK\n"
+ "#define STDMETHODCALLTYPE\n"
+ "#define __RPC_FAR\n"
+ "#define APIENTRY\n"
+ "#define __declspec(a)\n"
+ "#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method\n";
+
+class CppPreprocessor: public rpp::Client
+{
+public:
+ CppPreprocessor(QPointer<CppModelManager> modelManager)
+ : m_modelManager(modelManager),
+ m_documents(modelManager->documents()),
+ m_proc(this, env)
+ { }
+
+ void setWorkingCopy(const QMap<QString, QByteArray> &workingCopy)
+ { m_workingCopy = workingCopy; }
+
+ void setIncludePaths(const QStringList &includePaths)
+ { m_includePaths = includePaths; }
+
+ void setFrameworkPaths(const QStringList &frameworkPaths)
+ { m_frameworkPaths = frameworkPaths; }
+
+ void addIncludePath(const QString &path)
+ { m_includePaths.append(path); }
+
+ void setProjectFiles(const QStringList &files)
+ { m_projectFiles = files; }
+
+ void operator()(QString &fileName)
+ { sourceNeeded(fileName, IncludeGlobal); }
+
+protected:
+ bool includeFile(const QString &absoluteFilePath, QByteArray *result)
+ {
+ if (absoluteFilePath.isEmpty() || m_included.contains(absoluteFilePath)) {
+ return true;
+ }
+
+ if (m_workingCopy.contains(absoluteFilePath)) {
+ m_included.insert(absoluteFilePath);
+ *result = m_workingCopy.value(absoluteFilePath);
+ return true;
+ }
+
+ QFileInfo fileInfo(absoluteFilePath);
+ if (! fileInfo.isFile())
+ return false;
+
+ QFile file(absoluteFilePath);
+ if (file.open(QFile::ReadOnly)) {
+ m_included.insert(absoluteFilePath);
+ QTextStream stream(&file);
+ const QString contents = stream.readAll();
+ *result = contents.toUtf8();
+ file.close();
+ return true;
+ }
+
+ return false;
+ }
+
+ QByteArray tryIncludeFile(QString &fileName, IncludeType type)
+ {
+ QFileInfo fileInfo(fileName);
+ if (fileName == QLatin1String(pp_configuration_file) || fileInfo.isAbsolute()) {
+ QByteArray contents;
+ includeFile(fileName, &contents);
+ return contents;
+ }
+
+ if (type == IncludeLocal && m_currentDoc) {
+ QFileInfo currentFileInfo(m_currentDoc->fileName());
+ QString path = currentFileInfo.absolutePath();
+ path += QLatin1Char('/');
+ path += fileName;
+ path = QDir::cleanPath(path);
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+
+ foreach (const QString &includePath, m_includePaths) {
+ QString path = includePath;
+ path += QLatin1Char('/');
+ path += fileName;
+ path = QDir::cleanPath(path);
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+
+ // look in the system include paths
+ foreach (const QString &includePath, m_systemIncludePaths) {
+ QString path = includePath;
+ path += QLatin1Char('/');
+ path += fileName;
+ path = QDir::cleanPath(path);
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+
+ int index = fileName.indexOf(QLatin1Char('/'));
+ if (index != -1) {
+ QString frameworkName = fileName.left(index);
+ QString name = fileName.mid(index + 1);
+
+ foreach (const QString &frameworkPath, m_frameworkPaths) {
+ QString path = frameworkPath;
+ path += QLatin1Char('/');
+ path += frameworkName;
+ path += QLatin1String(".framework/Headers/");
+ path += name;
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+ }
+
+ QString path = fileName;
+ if (path.at(0) != QLatin1Char('/'))
+ path.prepend(QLatin1Char('/'));
+
+ foreach (const QString &projectFile, m_projectFiles) {
+ if (projectFile.endsWith(path)) {
+ fileName = projectFile;
+ QByteArray contents;
+ includeFile(fileName, &contents);
+ return contents;
+ }
+ }
+
+ //qDebug() << "**** file" << fileName << "not found!";
+ return QByteArray();
+ }
+
+ virtual void macroAdded(const QByteArray &macroName, const QByteArray &macroText)
+ {
+ if (! m_currentDoc)
+ return;
+
+ m_currentDoc->appendMacro(macroName, macroText);
+ }
+
+ void mergeEnvironment(Document::Ptr doc)
+ {
+ QSet<QString> processed;
+ mergeEnvironment(doc, &processed);
+ }
+
+ void mergeEnvironment(Document::Ptr doc, QSet<QString> *processed)
+ {
+ if (! doc)
+ return;
+
+ const QString fn = doc->fileName();
+
+ if (processed->contains(fn))
+ return;
+
+ processed->insert(fn);
+
+ foreach (QString includedFile, doc->includedFiles())
+ mergeEnvironment(m_documents.value(includedFile), processed);
+
+ const QByteArray macros = doc->definedMacros();
+ QByteArray localFileName = doc->fileName().toUtf8();
+
+ QByteArray dummy;
+ m_proc(localFileName, macros, &dummy);
+ }
+
+ virtual void startSkippingBlocks(unsigned offset)
+ {
+ //qDebug() << "start skipping blocks:" << offset;
+ if (m_currentDoc)
+ m_currentDoc->startSkippingBlocks(offset);
+ }
+
+ virtual void stopSkippingBlocks(unsigned offset)
+ {
+ //qDebug() << "stop skipping blocks:" << offset;
+ if (m_currentDoc)
+ m_currentDoc->stopSkippingBlocks(offset);
+ }
+
+ virtual void sourceNeeded(QString &fileName, IncludeType type)
+ {
+ if (fileName.isEmpty())
+ return;
+
+ QByteArray contents = tryIncludeFile(fileName, type);
+
+ if (m_currentDoc) {
+ m_currentDoc->addIncludeFile(fileName);
+ if (contents.isEmpty() && ! QFileInfo(fileName).isAbsolute()) {
+ QString msg;
+ msg += fileName;
+ msg += QLatin1String(": No such file or directory");
+ Document::DiagnosticMessage d(Document::DiagnosticMessage::Warning,
+ m_currentDoc->fileName(),
+ env.currentLine, /*column = */ 0,
+ msg);
+ m_currentDoc->addDiagnosticMessage(d);
+ //qWarning() << "file not found:" << fileName << m_currentDoc->fileName() << env.current_line;
+ }
+ }
+
+ if (! contents.isEmpty()) {
+ Document::Ptr cachedDoc = m_documents.value(fileName);
+ if (cachedDoc && m_currentDoc) {
+ mergeEnvironment(cachedDoc);
+ } else {
+ Document::Ptr previousDoc = switchDocument(Document::create(fileName));
+
+ const QByteArray previousFile = env.current_file;
+ const unsigned previousLine = env.currentLine;
+
+ env.current_file = QByteArray(m_currentDoc->translationUnit()->fileName(),
+ m_currentDoc->translationUnit()->fileNameLength());
+
+ QByteArray preprocessedCode;
+ m_proc(contents, &preprocessedCode);
+ //qDebug() << preprocessedCode;
+
+ env.current_file = previousFile;
+ env.currentLine = previousLine;
+
+ m_currentDoc->setSource(preprocessedCode);
+ m_currentDoc->parse();
+ m_currentDoc->check();
+ m_currentDoc->releaseTranslationUnit(); // release the AST and the token stream.
+
+ if (m_modelManager)
+ m_modelManager->emitDocumentUpdated(m_currentDoc);
+ (void) switchDocument(previousDoc);
+ }
+ }
+ }
+
+ Document::Ptr switchDocument(Document::Ptr doc)
+ {
+ Document::Ptr previousDoc = m_currentDoc;
+ m_currentDoc = doc;
+ return previousDoc;
+ }
+
+private:
+ QPointer<CppModelManager> m_modelManager;
+ CppModelManager::DocumentTable m_documents;
+ rpp::Environment env;
+ rpp::pp m_proc;
+ QStringList m_includePaths;
+ QStringList m_systemIncludePaths;
+ QMap<QString, QByteArray> m_workingCopy;
+ QStringList m_projectFiles;
+ QStringList m_frameworkPaths;
+ QSet<QString> m_included;
+ Document::Ptr m_currentDoc;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+
+using namespace CppTools;
+using namespace CppTools::Internal;
+
+/*!
+ \class CppTools::CppModelManager
+ \brief The CppModelManager keeps track of one CppCodeModel instance
+ for each project and all related CppCodeModelPart instances.
+
+ It also takes care of updating the code models when C++ files are
+ modified within Workbench.
+*/
+
+CppModelManager::CppModelManager(QObject *parent) :
+ CppModelManagerInterface(parent),
+ m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>())
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()
+ ->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+
+ Q_ASSERT(m_projectExplorer);
+
+ ProjectExplorer::SessionManager *session = m_projectExplorer->session();
+ Q_ASSERT(session != 0);
+
+ connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project *)),
+ this, SLOT(onAboutToRemoveProject(ProjectExplorer::Project *)));
+
+ connect(session, SIGNAL(sessionUnloaded()),
+ this, SLOT(onSessionUnloaded()));
+
+ qRegisterMetaType<CPlusPlus::Document::Ptr>("CPlusPlus::Document::Ptr");
+
+ // thread connections
+ connect(this, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
+ this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
+
+ m_hoverHandler = new CppHoverHandler(this, this);
+
+ // Listen for editor closed and opened events so that we can keep track of changing files
+ connect(m_core->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
+ this, SLOT(editorOpened(Core::IEditor *)));
+
+ connect(m_core->editorManager(), SIGNAL(editorAboutToClose(Core::IEditor *)),
+ this, SLOT(editorAboutToClose(Core::IEditor *)));
+}
+
+CppModelManager::~CppModelManager()
+{ }
+
+Document::Ptr CppModelManager::document(const QString &fileName)
+{ return m_documents.value(fileName); }
+
+CppModelManager::DocumentTable CppModelManager::documents()
+{ return m_documents; }
+
+QStringList CppModelManager::projectFiles() const
+{
+ QStringList files;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ files += pinfo.sourceFiles;
+ }
+ return files;
+}
+
+QStringList CppModelManager::includePaths() const
+{
+ QStringList includePaths;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ includePaths += pinfo.includePaths;
+ }
+ return includePaths;
+}
+
+QStringList CppModelManager::frameworkPaths() const
+{
+ QStringList frameworkPaths;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ frameworkPaths += pinfo.frameworkPaths;
+ }
+ return frameworkPaths;
+}
+
+QByteArray CppModelManager::definedMacros() const
+{
+ QByteArray macros;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ macros += pinfo.defines;
+ }
+ return macros;
+}
+
+QMap<QString, QByteArray> CppModelManager::buildWorkingCopyList() const
+{
+ QMap<QString, QByteArray> workingCopy;
+ QMapIterator<TextEditor::ITextEditor *, CppEditorSupport *> it(m_editorSupport);
+ while (it.hasNext()) {
+ it.next();
+ TextEditor::ITextEditor *textEditor = it.key();
+ CppEditorSupport *editorSupport = it.value();
+ QString fileName = textEditor->file()->fileName();
+ workingCopy[fileName] = editorSupport->contents().toUtf8();
+ }
+
+ // add the project configuration file
+ QByteArray conf(pp_configuration);
+ conf += definedMacros();
+ workingCopy[pp_configuration_file] = conf;
+
+ return workingCopy;
+}
+
+void CppModelManager::updateSourceFiles(const QStringList &sourceFiles)
+{ (void) refreshSourceFiles(sourceFiles); }
+
+CppModelManager::ProjectInfo *CppModelManager::projectInfo(ProjectExplorer::Project *project)
+{ return &m_projects[project]; }
+
+QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
+{
+ if (qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) {
+ const QMap<QString, QByteArray> workingCopy = buildWorkingCopyList();
+
+ QFuture<void> result = QtConcurrent::run(&CppModelManager::parse, this,
+ sourceFiles, workingCopy);
+
+ if (sourceFiles.count() > 1) {
+ m_core->progressManager()->addTask(result, tr("Indexing"),
+ CppTools::Constants::TASK_INDEX,
+ Core::ProgressManagerInterface::CloseOnSuccess);
+ }
+ return result;
+ }
+ return QFuture<void>();
+}
+
+/*!
+ \fn void CppModelManager::editorOpened(Core::IEditor *editor)
+ \brief If a C++ editor is opened, the model manager listens to content changes
+ in order to update the CppCodeModel accordingly. It also updates the
+ CppCodeModel for the first time with this editor.
+
+ \sa void CppModelManager::editorContentsChanged()
+ */
+void CppModelManager::editorOpened(Core::IEditor *editor)
+{
+ if (isCppEditor(editor)) {
+ TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ Q_ASSERT(textEditor != 0);
+
+ CppEditorSupport *editorSupport = new CppEditorSupport(this);
+ editorSupport->setTextEditor(textEditor);
+ m_editorSupport[textEditor] = editorSupport;
+
+ // ### move in CppEditorSupport
+ connect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*, QPoint, int)),
+ m_hoverHandler, SLOT(showToolTip(TextEditor::ITextEditor*, QPoint, int)));
+
+ // ### move in CppEditorSupport
+ connect(editor, SIGNAL(contextHelpIdRequested(TextEditor::ITextEditor*, int)),
+ m_hoverHandler, SLOT(updateContextHelpId(TextEditor::ITextEditor*, int)));
+ }
+}
+
+void CppModelManager::editorAboutToClose(Core::IEditor *editor)
+{
+ if (isCppEditor(editor)) {
+ TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ Q_ASSERT(textEditor != 0);
+
+ CppEditorSupport *editorSupport = m_editorSupport.value(textEditor);
+ m_editorSupport.remove(textEditor);
+ delete editorSupport;
+ }
+}
+
+bool CppModelManager::isCppEditor(Core::IEditor *editor) const
+{
+ Core::UniqueIDManager *uidm = m_core->uniqueIDManager();
+ const int uid = uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
+ return editor->context().contains(uid);
+}
+
+void CppModelManager::emitDocumentUpdated(Document::Ptr doc)
+{ emit documentUpdated(doc); }
+
+void CppModelManager::onDocumentUpdated(Document::Ptr doc)
+{
+ const QString fileName = doc->fileName();
+ m_documents[fileName] = doc;
+ QList<Core::IEditor *> openedEditors = m_core->editorManager()->openedEditors();
+ foreach (Core::IEditor *editor, openedEditors) {
+ if (editor->file()->fileName() == fileName) {
+ TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ if (! textEditor)
+ continue;
+
+ TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(textEditor->widget());
+ if (! ed)
+ continue;
+
+ QList<TextEditor::BaseTextEditor::BlockRange> blockRanges;
+
+ foreach (const Document::Block block, doc->skippedBlocks()) {
+ blockRanges.append(TextEditor::BaseTextEditor::BlockRange(block.begin(), block.end()));
+ }
+ ed->setIfdefedOutBlocks(blockRanges);
+
+ QList<QTextEdit::ExtraSelection> selections;
+
+ // set up the format for the errors
+ QTextCharFormat errorFormat;
+ errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ errorFormat.setUnderlineColor(Qt::red);
+
+ // set up the format for the warnings.
+ QTextCharFormat warningFormat;
+ warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ warningFormat.setUnderlineColor(Qt::darkYellow);
+
+ QSet<int> lines;
+ foreach (const Document::DiagnosticMessage m, doc->diagnosticMessages()) {
+ if (m.fileName() != fileName)
+ continue;
+ else if (lines.contains(m.line()))
+ continue;
+ else if (lines.size() == MAX_SELECTION_COUNT)
+ break; // we're done.
+
+ lines.insert(m.line());
+
+ QTextEdit::ExtraSelection sel;
+ if (m.isWarning())
+ sel.format = warningFormat;
+ else
+ sel.format = errorFormat;
+
+ QTextCursor c(ed->document()->findBlockByNumber(m.line() - 1));
+ const QString text = c.block().text();
+ for (int i = 0; i < text.size(); ++i) {
+ if (! text.at(i).isSpace()) {
+ c.setPosition(c.position() + i);
+ break;
+ }
+ }
+ c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ sel.cursor = c;
+ selections.append(sel);
+ }
+ ed->setExtraExtraSelections(selections);
+ break;
+ }
+ }
+}
+
+void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project)
+{
+ m_projects.remove(project);
+ GC();
+}
+
+void CppModelManager::onSessionUnloaded()
+{
+ if (m_core->progressManager())
+ m_core->progressManager()->cancelTasks(CppTools::Constants::TASK_INDEX);
+}
+
+void CppModelManager::parse(QFutureInterface<void> &future,
+ CppModelManager *model,
+ QStringList files,
+ QMap<QString, QByteArray> workingCopy)
+{
+ // Change the priority of the background parser thread to idle.
+ QThread::currentThread()->setPriority(QThread::IdlePriority);
+
+ future.setProgressRange(0, files.size());
+
+ CppPreprocessor preproc(model);
+ preproc.setWorkingCopy(workingCopy);
+ preproc.setProjectFiles(model->projectFiles());
+ preproc.setIncludePaths(model->includePaths());
+ preproc.setFrameworkPaths(model->frameworkPaths());
+
+ QString conf = QLatin1String(pp_configuration_file);
+ (void) preproc(conf);
+
+ const int STEP = 10;
+
+ for (int i = 0; i < files.size(); ++i) {
+ if (future.isPaused())
+ future.waitForResume();
+
+ if (future.isCanceled())
+ break;
+
+ future.setProgressValue(i);
+
+#ifdef CPPTOOLS_DEBUG_PARSING_TIME
+ QTime tm;
+ tm.start();
+#endif
+
+ QString fileName = files.at(i);
+ preproc(fileName);
+
+ if (! (i % STEP)) // Yields execution of the current thread.
+ QThread::yieldCurrentThread();
+
+#ifdef CPPTOOLS_DEBUG_PARSING_TIME
+ qDebug() << fileName << "parsed in:" << tm.elapsed();
+#endif
+ }
+
+ // Restore the previous thread priority.
+ QThread::currentThread()->setPriority(QThread::NormalPriority);
+}
+
+void CppModelManager::GC()
+{
+ DocumentTable documents = m_documents;
+
+ QSet<QString> processed;
+ QStringList todo = m_projectFiles;
+
+ while (! todo.isEmpty()) {
+ QString fn = todo.last();
+ todo.removeLast();
+
+ if (processed.contains(fn))
+ continue;
+
+ processed.insert(fn);
+
+ if (Document::Ptr doc = documents.value(fn)) {
+ todo += doc->includedFiles();
+ }
+ }
+
+ QStringList removedFiles;
+ QMutableMapIterator<QString, Document::Ptr> it(documents);
+ while (it.hasNext()) {
+ it.next();
+ const QString fn = it.key();
+ if (! processed.contains(fn)) {
+ removedFiles.append(fn);
+ it.remove();
+ }
+ }
+
+ emit aboutToRemoveFiles(removedFiles);
+ m_documents = documents;
+}
+
+
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
new file mode 100644
index 0000000000..bed882f9cd
--- /dev/null
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPMODELMANAGER_H
+#define CPPMODELMANAGER_H
+
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <projectexplorer/project.h>
+#include <cplusplus/CppDocument.h>
+
+#include <QMap>
+#include <QFutureInterface>
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace ProjectExplorer {
+class ProjectExplorerPlugin;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppEditorSupport;
+class CppHoverHandler;
+
+class CppModelManager : public CppModelManagerInterface
+{
+ Q_OBJECT
+
+public:
+ CppModelManager(QObject *parent);
+ virtual ~CppModelManager();
+
+ virtual void updateSourceFiles(const QStringList &sourceFiles);
+ virtual ProjectInfo *projectInfo(ProjectExplorer::Project *project);
+ virtual CPlusPlus::Document::Ptr document(const QString &fileName);
+ virtual DocumentTable documents();
+ virtual void GC();
+
+ QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
+
+ inline Core::ICore *core() const { return m_core; }
+
+ bool isCppEditor(Core::IEditor *editor) const; // ### private
+
+ void emitDocumentUpdated(CPlusPlus::Document::Ptr doc);
+
+Q_SIGNALS:
+ void projectPathChanged(const QString &projectPath);
+
+ void documentUpdated(CPlusPlus::Document::Ptr doc);
+ void aboutToRemoveFiles(const QStringList &files);
+
+public Q_SLOTS:
+ void editorOpened(Core::IEditor *editor);
+ void editorAboutToClose(Core::IEditor *editor);
+
+private Q_SLOTS:
+ // this should be executed in the GUI thread.
+ void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
+ void onAboutToRemoveProject(ProjectExplorer::Project *project);
+ void onSessionUnloaded();
+
+private:
+ QMap<QString, QByteArray> buildWorkingCopyList() const;
+ QStringList projectFiles() const;
+ QStringList includePaths() const;
+ QStringList frameworkPaths() const;
+ QByteArray definedMacros() const;
+
+ static void parse(QFutureInterface<void> &future,
+ CppModelManager *model,
+ QStringList files,
+ QMap<QString, QByteArray> workingCopy);
+
+private:
+ Core::ICore *m_core;
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ CppHoverHandler *m_hoverHandler;
+ DocumentTable m_documents;
+
+ // List of available source files
+ QStringList m_projectFiles;
+
+ // editor integration
+ QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport;
+
+ // project integration
+ QMap<ProjectExplorer::Project *, ProjectInfo> m_projects;
+
+ enum {
+ MAX_SELECTION_COUNT = 5
+ };
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+#endif // CPPMODELMANAGER_H
diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h
new file mode 100644
index 0000000000..3b93c346c5
--- /dev/null
+++ b/src/plugins/cpptools/cppmodelmanagerinterface.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPMODELMANAGERINTERFACE_H
+#define CPPMODELMANAGERINTERFACE_H
+
+#include <cpptools/cpptools_global.h>
+#include <cplusplus/CppDocument.h>
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+
+namespace ProjectExplorer {
+ class Project;
+}
+
+namespace CppTools {
+
+class CPPTOOLS_EXPORT CppModelManagerInterface
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ typedef QMap<QString, CPlusPlus::Document::Ptr> DocumentTable;
+
+ struct ProjectInfo
+ {
+ QString projectPath;
+ QByteArray defines;
+ QStringList sourceFiles;
+ QStringList includePaths;
+ QStringList frameworkPaths;
+ };
+
+public:
+ CppModelManagerInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~CppModelManagerInterface() {}
+
+ virtual void GC() = 0;
+ virtual void updateSourceFiles(const QStringList &sourceFiles) = 0;
+
+ virtual CPlusPlus::Document::Ptr document(const QString &fileName) = 0;
+ virtual DocumentTable documents() = 0;
+
+ virtual ProjectInfo *projectInfo(ProjectExplorer::Project *project) = 0;
+};
+
+} // namespace CppTools
+
+#endif // CPPMODELMANAGERINTERFACE_H
diff --git a/src/plugins/cpptools/cppquickopenfilter.cpp b/src/plugins/cpptools/cppquickopenfilter.cpp
new file mode 100644
index 0000000000..98086d3f81
--- /dev/null
+++ b/src/plugins/cpptools/cppquickopenfilter.cpp
@@ -0,0 +1,280 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppquickopenfilter.h"
+
+#include <Literals.h>
+#include <Symbols.h>
+#include <SymbolVisitor.h>
+#include <Scope.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/Icons.h>
+
+#include <coreplugin/editormanager/ieditor.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtCore/QMultiMap>
+
+#include <functional>
+
+using namespace CPlusPlus;
+
+namespace CppTools {
+namespace Internal {
+
+class SearchSymbols: public std::unary_function<Document::Ptr, QList<ModelItemInfo> >,
+ protected SymbolVisitor
+{
+ Overview overview;
+ Icons icons;
+ QList<ModelItemInfo> items;
+
+public:
+ QList<ModelItemInfo> operator()(Document::Ptr doc)
+ { return operator()(doc, QString()); }
+
+ QList<ModelItemInfo> operator()(Document::Ptr doc, const QString &scope)
+ {
+ QString previousScope = switchScope(scope);
+ items.clear();
+ for (unsigned i = 0; i < doc->globalSymbolCount(); ++i) {
+ accept(doc->globalSymbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return items;
+ }
+
+protected:
+ using SymbolVisitor::visit;
+
+ void accept(Symbol *symbol)
+ { Symbol::visitSymbol(symbol, this); }
+
+ QString switchScope(const QString &scope)
+ {
+ QString previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+ }
+
+ virtual bool visit(Enum *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString previousScope = switchScope(name);
+ QIcon icon = icons.iconForSymbol(symbol);
+ Scope *members = symbol->members();
+ items.append(ModelItemInfo(name, QString(), ModelItemInfo::Enum,
+ QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
+ symbol->line(),
+ icon));
+ for (unsigned i = 0; i < members->symbolCount(); ++i) {
+ accept(members->symbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return false;
+ }
+
+ virtual bool visit(Function *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString type = overview.prettyType(symbol->type());
+ QIcon icon = icons.iconForSymbol(symbol);
+ items.append(ModelItemInfo(name, type, ModelItemInfo::Method,
+ QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
+ symbol->line(),
+ icon));
+ return false;
+ }
+
+ virtual bool visit(Namespace *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString previousScope = switchScope(name);
+ Scope *members = symbol->members();
+ for (unsigned i = 0; i < members->symbolCount(); ++i) {
+ accept(members->symbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return false;
+ }
+#if 0
+ // This visit method would make function declaration be included in QuickOpen
+ virtual bool visit(Declaration *symbol)
+ {
+ if (symbol->type()->isFunction()) {
+ QString name = symbolName(symbol);
+ QString type = overview.prettyType(symbol->type());
+ //QIcon icon = ...;
+ items.append(ModelItemInfo(name, type, ModelItemInfo::Method,
+ QString::fromUtf8(symbol->fileName(), symbol->line()),
+ symbol->line()));
+ }
+ return false;
+ }
+#endif
+ virtual bool visit(Class *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString previousScope = switchScope(name);
+ QIcon icon = icons.iconForSymbol(symbol);
+ items.append(ModelItemInfo(name, QString(), ModelItemInfo::Class,
+ QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
+ symbol->line(),
+ icon));
+ Scope *members = symbol->members();
+ for (unsigned i = 0; i < members->symbolCount(); ++i) {
+ accept(members->symbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return false;
+ }
+
+ QString symbolName(Symbol *symbol) const
+ {
+ QString name = _scope;
+ if (! name.isEmpty())
+ name += QLatin1String("::");
+ QString symbolName = overview.prettyName(symbol->name());
+ if (symbolName.isEmpty()) {
+ QString type;
+ if (symbol->isNamespace()) {
+ type = QLatin1String("namespace");
+ } else if (symbol->isEnum()) {
+ type = QLatin1String("enum");
+ } else if (Class *c = symbol->asClass()) {
+ if (c->isUnion()) {
+ type = QLatin1String("union");
+ } else if (c->isStruct()) {
+ type = QLatin1String("struct");
+ } else {
+ type = QLatin1String("class");
+ }
+ } else {
+ type = QLatin1String("symbol");
+ }
+ symbolName = QLatin1String("<anonymous ");
+ symbolName += type;
+ symbolName += QLatin1String(">");
+ }
+ name += symbolName;
+ return name;
+ }
+
+private:
+ QString _scope;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+using namespace CppTools::Internal;
+
+CppQuickOpenFilter::CppQuickOpenFilter(CppModelManager *manager, Core::EditorManager *editorManager)
+ : m_manager(manager),
+ m_editorManager(editorManager),
+ m_forceNewSearchList(true)
+{
+ setShortcutString(":");
+ setIncludedByDefault(false);
+
+ connect(manager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
+ this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
+
+ connect(manager, SIGNAL(aboutToRemoveFiles(QStringList)),
+ this, SLOT(onAboutToRemoveFiles(QStringList)));
+}
+
+CppQuickOpenFilter::~CppQuickOpenFilter()
+{ }
+
+void CppQuickOpenFilter::onDocumentUpdated(CPlusPlus::Document::Ptr doc)
+{
+ m_searchList[doc->fileName()] = Info(doc);
+}
+
+void CppQuickOpenFilter::onAboutToRemoveFiles(const QStringList &files)
+{
+ foreach (QString file, files) {
+ m_searchList.remove(file);
+ }
+}
+
+void CppQuickOpenFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+}
+
+QList<QuickOpen::FilterEntry> CppQuickOpenFilter::matchesFor(const QString &origEntry)
+{
+ QString entry = trimWildcards(origEntry);
+ QList<QuickOpen::FilterEntry> entries;
+ QStringMatcher matcher(entry, Qt::CaseInsensitive);
+ const QRegExp regexp("*"+entry+"*", Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (!regexp.isValid())
+ return entries;
+ bool hasWildcard = (entry.contains('*') || entry.contains('?'));
+
+ SearchSymbols search;
+ QMutableMapIterator<QString, Info> it(m_searchList);
+ while (it.hasNext()) {
+ it.next();
+
+ Info info = it.value();
+ if (info.dirty) {
+ info.dirty = false;
+ info.items = search(info.doc);
+ it.setValue(info);
+ }
+
+ QList<ModelItemInfo> items = info.items;
+
+ foreach (ModelItemInfo info, items) {
+ if ((hasWildcard && regexp.exactMatch(info.symbolName))
+ || (!hasWildcard && matcher.indexIn(info.symbolName) != -1)) {
+ QVariant id = qVariantFromValue(info);
+ QuickOpen::FilterEntry filterEntry(this, info.symbolName, id, info.icon);
+ filterEntry.extraInfo = info.symbolType;
+ entries.append(filterEntry);
+ }
+ }
+ }
+
+ return entries;
+}
+
+void CppQuickOpenFilter::accept(QuickOpen::FilterEntry selection) const
+{
+ ModelItemInfo info = qvariant_cast<CppTools::Internal::ModelItemInfo>(selection.internalData);
+
+ TextEditor::BaseTextEditor::openEditorAt(info.fileName, info.line);
+}
diff --git a/src/plugins/cpptools/cppquickopenfilter.h b/src/plugins/cpptools/cppquickopenfilter.h
new file mode 100644
index 0000000000..1375e468f5
--- /dev/null
+++ b/src/plugins/cpptools/cppquickopenfilter.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPQUICKOPENFILTER_H
+#define CPPQUICKOPENFILTER_H
+
+#include "cppmodelmanager.h"
+#include <cplusplus/CppDocument.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <quickopen/iquickopenfilter.h>
+#include <QtGui/QIcon>
+#include <QFile>
+#include <QMetaType>
+
+namespace CppTools {
+namespace Internal {
+
+struct ModelItemInfo
+{
+ enum ItemType { Enum, Class, Method };
+
+ ModelItemInfo()
+ { }
+
+ ModelItemInfo(const QString &symbolName,
+ const QString &symbolType,
+ ItemType type,
+ const QString &fileName,
+ int line,
+ const QIcon &icon)
+ : symbolName(symbolName),
+ symbolType(symbolType),
+ type(type),
+ fileName(fileName),
+ line(line),
+ icon(icon)
+ { }
+
+ QString symbolName;
+ QString symbolType;
+ ItemType type;
+ QString fileName;
+ int line;
+ QIcon icon;
+};
+
+class CppQuickOpenFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+public:
+ CppQuickOpenFilter(CppModelManager *manager, Core::EditorManager *editorManager);
+ ~CppQuickOpenFilter();
+
+ QString trName() const { return tr("Classes and Methods"); }
+ QString name() const { return "Classes and Methods"; }
+ Priority priority() const { return Medium; }
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &future);
+
+private slots:
+ void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
+ void onAboutToRemoveFiles(const QStringList &files);
+
+private:
+ CppModelManager *m_manager;
+ Core::EditorManager *m_editorManager;
+
+ struct Info {
+ Info(): dirty(true) {}
+ Info(CPlusPlus::Document::Ptr doc): doc(doc), dirty(true) {}
+
+ CPlusPlus::Document::Ptr doc;
+ QList<ModelItemInfo> items;
+ bool dirty;
+ };
+
+ QMap<QString, Info> m_searchList;
+ QList<ModelItemInfo> m_previousResults;
+ bool m_forceNewSearchList;
+ QString m_previousEntry;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo)
+
+#endif // CPPQUICKOPENFILTER_H
diff --git a/src/plugins/cpptools/cpptools.cpp b/src/plugins/cpptools/cpptools.cpp
new file mode 100644
index 0000000000..ceca43afaa
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.cpp
@@ -0,0 +1,256 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cpptools.h"
+#include "cppcodecompletion.h"
+#include "cpphoverhandler.h"
+#include "cppmodelmanager.h"
+#include "cpptoolsconstants.h"
+#include "cppquickopenfilter.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <cppeditor/cppeditorconstants.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+using namespace CppTools::Internal;
+
+enum { debug = 0 };
+
+
+CppToolsPlugin *CppToolsPlugin::m_instance = 0;
+
+CppToolsPlugin::CppToolsPlugin() :
+ m_core(0),
+ m_context(-1),
+ m_modelManager(0)
+{
+ m_instance = this;
+}
+
+CppToolsPlugin::~CppToolsPlugin()
+{
+ m_instance = 0;
+ m_modelManager = 0; // deleted automatically
+}
+
+bool CppToolsPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ // Objects
+ m_modelManager = new CppModelManager(this);
+ addAutoReleasedObject(m_modelManager);
+ CppCodeCompletion *cppcodecompletion = new CppCodeCompletion(m_modelManager, m_core);
+ addAutoReleasedObject(cppcodecompletion);
+ CppQuickOpenFilter *quickOpenFilter = new CppQuickOpenFilter(m_modelManager,
+ m_core->editorManager());
+ addAutoReleasedObject(quickOpenFilter);
+
+ // Menus
+ Core::IActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS);
+ Core::IActionContainer *mcpptools = am->createMenu(CppTools::Constants::M_TOOLS_CPP);
+ QMenu *menu = mcpptools->menu();
+ menu->setTitle(tr("&C++"));
+ menu->setEnabled(true);
+ mtools->addMenu(mcpptools);
+
+ // Actions
+ m_context = m_core->uniqueIDManager()->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
+ QList<int> context = QList<int>() << m_context;
+
+ QAction *switchAction = new QAction(tr("Switch Header/Source"), this);
+ Core::ICommand *command = am->registerAction(switchAction, Constants::SWITCH_HEADER_SOURCE, context);
+ command->setDefaultKeySequence(QKeySequence(Qt::Key_F4));
+ mcpptools->addAction(command);
+ connect(switchAction, SIGNAL(triggered()), this, SLOT(switchHeaderSource()));
+
+ return true;
+}
+
+void CppToolsPlugin::extensionsInitialized()
+{
+}
+
+void CppToolsPlugin::switchHeaderSource()
+{
+ if (!m_core)
+ return;
+
+ Core::IEditor *editor = m_core->editorManager()->currentEditor();
+ QString otherFile = correspondingHeaderOrSource(editor->file()->fileName());
+ if (!otherFile.isEmpty()) {
+ m_core->editorManager()->openEditor(otherFile);
+ m_core->editorManager()->ensureEditorManagerVisible();
+ }
+}
+
+QFileInfo CppToolsPlugin::findFile(const QDir &dir, const QString &name,
+ const ProjectExplorer::Project *project) const
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << dir << name;
+
+ if (project) {
+ QString pattern = QString(1, QLatin1Char('/'));
+ pattern += name;
+ const QStringList projectFiles = project->files(ProjectExplorer::Project::AllFiles);
+ const QStringList::const_iterator pcend = projectFiles.constEnd();
+ for (QStringList::const_iterator it = projectFiles.constBegin(); it != pcend; ++it)
+ if (it->endsWith(pattern))
+ return QFileInfo(*it);
+ return QFileInfo();
+ }
+ return QFileInfo(dir, name);
+}
+
+// Figure out file type
+enum FileType { HeaderFile, C_SourceFile, CPP_SourceFile, UnknownType };
+
+static inline FileType fileType(const Core::MimeDatabase *mimeDatase, const QFileInfo & fi)
+{
+ const Core::MimeType mimeType = mimeDatase->findByFile(fi);
+ if (!mimeType)
+ return UnknownType;
+ const QString typeName = mimeType.type();
+ if (typeName == QLatin1String(CppTools::Constants::C_SOURCE_MIMETYPE))
+ return C_SourceFile;
+ if (typeName == QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE))
+ return CPP_SourceFile;
+ if (typeName == QLatin1String(CppTools::Constants::C_HEADER_MIMETYPE)
+ || typeName == QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE))
+ return HeaderFile;
+ return UnknownType;
+}
+
+// Return the suffixes that should be checked when trying to find a
+// source belonging to a header and vice versa
+static QStringList matchingCandidateSuffixes(const Core::MimeDatabase *mimeDatase, FileType type)
+{
+ switch (type) {
+ case UnknownType:
+ break;
+ case HeaderFile: // Note that C/C++ headers are undistinguishable
+ return mimeDatase->findByType(QLatin1String(CppTools::Constants::C_SOURCE_MIMETYPE)).suffixes() +
+ mimeDatase->findByType(QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE)).suffixes();
+ case C_SourceFile:
+ return mimeDatase->findByType(QLatin1String(CppTools::Constants::C_HEADER_MIMETYPE)).suffixes();
+ case CPP_SourceFile:
+ return mimeDatase->findByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)).suffixes();
+ }
+ return QStringList();
+}
+
+QString CppToolsPlugin::correspondingHeaderOrSourceI(const QString &fileName) const
+{
+ const Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ const Core::MimeDatabase *mimeDatase = core->mimeDatabase();
+ ProjectExplorer::ProjectExplorerPlugin *explorer =
+ ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+ ProjectExplorer::Project *project = (explorer ? explorer->currentProject() : 0);
+
+ const QFileInfo fi(fileName);
+ const FileType type = fileType(mimeDatase, fi);
+
+ if (debug)
+ qDebug() << Q_FUNC_INFO << fileName << type;
+
+ if (type == UnknownType)
+ return QString();
+
+ const QDir absoluteDir = fi.absoluteDir();
+ const QString baseName = fi.baseName();
+ const QStringList suffixes = matchingCandidateSuffixes(mimeDatase, type);
+
+ const QString privateHeaderSuffix = QLatin1String("_p");
+ const QChar dot = QLatin1Char('.');
+ QStringList candidates;
+ // Check base matches 'source.h'-> 'source.cpp' and vice versa
+ const QStringList::const_iterator scend = suffixes.constEnd();
+ for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
+ QString candidate = baseName;
+ candidate += dot;
+ candidate += *it;
+ const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
+ if (candidateFi.isFile())
+ return candidateFi.absoluteFilePath();
+ }
+ if (type == HeaderFile) {
+ // 'source_p.h': try 'source.cpp'
+ if (baseName.endsWith(privateHeaderSuffix)) {
+ QString sourceBaseName = baseName;
+ sourceBaseName.truncate(sourceBaseName.size() - privateHeaderSuffix.size());
+ for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
+ QString candidate = sourceBaseName;
+ candidate += dot;
+ candidate += *it;
+ const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
+ if (candidateFi.isFile())
+ return candidateFi.absoluteFilePath();
+ }
+ }
+ } else {
+ // 'source.cpp': try 'source_p.h'
+ const QStringList::const_iterator scend = suffixes.constEnd();
+ for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
+ QString candidate = baseName;
+ candidate += privateHeaderSuffix;
+ candidate += dot;
+ candidate += *it;
+ const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
+ if (candidateFi.isFile())
+ return candidateFi.absoluteFilePath();
+ }
+ }
+ return QString();
+}
+
+QString CppToolsPlugin::correspondingHeaderOrSource(const QString &fileName) const
+{
+ const QString rc = correspondingHeaderOrSourceI(fileName);
+ if (debug)
+ qDebug() << Q_FUNC_INFO << fileName << rc;
+ return rc;
+}
+
+Q_EXPORT_PLUGIN(CppToolsPlugin)
diff --git a/src/plugins/cpptools/cpptools.h b/src/plugins/cpptools/cpptools.h
new file mode 100644
index 0000000000..3d0f195309
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLS_H
+#define CPPTOOLS_H
+
+#include <extensionsystem/iplugin.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+class QDir;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppCodeCompletion;
+class CppModelManager;
+
+class CppToolsPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ static CppToolsPlugin *instance() { return m_instance; }
+
+ CppToolsPlugin();
+ ~CppToolsPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ CppModelManager *cppModelManager() { return m_modelManager; }
+ QString correspondingHeaderOrSource(const QString &fileName) const;
+
+private slots:
+ void switchHeaderSource();
+
+private:
+ QString correspondingHeaderOrSourceI(const QString &fileName) const;
+ QFileInfo findFile(const QDir &dir, const QString &name, const ProjectExplorer::Project *project) const;
+
+ Core::ICore *m_core;
+ int m_context;
+ CppModelManager *m_modelManager;
+
+ static CppToolsPlugin *m_instance;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+#endif // CPPTOOLS_H
diff --git a/src/plugins/cpptools/cpptools.pri b/src/plugins/cpptools/cpptools.pri
new file mode 100644
index 0000000000..1dffbfc556
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.pri
@@ -0,0 +1,3 @@
+include(cpptools_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(CppTools)
diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro
new file mode 100644
index 0000000000..17b72496a9
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.pro
@@ -0,0 +1,40 @@
+TEMPLATE = lib
+TARGET = CppTools
+include(../../qworkbenchplugin.pri)
+include(../../plugins/quickopen/quickopen.pri)
+include(cpptools_dependencies.pri)
+
+#DEFINES += QT_NO_CAST_FROM_ASCII
+DEFINES += QT_NO_CAST_TO_ASCII
+unix:QMAKE_CXXFLAGS_DEBUG+=-O3
+
+INCLUDEPATH += .
+
+DEFINES += CPPTOOLS_LIBRARY
+
+CONFIG += help
+include(rpp/rpp.pri)|error("Can't find RPP")
+
+HEADERS += \
+ cpptools_global.h \
+ cppquickopenfilter.h
+
+SOURCES += \
+ cppquickopenfilter.cpp \
+ cpptoolseditorsupport.cpp
+
+# Input
+SOURCES += cpptools.cpp \
+ cppmodelmanager.cpp \
+ cppcodecompletion.cpp \
+ cpphoverhandler.cpp
+
+HEADERS += cpptools.h \
+ cppmodelmanager.h \
+ cppcodecompletion.h \
+ cpphoverhandler.h \
+ cppmodelmanagerinterface.h \
+ cpptoolseditorsupport.h \
+ cpptoolsconstants.h
+
+RESOURCES += cpptools.qrc
diff --git a/src/plugins/cpptools/cpptools.qrc b/src/plugins/cpptools/cpptools.qrc
new file mode 100644
index 0000000000..a750578a4b
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/cpptools" >
+ <file>images/f1.svg</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/cpptools/cpptools_dependencies.pri b/src/plugins/cpptools/cpptools_dependencies.pri
new file mode 100644
index 0000000000..e12a33bc46
--- /dev/null
+++ b/src/plugins/cpptools/cpptools_dependencies.pri
@@ -0,0 +1,3 @@
+include(../../libs/cplusplus/cplusplus.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
diff --git a/src/plugins/cpptools/cpptools_global.h b/src/plugins/cpptools/cpptools_global.h
new file mode 100644
index 0000000000..294a54ceb2
--- /dev/null
+++ b/src/plugins/cpptools/cpptools_global.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLS_GLOBAL_H
+#define CPPTOOLS_GLOBAL_H
+
+#if defined(CPPTOOLS_LIBRARY)
+# define CPPTOOLS_EXPORT Q_DECL_EXPORT
+#else
+# define CPPTOOLS_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // CPPTOOLS_GLOBAL_H
diff --git a/src/plugins/cpptools/cpptoolsconstants.h b/src/plugins/cpptools/cpptoolsconstants.h
new file mode 100644
index 0000000000..8a3e92cf2d
--- /dev/null
+++ b/src/plugins/cpptools/cpptoolsconstants.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLSCONSTANTS_H
+#define CPPTOOLSCONSTANTS_H
+
+namespace CppTools {
+namespace Constants {
+
+const char * const M_TOOLS_CPP = "CppTools.Tools.Menu";
+const char * const SWITCH_HEADER_SOURCE = "CppTools.SwitchHeaderSource";
+const char * const TASK_INDEX = "CppTools.Task.Index";
+const char * const C_SOURCE_MIMETYPE = "text/x-csrc";
+const char * const C_HEADER_MIMETYPE = "text/x-chdr";
+const char * const CPP_SOURCE_MIMETYPE = "text/x-c++src";
+const char * const CPP_HEADER_MIMETYPE = "text/x-c++hdr";
+}
+}
+
+#endif //CPPTOOLSCONSTANTS_H
diff --git a/src/plugins/cpptools/cpptoolseditorsupport.cpp b/src/plugins/cpptools/cpptoolseditorsupport.cpp
new file mode 100644
index 0000000000..ca36045422
--- /dev/null
+++ b/src/plugins/cpptools/cpptoolseditorsupport.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "cpptoolseditorsupport.h"
+#include "cppmodelmanager.h"
+
+#include <texteditor/itexteditor.h>
+#include <QTimer>
+
+using namespace CppTools::Internal;
+
+CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
+ : QObject(modelManager),
+ _modelManager(modelManager),
+ _updateDocumentInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL)
+{
+ _updateDocumentTimer = new QTimer(this);
+ _updateDocumentTimer->setSingleShot(true);
+ _updateDocumentTimer->setInterval(_updateDocumentInterval);
+ connect(_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
+}
+
+CppEditorSupport::~CppEditorSupport()
+{ }
+
+TextEditor::ITextEditor *CppEditorSupport::textEditor() const
+{ return _textEditor; }
+
+void CppEditorSupport::setTextEditor(TextEditor::ITextEditor *textEditor)
+{
+ _textEditor = textEditor;
+
+ if (! _textEditor)
+ return;
+
+ connect(_textEditor, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
+ updateDocument();
+}
+
+QString CppEditorSupport::contents() const
+{
+ if (! _textEditor)
+ return QString();
+
+ return _textEditor->contents();
+}
+
+int CppEditorSupport::updateDocumentInterval() const
+{ return _updateDocumentInterval; }
+
+void CppEditorSupport::setUpdateDocumentInterval(int updateDocumentInterval)
+{ _updateDocumentInterval = updateDocumentInterval; }
+
+void CppEditorSupport::updateDocument()
+{ _updateDocumentTimer->start(_updateDocumentInterval); }
+
+void CppEditorSupport::updateDocumentNow()
+{
+ if (_documentParser.isRunning()) {
+ _updateDocumentTimer->start(_updateDocumentInterval);
+ } else {
+ _updateDocumentTimer->stop();
+ QStringList sourceFiles(_textEditor->file()->fileName());
+ _documentParser = _modelManager->refreshSourceFiles(sourceFiles);
+ }
+}
+
diff --git a/src/plugins/cpptools/cpptoolseditorsupport.h b/src/plugins/cpptools/cpptoolseditorsupport.h
new file mode 100644
index 0000000000..51a905e895
--- /dev/null
+++ b/src/plugins/cpptools/cpptoolseditorsupport.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLSEDITORSUPPORT_H
+#define CPPTOOLSEDITORSUPPORT_H
+
+#include <QObject>
+#include <QPointer>
+#include <QFuture>
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+class QByteArray;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+ class ITextEditor;
+} // end of namespace TextEditor
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+
+class CppEditorSupport: public QObject
+{
+ Q_OBJECT
+
+public:
+ CppEditorSupport(CppModelManager *modelManager);
+ virtual ~CppEditorSupport();
+
+ TextEditor::ITextEditor *textEditor() const;
+ void setTextEditor(TextEditor::ITextEditor *textEditor);
+
+ int updateDocumentInterval() const;
+ void setUpdateDocumentInterval(int updateDocumentInterval);
+
+ QString contents() const;
+
+private Q_SLOTS:
+ void updateDocument();
+ void updateDocumentNow();
+
+private:
+ enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 150 };
+
+ CppModelManager *_modelManager;
+ QPointer<TextEditor::ITextEditor> _textEditor;
+ QTimer *_updateDocumentTimer;
+ int _updateDocumentInterval;
+ QFuture<void> _documentParser;
+};
+
+} // end of namespace Internal
+} // end of namespace CppTools
+
+#endif // CPPTOOLSEDITORSUPPORT_H
diff --git a/src/plugins/cpptools/images/f1.svg b/src/plugins/cpptools/images/f1.svg
new file mode 100644
index 0000000000..468594cb77
--- /dev/null
+++ b/src/plugins/cpptools/images/f1.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="24"
+ id="svg2411"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="f1.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2413">
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient001"
+ id="linearGradient3201"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.6285394,0,0,3.6290105,-1258.7023,-359.38242)"
+ spreadMethod="pad"
+ x1="375.31006"
+ y1="88.869247"
+ x2="466.8873"
+ y2="180.4346" />
+ <linearGradient
+ id="linearGradient001">
+ <stop
+ id="stop608"
+ offset="0.000000"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop609"
+ offset="1.000000"
+ style="stop-color:#efefef;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient001"
+ id="linearGradient3207"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.8401167,0,0,3.8424815,-1348.031,-388.46373)"
+ spreadMethod="pad"
+ x1="470.3931"
+ y1="136.23064"
+ x2="374.90988"
+ y2="136.23064" />
+ <linearGradient
+ id="linearGradient002">
+ <stop
+ id="stop566"
+ offset="0.000000"
+ style="stop-color:#9d9d9f;stop-opacity:1;" />
+ <stop
+ id="stop567"
+ offset="1.000000"
+ style="stop-color:#e5e5e5;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient002"
+ id="linearGradient2419"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.6611924,0,0,3.6628816,-1231.7325,-383.72165)"
+ spreadMethod="pad"
+ x1="471.00525"
+ y1="201.05208"
+ x2="348.94803"
+ y2="79.051147" />
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective2419" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.2"
+ inkscape:cx="22.801892"
+ inkscape:cy="10.456883"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="963"
+ inkscape:window-height="667"
+ inkscape:window-x="207"
+ inkscape:window-y="207" />
+ <metadata
+ id="metadata2416">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ transform="matrix(4.3636364e-2,0,0,4.3636364e-2,0,6.1090908)"
+ id="g2404">
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ y="-140"
+ x="2.4832567e-14"
+ width="550"
+ style="font-size:12px;fill:#b0b0b0;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.81658993pt;stroke-opacity:1"
+ ry="81.511414"
+ id="rect621"
+ height="550" />
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ y="-128.55069"
+ x="11.458333"
+ width="527.08331"
+ style="font-size:12px;fill:url(#linearGradient2419);fill-rule:evenodd;stroke:none;stroke-width:1.03125;stroke-miterlimit:4;stroke-dasharray:none"
+ ry="78.116447"
+ id="rect2417"
+ height="527.09235" />
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ y="-71.25"
+ x="68.950378"
+ width="412.29962"
+ style="font-size:12px;fill:url(#linearGradient3207);fill-rule:evenodd;stroke:none;stroke-width:2.4979167;stroke-miterlimit:4;stroke-dasharray:none"
+ ry="39.785442"
+ rx="34.514793"
+ id="rect3205"
+ height="412.5" />
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ y="-59.791668"
+ x="80.208336"
+ width="389.58334"
+ style="font-size:12px;fill:url(#linearGradient3201);fill-rule:evenodd;stroke:none;stroke-width:25.41458321;stroke-miterlimit:4;stroke-dasharray:none"
+ ry="25.400656"
+ rx="22.902761"
+ id="rect3199"
+ height="389.58334" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccsccc"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ id="text3219"
+ d="M 137.5,157.91667 L 137.5,-2.4752517 L 229.16667,-2.5 L 229.16667,20.416667 L 160.41667,20.416667 L 160.41667,66.25 L 206.25,66.25 L 206.25,89.166667 L 160.41667,89.166667 L 160.41667,157.91667 L 137.5,157.91667 z M 320.89291,157.91667 L 297.91667,157.91667 L 297.91667,40.04211 C 284.08134,48.574912 275.21133,59.2993 252.08333,66.25 L 252.08333,47.355939 C 263.04835,44.807707 286.00818,25.67917 293.48823,18.312241 C 300.9682,10.945593 306.26379,4.4293192 309.375,-2.5 L 320.83333,-2.5 L 320.89291,157.91667 z"
+ style="font-size:261.65481567px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" />
+ </g>
+ </g>
+</svg>
diff --git a/src/plugins/cpptools/rpp/pp-cctype.h b/src/plugins/cpptools/rpp/pp-cctype.h
new file mode 100644
index 0000000000..aff4fb2c51
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-cctype.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_CCTYPE_H
+#define PP_CCTYPE_H
+
+#include <cctype>
+
+namespace rpp {
+
+inline bool pp_isalpha (int __ch)
+{ return std::isalpha ((unsigned char) __ch) != 0; }
+
+inline bool pp_isalnum (int __ch)
+{ return std::isalnum ((unsigned char) __ch) != 0; }
+
+inline bool pp_isdigit (int __ch)
+{ return std::isdigit ((unsigned char) __ch) != 0; }
+
+inline bool pp_isspace (int __ch)
+{ return std::isspace ((unsigned char) __ch) != 0; }
+
+} // namespace rpp
+
+#endif // PP_CCTYPE_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-client.h b/src/plugins/cpptools/rpp/pp-client.h
new file mode 100644
index 0000000000..13d9eda713
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-client.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PP_CLIENT_H
+#define PP_CLIENT_H
+
+#include <QByteArray>
+#include <QString>
+#include <QFile>
+
+namespace rpp {
+
+class Client
+{
+ Client(const Client &other);
+ void operator=(const Client &other);
+
+public:
+ enum IncludeType {
+ IncludeLocal,
+ IncludeGlobal
+ };
+
+public:
+ Client()
+ { }
+
+ virtual ~Client()
+ { }
+
+ virtual void macroAdded(const QByteArray &macroId, const QByteArray &text) = 0;
+ virtual void sourceNeeded(QString &fileName, IncludeType mode) = 0; // ### FIX the signature.
+
+ virtual void startSkippingBlocks(unsigned offset) = 0;
+ virtual void stopSkippingBlocks(unsigned offset) = 0;
+};
+
+} // end of namespace rpp
+
+#endif // PP_CLIENT_H
diff --git a/src/plugins/cpptools/rpp/pp-engine.cpp b/src/plugins/cpptools/rpp/pp-engine.cpp
new file mode 100644
index 0000000000..97e168f0c2
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-engine.cpp
@@ -0,0 +1,1085 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp.h"
+#include <Lexer.h>
+#include <Token.h>
+#include <QtDebug>
+
+using namespace rpp;
+using namespace CPlusPlus;
+
+namespace {
+
+class RangeLexer
+{
+ const Token *first;
+ const Token *last;
+ Token trivial;
+
+public:
+ inline RangeLexer(const Token *first, const Token *last)
+ : first(first), last(last)
+ {
+ // WARN: `last' must be a valid iterator.
+ trivial.offset = last->offset;
+ }
+
+ inline operator bool() const
+ { return first != last; }
+
+ inline bool isValid() const
+ { return first != last; }
+
+ inline int size() const
+ { return std::distance(first, last); }
+
+ inline const Token *dot() const
+ { return first; }
+
+ inline const Token &operator*() const
+ {
+ if (first != last)
+ return *first;
+
+ return trivial;
+ }
+
+ inline const Token *operator->() const
+ {
+ if (first != last)
+ return first;
+
+ return &trivial;
+ }
+
+ inline RangeLexer &operator++()
+ {
+ ++first;
+ return *this;
+ }
+};
+
+class ExpressionEvaluator
+{
+ ExpressionEvaluator(const ExpressionEvaluator &other);
+ void operator = (const ExpressionEvaluator &other);
+
+public:
+ ExpressionEvaluator(Environment *env)
+ : env(env), _lex(0)
+ { }
+
+ Value operator()(const Token *firstToken, const Token *lastToken,
+ const QByteArray &source)
+ {
+ this->source = source;
+ const Value previousValue = switchValue(Value());
+ RangeLexer tmp(firstToken, lastToken);
+ RangeLexer *previousLex = _lex;
+ _lex = &tmp;
+ process_expression();
+ _lex = previousLex;
+ return switchValue(previousValue);
+ }
+
+protected:
+ Value switchValue(const Value &value)
+ {
+ Value previousValue = _value;
+ _value = value;
+ return previousValue;
+ }
+
+ bool isTokenDefined() const
+ {
+ if ((*_lex)->isNot(T_IDENTIFIER))
+ return false;
+ const QByteArray spell = tokenSpell();
+ if (spell.size() != 7)
+ return false;
+ return spell == "defined";
+ }
+
+ QByteArray tokenSpell() const
+ {
+ const QByteArray text = QByteArray::fromRawData(source.constData() + (*_lex)->offset,
+ (*_lex)->length);
+ return text;
+ }
+
+ bool process_expression()
+ { return process_constant_expression(); }
+
+ bool process_primary()
+ {
+ if ((*_lex)->is(T_INT_LITERAL)) {
+ _value.set_long(tokenSpell().toLong());
+ ++(*_lex);
+ return true;
+ } else if (isTokenDefined()) {
+ ++(*_lex);
+ if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(env->resolve(tokenSpell()) != 0);
+ ++(*_lex);
+ return true;
+ } else if ((*_lex)->is(T_LPAREN)) {
+ ++(*_lex);
+ if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(env->resolve(tokenSpell()) != 0);
+ ++(*_lex);
+ if ((*_lex)->is(T_RPAREN)) {
+ ++(*_lex);
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ } else if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(0);
+ ++(*_lex);
+ return true;
+ } else if ((*_lex)->is(T_MINUS)) {
+ ++(*_lex);
+ process_primary();
+ _value.set_long(- _value.l);
+ return true;
+ } else if ((*_lex)->is(T_PLUS)) {
+ ++(*_lex);
+ process_primary();
+ return true;
+ } else if ((*_lex)->is(T_EXCLAIM)) {
+ ++(*_lex);
+ process_primary();
+ _value.set_long(_value.is_zero());
+ return true;
+ } else if ((*_lex)->is(T_LPAREN)) {
+ ++(*_lex);
+ process_expression();
+ if ((*_lex)->is(T_RPAREN))
+ ++(*_lex);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool process_multiplicative()
+ {
+ process_primary();
+
+ while ((*_lex)->is(T_STAR) || (*_lex)->is(T_SLASH) || (*_lex)->is(T_PERCENT)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_primary();
+
+ if (op.is(T_STAR)) {
+ _value = left * _value;
+ } else if (op.is(T_SLASH)) {
+ if (_value.is_zero())
+ _value.set_long(0);
+ else
+ _value = left / _value;
+ } else if (op.is(T_PERCENT)) {
+ if (_value.is_zero())
+ _value.set_long(0);
+ else
+ _value = left % _value;
+ }
+ }
+
+ return true;
+ }
+
+ bool process_additive()
+ {
+ process_multiplicative();
+
+ while ((*_lex)->is(T_PLUS) || (*_lex)->is(T_MINUS)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_multiplicative();
+
+ if (op.is(T_PLUS))
+ _value = left + _value;
+ else if (op.is(T_MINUS))
+ _value = left - _value;
+ }
+
+ return true;
+ }
+
+ bool process_shift()
+ {
+ process_additive();
+
+ while ((*_lex)->is(T_MINUS_MINUS) || (*_lex)->is(T_GREATER_GREATER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_additive();
+
+ if (op.is(T_MINUS_MINUS))
+ _value = left << _value;
+ else if (op.is(T_GREATER_GREATER))
+ _value = left >> _value;
+ }
+
+ return true;
+ }
+
+ bool process_relational()
+ {
+ process_shift();
+
+ while ((*_lex)->is(T_LESS) || (*_lex)->is(T_LESS_EQUAL) ||
+ (*_lex)->is(T_GREATER) || (*_lex)->is(T_GREATER_EQUAL)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_shift();
+
+ if (op.is(T_LESS))
+ _value = left < _value;
+ else if (op.is(T_LESS_EQUAL))
+ _value = left <= _value;
+ else if (op.is(T_GREATER))
+ _value = left > _value;
+ else if (op.is(T_GREATER_EQUAL))
+ _value = left >= _value;
+ }
+
+ return true;
+ }
+
+ bool process_equality()
+ {
+ process_relational();
+
+ while ((*_lex)->is(T_EXCLAIM_EQUAL) || (*_lex)->is(T_EQUAL_EQUAL)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_relational();
+
+ if (op.is(T_EXCLAIM_EQUAL))
+ _value = left != _value;
+ else if (op.is(T_EQUAL_EQUAL))
+ _value = left == _value;
+ }
+
+ return true;
+ }
+
+ bool process_and()
+ {
+ process_equality();
+
+ while ((*_lex)->is(T_AMPER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_equality();
+
+ _value = left & _value;
+ }
+
+ return true;
+ }
+
+ bool process_xor()
+ {
+ process_and();
+
+ while ((*_lex)->is(T_CARET)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_and();
+
+ _value = left ^ _value;
+ }
+
+ return true;
+ }
+
+ bool process_or()
+ {
+ process_xor();
+
+ while ((*_lex)->is(T_CARET)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_xor();
+
+ _value = left | _value;
+ }
+
+ return true;
+ }
+
+ bool process_logical_and()
+ {
+ process_or();
+
+ while ((*_lex)->is(T_AMPER_AMPER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_or();
+
+ _value = left && _value;
+ }
+
+ return true;
+ }
+
+ bool process_logical_or()
+ {
+ process_logical_and();
+
+ while ((*_lex)->is(T_PIPE_PIPE)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_logical_and();
+
+ _value = left || _value;
+ }
+
+ return true;
+ }
+
+ bool process_constant_expression()
+ {
+ process_logical_or();
+ const Value cond = _value;
+ if ((*_lex)->is(T_QUESTION)) {
+ ++(*_lex);
+ process_constant_expression();
+ Value left = _value, right;
+ if ((*_lex)->is(T_COLON)) {
+ ++(*_lex);
+ process_constant_expression();
+ right = _value;
+ }
+ _value = ! cond.is_zero() ? left : right;
+ }
+
+ return true;
+ }
+
+private:
+ Environment *env;
+ QByteArray source;
+ RangeLexer *_lex;
+ Value _value;
+};
+
+} // end of anonymous namespace
+
+
+pp::pp (Client *client, Environment &env)
+ : client(client),
+ env(env),
+ expand(env)
+{
+ resetIfLevel ();
+}
+
+void pp::pushState(const State &s)
+{
+ _savedStates.append(state());
+ _source = s.source;
+ _tokens = s.tokens;
+ _dot = s.dot;
+}
+
+pp::State pp::state() const
+{
+ State state;
+ state.source = _source;
+ state.tokens = _tokens;
+ state.dot = _dot;
+ return state;
+}
+
+void pp::popState()
+{
+ const State &state = _savedStates.last();
+ _source = state.source;
+ _tokens = state.tokens;
+ _dot = state.dot;
+ _savedStates.removeLast();
+}
+
+void pp::operator () (const QByteArray &filename,
+ const QByteArray &source,
+ QByteArray *result)
+{
+ const QByteArray previousFile = env.current_file;
+ env.current_file = filename;
+
+ operator () (source, result);
+
+ env.current_file = previousFile;
+}
+
+pp::State pp::createStateFromSource(const QByteArray &source) const
+{
+ State state;
+ state.source = source;
+ Lexer lex(state.source.constBegin(), state.source.constEnd());
+ lex.setScanKeywords(false);
+ Token tok;
+ do {
+ lex(&tok);
+ state.tokens.append(tok);
+ } while (tok.isNot(T_EOF_SYMBOL));
+ state.dot = state.tokens.constBegin();
+ return state;
+}
+
+void pp::operator()(const QByteArray &source, QByteArray *result)
+{
+ pushState(createStateFromSource(source));
+
+ const unsigned previousCurrentLine = env.currentLine;
+ env.currentLine = 0;
+
+ while (true) {
+ if (env.currentLine != _dot->lineno) {
+ if (env.currentLine > _dot->lineno) {
+ result->append('\n');
+ result->append('#');
+ result->append(QByteArray::number(_dot->lineno));
+ result->append(' ');
+ result->append('"');
+ result->append(env.current_file);
+ result->append('"');
+ result->append('\n');
+ } else {
+ for (unsigned i = env.currentLine; i < _dot->lineno; ++i)
+ result->append('\n');
+ }
+ env.currentLine = _dot->lineno;
+ }
+
+ if (_dot->is(T_EOF_SYMBOL)) {
+ break;
+ } else if (_dot->is(T_POUND) && (! _dot->joined && _dot->newline)) {
+ TokenIterator start = _dot;
+ do {
+ ++_dot;
+ } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
+
+ //qDebug() << QByteArray(first + beginPP.offset,
+ //tokens.last().end() - beginPP.offset);
+
+ const bool skippingBlocks = _skipping[iflevel];
+
+ processDirective(start, _dot);
+
+ if (client && skippingBlocks != _skipping[iflevel]) {
+ unsigned offset = start->offset;
+ if (_skipping[iflevel]) {
+ if (_dot->newline)
+ ++offset;
+ client->startSkippingBlocks(offset);
+ } else {
+ if (offset)
+ --offset;
+ client->stopSkippingBlocks(offset);
+ }
+ }
+ } else if (skipping()) {
+ do {
+ ++_dot;
+ } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
+ } else {
+ if (_dot->joined)
+ result->append("\\\n");
+ else if (_dot->newline) {
+ result->append('\n');
+ result->append('#');
+ result->append(QByteArray::number(_dot->lineno));
+ result->append(' ');
+ result->append('"');
+ result->append(env.current_file);
+ result->append('"');
+ result->append('\n');
+ }
+ else if (_dot->whitespace)
+ result->append(' ');
+
+ if (_dot->isNot(T_IDENTIFIER)) {
+ result->append(tokenSpell(*_dot));
+ ++_dot;
+ } else {
+ const TokenIterator identifierToken = _dot;
+ ++_dot; // skip T_IDENTIFIER
+
+ const QByteArray spell = tokenSpell(*identifierToken);
+ if (env.isBuiltinMacro(spell)) {
+ expand(spell.constBegin(), spell.constEnd(), result);
+ continue;
+ }
+
+ Macro *m = env.resolve(spell);
+ if (! m) {
+ result->append(spell);
+ } else {
+ if (! m->function_like) {
+ if (_dot->isNot(T_LPAREN)) {
+ expand(m->definition.constBegin(),
+ m->definition.constEnd(),
+ result);
+ continue;
+ } else {
+ QByteArray tmp;
+ expand(m->definition.constBegin(),
+ m->definition.constEnd(),
+ &tmp);
+
+ m = 0; // reset the active the macro
+
+ pushState(createStateFromSource(tmp));
+ if (_dot->is(T_IDENTIFIER)) {
+ const QByteArray id = tokenSpell(*_dot);
+ Macro *macro = env.resolve(id);
+ if (macro && macro->function_like)
+ m = macro;
+ }
+ popState();
+
+ if (! m) {
+ result->append(tmp);
+ continue;
+ }
+ }
+ }
+
+ // collect the actual arguments
+ if (_dot->isNot(T_LPAREN)) {
+ // ### warnng expected T_LPAREN
+ result->append(m->name);
+ continue;
+ }
+
+ int count = 0;
+ while (_dot->isNot(T_EOF_SYMBOL)) {
+ if (_dot->is(T_LPAREN))
+ ++count;
+ else if (_dot->is(T_RPAREN)) {
+ if (! --count)
+ break;
+ }
+ ++_dot;
+ }
+ if (_dot->isNot(T_RPAREN)) {
+ // ### warning expected T_RPAREN
+ } else {
+ const char *beginOfText = startOfToken(*identifierToken);
+ const char *endOfText = endOfToken(*_dot);
+ ++_dot; // skip T_RPAREN
+ expand(beginOfText, endOfText, result);
+ }
+ }
+ }
+ }
+ }
+
+ popState();
+ env.currentLine = previousCurrentLine;
+}
+
+const char *pp::startOfToken(const Token &token) const
+{ return _source.constBegin() + token.begin(); }
+
+const char *pp::endOfToken(const Token &token) const
+{ return _source.constBegin() + token.end(); }
+
+QByteArray pp::tokenSpell(const Token &token) const
+{
+ const QByteArray text = QByteArray::fromRawData(_source.constBegin() + token.offset,
+ token.length);
+ return text;
+}
+
+QByteArray pp::tokenText(const Token &token) const
+{
+ const QByteArray text(_source.constBegin() + token.offset,
+ token.length);
+ return text;
+}
+
+void pp::processDirective(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray directive = tokenSpell(*tk);
+ switch (PP_DIRECTIVE_TYPE d = classifyDirective(directive)) {
+ case PP_DEFINE:
+ if (! skipping())
+ processDefine(firstToken, lastToken);
+ break;
+
+ case PP_INCLUDE:
+ case PP_INCLUDE_NEXT:
+ if (! skipping())
+ processInclude(d == PP_INCLUDE_NEXT, firstToken, lastToken);
+ break;
+
+ case PP_UNDEF:
+ if (! skipping())
+ processUndef(firstToken, lastToken);
+ break;
+
+ case PP_ELIF:
+ processElif(firstToken, lastToken);
+ break;
+
+ case PP_ELSE:
+ processElse(firstToken, lastToken);
+ break;
+
+ case PP_ENDIF:
+ processEndif(firstToken, lastToken);
+ break;
+
+ case PP_IF:
+ processIf(firstToken, lastToken);
+ break;
+
+ case PP_IFDEF:
+ case PP_IFNDEF:
+ processIfdef(d == PP_IFNDEF, firstToken, lastToken);
+ break;
+
+ default:
+ break;
+ } // switch
+ }
+}
+
+QVector<Token> pp::tokenize(const QByteArray &text) const
+{
+ QVector<Token> tokens;
+ Lexer lex(text.constBegin(), text.constEnd());
+ lex.setScanKeywords(false);
+ Token tk;
+ do {
+ lex(&tk);
+ tokens.append(tk);
+ } while (tk.isNot(T_EOF_SYMBOL));
+ return tokens;
+}
+
+void pp::processInclude(bool skipCurentPath,
+ TokenIterator firstToken, TokenIterator lastToken,
+ bool acceptMacros)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+ ++tk; // skip `include|nclude_next'
+
+ if (acceptMacros && tk->is(T_IDENTIFIER)) {
+#if 0
+ QByteArray name;
+ name.reserve(256);
+ MacroExpander expandInclude(env);
+ expandInclude(startOfToken(tokens.at(2)),
+ startOfToken(tokens.last()),
+ &name);
+ const QByteArray previousSource = switchSource(name);
+ //processInclude(skipCurentPath, tokenize(name), /*accept macros=*/ false);
+ (void) switchSource(previousSource);
+#endif
+ } else if (tk->is(T_LESS)) {
+ TokenIterator start = tk.dot();
+ for (; tk->isNot(T_EOF_SYMBOL); ++tk) {
+ if (tk->is(T_GREATER))
+ break;
+ }
+ const char *beginOfPath = endOfToken(*start);
+ const char *endOfPath = startOfToken(*tk);
+ const QByteArray path = QByteArray::fromRawData(beginOfPath,
+ endOfPath - beginOfPath);
+
+ QString fn = QString::fromUtf8(path.constData(), path.length());
+
+ if (client)
+ client->sourceNeeded(fn, Client::IncludeGlobal);
+ } else if (tk->is(T_ANGLE_STRING_LITERAL) || tk->is(T_STRING_LITERAL)) {
+ const QByteArray spell = tokenSpell(*tk);
+ const char *beginOfPath = spell.constBegin();
+ const char *endOfPath = spell.constEnd();
+ const char quote = *beginOfPath;
+ if (beginOfPath + 1 != endOfPath && ((quote == '"' && endOfPath[-1] == '"') ||
+ (quote == '<' && endOfPath[-1] == '>'))) {
+ const QByteArray path = QByteArray::fromRawData(beginOfPath + 1,
+ spell.length() - 2);
+ QString fn = QString::fromUtf8(path.constData(), path.length());
+
+ if (client)
+ client->sourceNeeded(fn, Client::IncludeLocal);
+ }
+ }
+}
+
+void pp::processDefine(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ if (tk.size() < 3)
+ return; // nothing to do
+
+ ++tk; // skip T_POUND
+ ++tk; // skip T_DEFINE
+
+ if (tk->isNot(T_IDENTIFIER)) {
+ // ### warning expected an `identifier'
+ return;
+ }
+
+ Macro macro;
+ macro.name = tokenText(*tk);
+ ++tk; // skip T_IDENTIFIER
+
+ if (tk->is(T_LPAREN) && ! tk->whitespace) {
+ // a function-like macro definition
+ macro.function_like = true;
+
+ ++tk; // skip T_LPAREN
+ if (tk->is(T_IDENTIFIER)) {
+ macro.formals.append(tokenText(*tk));
+ ++tk; // skip T_IDENTIFIER
+ while (tk->is(T_COMMA)) {
+ ++tk;// skip T_COMMA
+ if (tk->isNot(T_IDENTIFIER))
+ break;
+ macro.formals.append(tokenText(*tk));
+ ++tk; // skip T_IDENTIFIER
+ }
+ }
+
+ if (tk->is(T_DOT_DOT_DOT)) {
+ macro.variadics = true;
+ ++tk; // skip T_DOT_DOT_DOT
+ }
+
+ if (tk->isNot(T_RPAREN)) {
+ // ### warning expected `)'
+ return;
+ }
+
+ ++tk; // skip T_RPAREN
+ }
+
+ QByteArray macroId = macro.name;
+ const bool isQtWord = isQtReservedWord(macroId);
+
+ if (macro.function_like) {
+ macroId += '(';
+ for (int i = 0; i < macro.formals.size(); ++i) {
+ if (i != 0)
+ macroId += ", ";
+
+ const QByteArray formal = macro.formals.at(i);
+ macroId += formal;
+ }
+ macroId += ')';
+ }
+
+ if (isQtWord)
+ macro.definition = macroId;
+ else {
+ const char *startOfDefinition = startOfToken(*tk);
+ const char *endOfDefinition = startOfToken(*lastToken);
+ macro.definition.append(startOfDefinition,
+ endOfDefinition - startOfDefinition);
+ macro.definition.replace("\\\n", " ");
+ }
+
+ env.bind(macro);
+
+ QByteArray macroText;
+ macroText.reserve(64);
+ macroText += "#define ";
+
+ macroText += macroId;
+ macroText += ' ';
+ macroText += macro.definition;
+ macroText += '\n';
+
+ client->macroAdded(macroId, macroText);
+}
+
+void pp::processIf(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skipt `if'
+
+ if (testIfLevel()) {
+ const char *first = startOfToken(*tk);
+ const char *last = startOfToken(*lastToken);
+
+ MacroExpander expandCondition (env);
+ QByteArray condition;
+ condition.reserve(256);
+ expandCondition(first, last, &condition);
+
+ QVector<Token> tokens = tokenize(condition);
+
+ const Value result = evalExpression(tokens.constBegin(),
+ tokens.constEnd() - 1,
+ condition);
+
+ _true_test[iflevel] = ! result.is_zero ();
+ _skipping[iflevel] = result.is_zero ();
+ }
+}
+
+void pp::processElse(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ if (iflevel == 0 && !skipping ()) {
+ // std::cerr << "*** WARNING #else without #if" << std::endl;
+ } else if (iflevel > 0 && _skipping[iflevel - 1]) {
+ _skipping[iflevel] = true;
+ } else {
+ _skipping[iflevel] = _true_test[iflevel];
+ }
+}
+
+void pp::processElif(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+ ++tk; // skipt `elif'
+
+ if (! (iflevel > 0)) {
+ // std::cerr << "*** WARNING: " << __FILE__ << __LINE__ << std::endl;
+ } else if (iflevel == 0 && !skipping()) {
+ // std::cerr << "*** WARNING #else without #if" << std::endl;
+ } else if (!_true_test[iflevel] && !_skipping[iflevel - 1]) {
+ const Value result = evalExpression(tk.dot(), lastToken, _source);
+ _true_test[iflevel] = ! result.is_zero ();
+ _skipping[iflevel] = result.is_zero ();
+ } else {
+ _skipping[iflevel] = true;
+ }
+}
+
+void pp::processEndif(TokenIterator, TokenIterator)
+{
+ if (iflevel == 0 && !skipping()) {
+ // std::cerr << "*** WARNING #endif without #if" << std::endl;
+ } else {
+ _skipping[iflevel] = false;
+ _true_test[iflevel] = false;
+
+ --iflevel;
+ }
+}
+
+void pp::processIfdef(bool checkUndefined,
+ TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skip `ifdef'
+ if (testIfLevel()) {
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray macroName = tokenSpell(*tk);
+ bool value = env.resolve(macroName) != 0 || env.isBuiltinMacro(macroName);
+
+ if (checkUndefined)
+ value = ! value;
+
+ _true_test[iflevel] = value;
+ _skipping [iflevel] = ! value;
+ }
+ }
+}
+
+void pp::processUndef(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skip `undef'
+
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray macroName = tokenText(*tk);
+ env.remove(macroName);
+
+ QByteArray macroText;
+ macroText += "#undef ";
+ macroText += macroName;
+ macroText += '\n';
+ client->macroAdded(macroName, macroText);
+ }
+}
+
+void pp::resetIfLevel ()
+{
+ iflevel = 0;
+ _skipping[iflevel] = false;
+ _true_test[iflevel] = false;
+}
+
+pp::PP_DIRECTIVE_TYPE pp::classifyDirective (const QByteArray &__directive) const
+{
+ switch (__directive.size())
+ {
+ case 2:
+ if (__directive[0] == 'i' && __directive[1] == 'f')
+ return PP_IF;
+ break;
+
+ case 4:
+ if (__directive[0] == 'e' && __directive == "elif")
+ return PP_ELIF;
+ else if (__directive[0] == 'e' && __directive == "else")
+ return PP_ELSE;
+ break;
+
+ case 5:
+ if (__directive[0] == 'i' && __directive == "ifdef")
+ return PP_IFDEF;
+ else if (__directive[0] == 'u' && __directive == "undef")
+ return PP_UNDEF;
+ else if (__directive[0] == 'e' && __directive == "endif")
+ return PP_ENDIF;
+ break;
+
+ case 6:
+ if (__directive[0] == 'i' && __directive == "ifndef")
+ return PP_IFNDEF;
+ else if (__directive[0] == 'd' && __directive == "define")
+ return PP_DEFINE;
+ break;
+
+ case 7:
+ if (__directive[0] == 'i' && __directive == "include")
+ return PP_INCLUDE;
+ break;
+
+ case 12:
+ if (__directive[0] == 'i' && __directive == "include_next")
+ return PP_INCLUDE_NEXT;
+ break;
+
+ default:
+ break;
+ }
+
+ return PP_UNKNOWN_DIRECTIVE;
+}
+
+bool pp::testIfLevel()
+{
+ const bool result = !_skipping[iflevel++];
+ _skipping[iflevel] = _skipping[iflevel - 1];
+ _true_test[iflevel] = false;
+ return result;
+}
+
+int pp::skipping() const
+{ return _skipping[iflevel]; }
+
+Value pp::evalExpression(TokenIterator firstToken, TokenIterator lastToken,
+ const QByteArray &source) const
+{
+ ExpressionEvaluator eval(&env);
+ const Value result = eval(firstToken, lastToken, source);
+ return result;
+}
+
+bool pp::isQtReservedWord (const QByteArray &macroId) const
+{
+ const int size = macroId.size();
+ if (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_SIGNALS")
+ return true;
+ else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_SLOTS")
+ return true;
+ else if (size == 6 && macroId.at(0) == 'S' && macroId == "SIGNAL")
+ return true;
+ else if (size == 4 && macroId.at(0) == 'S' && macroId == "SLOT")
+ return true;
+ else if (size == 7 && macroId.at(0) == 's' && macroId == "signals")
+ return true;
+ else if (size == 5 && macroId.at(0) == 's' && macroId == "slots")
+ return true;
+ return false;
+}
diff --git a/src/plugins/cpptools/rpp/pp-engine.h b/src/plugins/cpptools/rpp/pp-engine.h
new file mode 100644
index 0000000000..fb3b9a3212
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-engine.h
@@ -0,0 +1,230 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_ENGINE_H
+#define PP_ENGINE_H
+
+#include "pp-client.h"
+#include <Token.h>
+#include <QVector>
+
+namespace CPlusPlus {
+ class Token;
+}
+
+namespace rpp {
+
+ struct Value
+ {
+ enum Kind {
+ Kind_Long,
+ Kind_ULong,
+ };
+
+ Kind kind;
+
+ union {
+ long l;
+ unsigned long ul;
+ };
+
+
+ Value()
+ : kind(Kind_Long), l(0)
+ { }
+
+ inline bool is_ulong () const
+ { return kind == Kind_ULong; }
+
+ inline void set_ulong (unsigned long v)
+ {
+ ul = v;
+ kind = Kind_ULong;
+ }
+
+ inline void set_long (long v)
+ {
+ l = v;
+ kind = Kind_Long;
+ }
+
+ inline bool is_zero () const
+ { return l == 0; }
+
+#define PP_DEFINE_BIN_OP(name, op) \
+ inline Value operator op(const Value &other) const \
+ { \
+ Value v = *this; \
+ if (v.is_ulong () || other.is_ulong ()) \
+ v.set_ulong (v.ul op other.ul); \
+ else \
+ v.set_long (v.l op other.l); \
+ return v; \
+ }
+
+ PP_DEFINE_BIN_OP(op_add, +)
+ PP_DEFINE_BIN_OP(op_sub, -)
+ PP_DEFINE_BIN_OP(op_mult, *)
+ PP_DEFINE_BIN_OP(op_div, /)
+ PP_DEFINE_BIN_OP(op_mod, %)
+ PP_DEFINE_BIN_OP(op_lhs, <<)
+ PP_DEFINE_BIN_OP(op_rhs, >>)
+ PP_DEFINE_BIN_OP(op_lt, <)
+ PP_DEFINE_BIN_OP(op_gt, >)
+ PP_DEFINE_BIN_OP(op_le, <=)
+ PP_DEFINE_BIN_OP(op_ge, >=)
+ PP_DEFINE_BIN_OP(op_eq, ==)
+ PP_DEFINE_BIN_OP(op_ne, !=)
+ PP_DEFINE_BIN_OP(op_bit_and, &)
+ PP_DEFINE_BIN_OP(op_bit_or, |)
+ PP_DEFINE_BIN_OP(op_bit_xor, ^)
+ PP_DEFINE_BIN_OP(op_and, &&)
+ PP_DEFINE_BIN_OP(op_or, ||)
+
+#undef PP_DEFINE_BIN_OP
+ };
+
+ class pp
+ {
+ Client *client;
+ Environment &env;
+ MacroExpander expand;
+
+ enum { MAX_LEVEL = 512 };
+
+ bool _skipping[MAX_LEVEL]; // ### move in state
+ bool _true_test[MAX_LEVEL]; // ### move in state
+ int iflevel; // ### move in state
+
+ enum PP_DIRECTIVE_TYPE
+ {
+ PP_UNKNOWN_DIRECTIVE,
+ PP_DEFINE,
+ PP_INCLUDE,
+ PP_INCLUDE_NEXT,
+ PP_ELIF,
+ PP_ELSE,
+ PP_ENDIF,
+ PP_IF,
+ PP_IFDEF,
+ PP_IFNDEF,
+ PP_UNDEF
+ };
+
+ typedef const CPlusPlus::Token *TokenIterator;
+
+ struct State {
+ QByteArray source;
+ QVector<CPlusPlus::Token> tokens;
+ TokenIterator dot;
+ };
+
+ QList<State> _savedStates;
+
+ State state() const;
+ void pushState(const State &state);
+ void popState();
+
+ QByteArray _source;
+ QVector<CPlusPlus::Token> _tokens;
+ TokenIterator _dot;
+
+ State createStateFromSource(const QByteArray &source) const;
+
+ public:
+ pp(Client *client, Environment &env);
+
+ void operator()(const QByteArray &filename,
+ const QByteArray &source,
+ QByteArray *result);
+
+ void operator()(const QByteArray &source,
+ QByteArray *result);
+
+ private:
+ void resetIfLevel();
+ bool testIfLevel();
+ int skipping() const;
+
+ PP_DIRECTIVE_TYPE classifyDirective(const QByteArray &directive) const;
+
+ Value evalExpression(TokenIterator firstToken,
+ TokenIterator lastToken,
+ const QByteArray &source) const;
+
+ QVector<CPlusPlus::Token> tokenize(const QByteArray &text) const;
+
+ const char *startOfToken(const CPlusPlus::Token &token) const;
+ const char *endOfToken(const CPlusPlus::Token &token) const;
+
+ QByteArray tokenSpell(const CPlusPlus::Token &token) const;
+ QByteArray tokenText(const CPlusPlus::Token &token) const; // does a deep copy
+
+ void processDirective(TokenIterator dot, TokenIterator lastToken);
+ void processInclude(bool skipCurrentPath,
+ TokenIterator dot, TokenIterator lastToken,
+ bool acceptMacros = true);
+ void processDefine(TokenIterator dot, TokenIterator lastToken);
+ void processIf(TokenIterator dot, TokenIterator lastToken);
+ void processElse(TokenIterator dot, TokenIterator lastToken);
+ void processElif(TokenIterator dot, TokenIterator lastToken);
+ void processEndif(TokenIterator dot, TokenIterator lastToken);
+ void processIfdef(bool checkUndefined,
+ TokenIterator dot, TokenIterator lastToken);
+ void processUndef(TokenIterator dot, TokenIterator lastToken);
+
+ bool isQtReservedWord(const QByteArray &name) const;
+ };
+
+} // namespace rpp
+
+#endif // PP_ENGINE_H
diff --git a/src/plugins/cpptools/rpp/pp-environment.cpp b/src/plugins/cpptools/rpp/pp-environment.cpp
new file mode 100644
index 0000000000..1503787898
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-environment.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-environment.h"
+#include "pp.h"
+#include <cstring>
+
+using namespace rpp;
+
+Environment::Environment ()
+ : currentLine(0),
+ hide_next(false),
+ _macros(0),
+ _allocated_macros(0),
+ _macro_count(-1),
+ _hash(0),
+ _hash_count(401)
+{
+}
+
+Environment::~Environment ()
+{
+ if (_macros) {
+ qDeleteAll(firstMacro(), lastMacro());
+ free(_macros);
+ }
+
+ if (_hash)
+ free(_hash);
+}
+
+unsigned Environment::macroCount () const
+{ return _macro_count + 1; }
+
+Macro *Environment::macroAt (unsigned index) const
+{ return _macros[index]; }
+
+Macro *Environment::bind(const Macro &__macro)
+{
+ Q_ASSERT(! __macro.name.isEmpty());
+
+ Macro *m = new Macro (__macro);
+ m->hashcode = hash_code(m->name);
+ m->fileName = current_file;
+ m->line = currentLine;
+
+ if (++_macro_count == _allocated_macros) {
+ if (! _allocated_macros)
+ _allocated_macros = 401;
+ else
+ _allocated_macros <<= 1;
+
+ _macros = (Macro **) realloc(_macros, sizeof(Macro *) * _allocated_macros);
+ }
+
+ _macros[_macro_count] = m;
+
+ if (! _hash || _macro_count > (_hash_count >> 1)) {
+ rehash();
+ } else {
+ const unsigned h = m->hashcode % _hash_count;
+ m->next = _hash[h];
+ _hash[h] = m;
+ }
+
+ return m;
+}
+
+void Environment::remove (const QByteArray &name)
+{
+ Macro macro;
+ macro.name = name;
+ macro.hidden = true;
+ bind(macro);
+}
+
+bool Environment::isBuiltinMacro(const QByteArray &s) const
+{
+ if (s.length() != 8)
+ return false;
+
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'D') {
+ if (s[3] == 'A') {
+ if (s[4] == 'T') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'F') {
+ if (s[3] == 'I') {
+ if (s[4] == 'L') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'L') {
+ if (s[3] == 'I') {
+ if (s[4] == 'N') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'T') {
+ if (s[3] == 'I') {
+ if (s[4] == 'M') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Macro *Environment::resolve (const QByteArray &name) const
+{
+ if (! _macros)
+ return 0;
+
+ Macro *it = _hash[hash_code (name) % _hash_count];
+ for (; it; it = it->next) {
+ if (it->name != name)
+ continue;
+ else if (it->hidden)
+ return 0;
+ else break;
+ }
+ return it;
+}
+
+unsigned Environment::hash_code (const QByteArray &s)
+{
+ unsigned hash_value = 0;
+
+ for (int i = 0; i < s.size (); ++i)
+ hash_value = (hash_value << 5) - hash_value + s.at (i);
+
+ return hash_value;
+}
+
+void Environment::rehash()
+{
+ if (_hash) {
+ free(_hash);
+ _hash_count <<= 1;
+ }
+
+ _hash = (Macro **) calloc(_hash_count, sizeof(Macro *));
+
+ for (Macro **it = firstMacro(); it != lastMacro(); ++it) {
+ Macro *m= *it;
+ const unsigned h = m->hashcode % _hash_count;
+ m->next = _hash[h];
+ _hash[h] = m;
+ }
+}
diff --git a/src/plugins/cpptools/rpp/pp-environment.h b/src/plugins/cpptools/rpp/pp-environment.h
new file mode 100644
index 0000000000..cdecf4de61
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-environment.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_ENVIRONMENT_H
+#define PP_ENVIRONMENT_H
+
+#include <QVector>
+#include <QByteArray>
+
+namespace rpp {
+
+struct Macro;
+
+class Environment
+{
+public:
+ Environment();
+ ~Environment();
+
+ unsigned macroCount() const;
+ Macro *macroAt(unsigned index) const;
+
+ Macro *bind(const Macro &macro);
+ void remove(const QByteArray &name);
+
+ Macro *resolve(const QByteArray &name) const;
+ bool isBuiltinMacro(const QByteArray &name) const;
+
+ const Macro *const *firstMacro() const
+ { return _macros; }
+
+ Macro **firstMacro()
+ { return _macros; }
+
+ const Macro *const *lastMacro() const
+ { return _macros + _macro_count + 1; }
+
+ Macro **lastMacro()
+ { return _macros + _macro_count + 1; }
+
+private:
+ static unsigned hash_code (const QByteArray &s);
+ void rehash();
+
+public:
+ QByteArray current_file;
+ unsigned currentLine;
+ bool hide_next;
+
+private:
+ Macro **_macros;
+ int _allocated_macros;
+ int _macro_count;
+ Macro **_hash;
+ int _hash_count;
+};
+
+} // namespace rpp
+
+#endif // PP_ENVIRONMENT_H
diff --git a/src/plugins/cpptools/rpp/pp-fwd.h b/src/plugins/cpptools/rpp/pp-fwd.h
new file mode 100644
index 0000000000..05b68774cf
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-fwd.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_FWD_H
+#define PP_FWD_H
+
+namespace rpp {
+
+} // namespace rpp
+
+#endif // PP_FWD_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-internal.h b/src/plugins/cpptools/rpp/pp-internal.h
new file mode 100644
index 0000000000..eed958372c
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-internal.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_INTERNAL_H
+#define PP_INTERNAL_H
+
+#include <QByteArray>
+
+namespace rpp {
+
+ namespace _PP_internal
+ {
+
+ inline void output_line(const QByteArray &__filename, int __line, QByteArray *__result)
+ {
+ QByteArray __msg;
+
+ __msg += "# ";
+
+ char __line_descr[16];
+ qsnprintf (__line_descr, 16, "%d", __line);
+ __msg += __line_descr;
+
+ __msg += " \"";
+
+ if (__filename.isEmpty ())
+ __msg += "<editor>";
+ else
+ __msg += __filename;
+
+ __msg += "\"\n";
+ __result->append(__msg);
+ }
+
+ inline bool comment_p (const char *__first, const char *__last)
+ {
+ if (__first == __last)
+ return false;
+
+ if (*__first != '/')
+ return false;
+
+ if (++__first == __last)
+ return false;
+
+ return (*__first == '/' || *__first == '*');
+ }
+
+ } // _PP_internal
+
+} // namespace rpp
+
+#endif // PP_INTERNAL_H
diff --git a/src/plugins/cpptools/rpp/pp-macro-expander.cpp b/src/plugins/cpptools/rpp/pp-macro-expander.cpp
new file mode 100644
index 0000000000..658f2acc67
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro-expander.cpp
@@ -0,0 +1,362 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "pp.h"
+#include "pp-macro-expander.h"
+#include <QDateTime>
+
+using namespace rpp;
+
+MacroExpander::MacroExpander (Environment &env, pp_frame *frame)
+ : env (env), frame (frame),
+ lines (0), generated_lines (0)
+{ }
+
+const QByteArray *MacroExpander::resolve_formal (const QByteArray &__name)
+{
+ if (! (frame && frame->expanding_macro))
+ return 0;
+
+ const QVector<QByteArray> &formals = frame->expanding_macro->formals;
+ for (int index = 0; index < formals.size(); ++index) {
+ const QByteArray formal = formals.at(index);
+
+ if (formal == __name && index < frame->actuals.size())
+ return &frame->actuals.at(index);
+ }
+
+ return 0;
+}
+
+const char *MacroExpander::operator () (const char *__first, const char *__last,
+ QByteArray *__result)
+{
+ generated_lines = 0;
+ __first = skip_blanks (__first, __last);
+ lines = skip_blanks.lines;
+
+ while (__first != __last)
+ {
+ if (*__first == '\n')
+ {
+ __result->append('\n');
+ __result->append('#');
+ __result->append(QByteArray::number(env.currentLine));
+ __result->append(' ');
+ __result->append('"');
+ __result->append(env.current_file);
+ __result->append('"');
+ __result->append('\n');
+ ++lines;
+
+ __first = skip_blanks (++__first, __last);
+ lines += skip_blanks.lines;
+
+ if (__first != __last && *__first == '#')
+ break;
+ }
+ else if (*__first == '#')
+ {
+ __first = skip_blanks (++__first, __last);
+ lines += skip_blanks.lines;
+
+ const char *end_id = skip_identifier (__first, __last);
+ const QByteArray fast_name(__first, end_id - __first);
+ __first = end_id;
+
+ if (const QByteArray *actual = resolve_formal (fast_name))
+ {
+ __result->append('\"');
+
+ const char *actual_begin = actual->constData ();
+ const char *actual_end = actual_begin + actual->size ();
+
+ for (const char *it = skip_whitespaces (actual_begin, actual_end);
+ it != actual_end; ++it)
+ {
+ if (*it == '"' || *it == '\\')
+ {
+ __result->append('\\');
+ __result->append(*it);
+ }
+ else if (*it == '\n')
+ {
+ __result->append('"');
+ __result->append('\n');
+ __result->append('"');
+ }
+ else
+ __result->append(*it);
+ }
+
+ __result->append('\"');
+ }
+ else
+ __result->append('#'); // ### warning message?
+ }
+ else if (*__first == '\"')
+ {
+ const char *next_pos = skip_string_literal (__first, __last);
+ lines += skip_string_literal.lines;
+ __result->append(__first, next_pos - __first);
+ __first = next_pos;
+ }
+ else if (*__first == '\'')
+ {
+ const char *next_pos = skip_char_literal (__first, __last);
+ lines += skip_char_literal.lines;
+ __result->append(__first, next_pos - __first);
+ __first = next_pos;
+ }
+ else if (_PP_internal::comment_p (__first, __last))
+ {
+ __first = skip_comment_or_divop (__first, __last);
+ int n = skip_comment_or_divop.lines;
+ lines += n;
+
+ while (n-- > 0)
+ __result->append('\n');
+ }
+ else if (pp_isspace (*__first))
+ {
+ for (; __first != __last; ++__first)
+ {
+ if (*__first == '\n' || !pp_isspace (*__first))
+ break;
+ }
+
+ __result->append(' ');
+ }
+ else if (pp_isdigit (*__first))
+ {
+ const char *next_pos = skip_number (__first, __last);
+ lines += skip_number.lines;
+ __result->append(__first, next_pos - __first);
+ __first = next_pos;
+ }
+ else if (pp_isalpha (*__first) || *__first == '_')
+ {
+ const char *name_begin = __first;
+ const char *name_end = skip_identifier (__first, __last);
+ __first = name_end; // advance
+
+ // search for the paste token
+ const char *next = skip_blanks (__first, __last);
+ bool paste = false;
+ if (next != __last && *next == '#')
+ {
+ paste = true;
+ ++next;
+ if (next != __last && *next == '#')
+ __first = skip_blanks(++next, __last);
+ }
+
+ const QByteArray fast_name(name_begin, name_end - name_begin);
+
+ if (const QByteArray *actual = resolve_formal (fast_name))
+ {
+ const char *begin = actual->constData ();
+ const char *end = begin + actual->size ();
+ if (paste) {
+ for (--end; end != begin - 1; --end) {
+ if (! pp_isspace(*end))
+ break;
+ }
+ ++end;
+ }
+ __result->append(begin, end - begin);
+ continue;
+ }
+
+ Macro *macro = env.resolve (fast_name);
+ if (! macro || macro->hidden || env.hide_next)
+ {
+ if (fast_name.size () == 7 && fast_name [0] == 'd' && fast_name == "defined")
+ env.hide_next = true;
+ else
+ env.hide_next = false;
+
+ if (fast_name.size () == 8 && fast_name [0] == '_' && fast_name [1] == '_')
+ {
+ if (fast_name == "__LINE__")
+ {
+ char buf [16];
+ const size_t count = qsnprintf (buf, 16, "%d", env.currentLine + lines);
+ __result->append(buf, count);
+ continue;
+ }
+
+ else if (fast_name == "__FILE__")
+ {
+ __result->append('"');
+ __result->append(env.current_file);
+ __result->append('"');
+ continue;
+ }
+
+ else if (fast_name == "__DATE__")
+ {
+ __result->append('"');
+ __result->append(QDate::currentDate().toString().toUtf8());
+ __result->append('"');
+ continue;
+ }
+
+ else if (fast_name == "__TIME__")
+ {
+ __result->append('"');
+ __result->append(QTime::currentTime().toString().toUtf8());
+ __result->append('"');
+ continue;
+ }
+
+ }
+
+ __result->append(name_begin, name_end - name_begin);
+ continue;
+ }
+
+ if (! macro->function_like)
+ {
+ Macro *m = 0;
+
+ if (! macro->definition.isEmpty())
+ {
+ macro->hidden = true;
+
+ QByteArray __tmp;
+ __tmp.reserve (256);
+
+ MacroExpander expand_macro (env);
+ expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), &__tmp);
+ generated_lines += expand_macro.lines;
+
+ if (! __tmp.isEmpty ())
+ {
+ const char *__tmp_begin = __tmp.constBegin();
+ const char *__tmp_end = __tmp.constEnd();
+ const char *__begin_id = skip_whitespaces (__tmp_begin, __tmp_end);
+ const char *__end_id = skip_identifier (__begin_id, __tmp_end);
+
+ if (__end_id == __tmp_end)
+ {
+ const QByteArray __id (__begin_id, __end_id - __begin_id);
+ m = env.resolve (__id);
+ }
+
+ if (! m)
+ *__result += __tmp;
+ }
+
+ macro->hidden = false;
+ }
+
+ if (! m)
+ continue;
+
+ macro = m;
+ }
+
+ // function like macro
+ const char *arg_it = skip_whitespaces (__first, __last);
+
+ if (arg_it == __last || *arg_it != '(')
+ {
+ __result->append(name_begin, name_end - name_begin);
+ lines += skip_whitespaces.lines;
+ __first = arg_it;
+ continue;
+ }
+
+ QVector<QByteArray> actuals;
+ actuals.reserve (5);
+ ++arg_it; // skip '('
+
+ MacroExpander expand_actual (env, frame);
+
+ const char *arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ if (arg_it != arg_end)
+ {
+ const QByteArray actual (arg_it, arg_end - arg_it);
+ QByteArray expanded;
+ expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
+ actuals.push_back (expanded);
+ arg_it = arg_end;
+ }
+
+ while (arg_it != __last && *arg_end == ',')
+ {
+ ++arg_it; // skip ','
+
+ arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ const QByteArray actual (arg_it, arg_end - arg_it);
+ QByteArray expanded;
+ expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
+ actuals.push_back (expanded);
+ arg_it = arg_end;
+ }
+
+ if (! (arg_it != __last && *arg_it == ')'))
+ return __last;
+
+ ++arg_it; // skip ')'
+ __first = arg_it;
+
+ pp_frame frame (macro, actuals);
+ MacroExpander expand_macro (env, &frame);
+ macro->hidden = true;
+ expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), __result);
+ macro->hidden = false;
+ generated_lines += expand_macro.lines;
+ }
+ else
+ __result->append(*__first++);
+ }
+
+ return __first;
+}
+
+const char *MacroExpander::skip_argument_variadics (QVector<QByteArray> const &__actuals,
+ Macro *__macro,
+ const char *__first, const char *__last)
+{
+ const char *arg_end = skip_argument (__first, __last);
+
+ while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ','
+ && (__actuals.size () + 1) == __macro->formals.size ())
+ {
+ arg_end = skip_argument (++arg_end, __last);
+ }
+
+ return arg_end;
+}
diff --git a/src/plugins/cpptools/rpp/pp-macro-expander.h b/src/plugins/cpptools/rpp/pp-macro-expander.h
new file mode 100644
index 0000000000..bdf21a421b
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro-expander.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_MACRO_EXPANDER_H
+#define PP_MACRO_EXPANDER_H
+
+namespace rpp {
+
+ struct pp_frame
+ {
+ Macro *expanding_macro;
+ const QVector<QByteArray> actuals;
+
+ pp_frame (Macro *expanding_macro, const QVector<QByteArray> &actuals)
+ : expanding_macro (expanding_macro),
+ actuals (actuals)
+ { }
+ };
+
+ class MacroExpander
+ {
+ Environment &env;
+ pp_frame *frame;
+
+ pp_skip_number skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_argument skip_argument;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+ pp_skip_whitespaces skip_whitespaces;
+
+ const QByteArray *resolve_formal (const QByteArray &name);
+
+ public:
+ MacroExpander (Environment &env, pp_frame *frame = 0);
+
+ const char *operator () (const char *first, const char *last,
+ QByteArray *result);
+
+ const char *skip_argument_variadics (const QVector<QByteArray> &actuals,
+ Macro *macro,
+ const char *first, const char *last);
+
+ public: // attributes
+ int lines;
+ int generated_lines;
+ };
+
+} // namespace rpp
+
+#endif // PP_MACRO_EXPANDER_H
+
diff --git a/src/plugins/cpptools/rpp/pp-macro.h b/src/plugins/cpptools/rpp/pp-macro.h
new file mode 100644
index 0000000000..b220168989
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_MACRO_H
+#define PP_MACRO_H
+
+#include <QByteArray>
+#include <QVector>
+
+namespace rpp {
+
+ struct Macro
+ {
+ QByteArray name;
+ QByteArray definition;
+ QVector<QByteArray> formals;
+ QByteArray fileName;
+ int line;
+ int lines;
+ Macro *next;
+ unsigned hashcode;
+
+ union
+ {
+ unsigned state;
+
+ struct
+ {
+ unsigned hidden: 1;
+ unsigned function_like: 1;
+ unsigned variadics: 1;
+ };
+ };
+
+ inline Macro():
+ line(0),
+ lines(0),
+ next(0),
+ hashcode(0),
+ state(0)
+ { }
+ };
+
+} // namespace rpp
+
+#endif // PP_MACRO_H
diff --git a/src/plugins/cpptools/rpp/pp-scanner.h b/src/plugins/cpptools/rpp/pp-scanner.h
new file mode 100644
index 0000000000..d9036d8855
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-scanner.h
@@ -0,0 +1,380 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_SCANNER_H
+#define PP_SCANNER_H
+
+namespace rpp {
+
+struct pp_skip_blanks
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (*__first == '\\')
+ {
+ const char *__begin = __first;
+ ++__begin;
+
+ if (__begin != __last && *__begin == '\n')
+ ++__first;
+ else
+ break;
+ }
+ else if (*__first == '\n' || !pp_isspace (*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_whitespaces
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isspace (*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_comment_or_divop
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ MAYBE_BEGIN,
+ BEGIN,
+ MAYBE_END,
+ END,
+ IN_COMMENT,
+ IN_CXX_COMMENT
+ } state (MAYBE_BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case MAYBE_BEGIN:
+ if (*__first != '/')
+ return __first;
+
+ state = BEGIN;
+ break;
+
+ case BEGIN:
+ if (*__first == '*')
+ state = IN_COMMENT;
+ else if (*__first == '/')
+ state = IN_CXX_COMMENT;
+ else
+ return __first;
+ break;
+
+ case IN_COMMENT:
+ if (*__first == '*')
+ state = MAYBE_END;
+ break;
+
+ case IN_CXX_COMMENT:
+ if (*__first == '\n')
+ return __first;
+ break;
+
+ case MAYBE_END:
+ if (*__first == '/')
+ state = END;
+ else if (*__first != '*')
+ state = IN_COMMENT;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_identifier
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isalnum (*__first) && *__first != '_')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_number
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isalnum (*__first) && *__first != '.')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_string_literal
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\"')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ if (! (*__first != '\n'))
+ return __last;
+
+ if (*__first == '\"')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_char_literal
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ lines = 0;
+
+ for (; state != END && __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\'')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ if (! (*__first != '\n'))
+ return __last;
+
+ if (*__first == '\'')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_argument
+{
+ pp_skip_identifier skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ int depth = 0;
+ lines = 0;
+
+ while (__first != __last)
+ {
+ if (!depth && (*__first == ')' || *__first == ','))
+ break;
+ else if (*__first == '(')
+ ++depth, ++__first;
+ else if (*__first == ')')
+ --depth, ++__first;
+ else if (*__first == '\"')
+ {
+ __first = skip_string_literal (__first, __last);
+ lines += skip_string_literal.lines;
+ }
+ else if (*__first == '\'')
+ {
+ __first = skip_char_literal (__first, __last);
+ lines += skip_char_literal.lines;
+ }
+ else if (*__first == '/')
+ {
+ __first = skip_comment_or_divop (__first, __last);
+ lines += skip_comment_or_divop.lines;
+ }
+ else if (pp_isalpha (*__first) || *__first == '_')
+ {
+ __first = skip_identifier (__first, __last);
+ lines += skip_identifier.lines;
+ }
+ else if (pp_isdigit (*__first))
+ {
+ __first = skip_number (__first, __last);
+ lines += skip_number.lines;
+ }
+ else if (*__first == '\n')
+ {
+ ++__first;
+ ++lines;
+ }
+ else
+ ++__first;
+ }
+
+ return __first;
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_SCANNER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-symbol.h b/src/plugins/cpptools/rpp/pp-symbol.h
new file mode 100644
index 0000000000..37e2a623e5
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-symbol.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
diff --git a/src/plugins/cpptools/rpp/pp.h b/src/plugins/cpptools/rpp/pp.h
new file mode 100644
index 0000000000..52411f7624
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_H
+#define PP_H
+
+#if defined(_WIN64) || defined(WIN64) || defined(__WIN64__) \
+ || defined(_WIN32) || defined(WIN32) || defined(__WIN32__)
+# define PP_OS_WIN
+#endif
+
+#include <cassert>
+#include <cstring>
+#include <cctype>
+
+#include "pp-fwd.h"
+#include "pp-cctype.h"
+#include "pp-symbol.h"
+#include "pp-internal.h"
+#include "pp-macro.h"
+#include "pp-environment.h"
+#include "pp-scanner.h"
+#include "pp-macro-expander.h"
+#include "pp-engine.h"
+#include "pp-client.h"
+
+#endif // PP_H
diff --git a/src/plugins/cpptools/rpp/rpp.pri b/src/plugins/cpptools/rpp/rpp.pri
new file mode 100644
index 0000000000..f47976e6fe
--- /dev/null
+++ b/src/plugins/cpptools/rpp/rpp.pri
@@ -0,0 +1,20 @@
+DEPENDPATH += $$PWD
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/pp-cctype.h \
+ $$PWD/pp-engine.h \
+ $$PWD/pp-environment.h \
+ $$PWD/pp-fwd.h \
+ $$PWD/pp-internal.h \
+ $$PWD/pp-macro-expander.h \
+ $$PWD/pp-macro.h \
+ $$PWD/pp-scanner.h \
+ $$PWD/pp-symbol.h \
+ $$PWD/pp.h \
+ $$PWD/pp-client.h
+
+SOURCES += $$PWD/pp-engine.cpp \
+ $$PWD/pp-environment.cpp \
+ $$PWD/pp-macro-expander.cpp
+
+
diff --git a/src/plugins/debugger/Debugger.pluginspec b/src/plugins/debugger/Debugger.pluginspec
new file mode 100644
index 0000000000..d68c17517e
--- /dev/null
+++ b/src/plugins/debugger/Debugger.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="Debugger" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Debugger integration.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="CppEditor" version="0.9.1"/><!-- Debugger plugin adds items to the editor's context menu -->
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="Find" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/debugger/assert.h b/src/plugins/debugger/assert.h
new file mode 100644
index 0000000000..a4310040fe
--- /dev/null
+++ b/src/plugins/debugger/assert.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_QWB_ASSERT_H
+#define DEBUGGER_QWB_ASSERT_H
+
+#ifdef Q_OS_UNIX
+#define QWB_ASSERT(cond, action) \
+ if(cond){}else{qDebug()<<"ASSERTION"<<#cond<<"FAILED"<<__FILE__<<__LINE__;action;}
+#else
+#define QWB_ASSERT(cond, action) \
+ if(cond){}else{qDebug()<<"ASSERTION"<<#cond<<"FAILED";action;}
+#endif
+
+#endif
+
diff --git a/src/plugins/debugger/attachexternaldialog.cpp b/src/plugins/debugger/attachexternaldialog.cpp
new file mode 100644
index 0000000000..5aeec2ec62
--- /dev/null
+++ b/src/plugins/debugger/attachexternaldialog.cpp
@@ -0,0 +1,344 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "attachexternaldialog.h"
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QPushButton>
+#include <QStandardItemModel>
+#include <QHeaderView>
+
+using namespace Debugger::Internal;
+
+AttachExternalDialog::AttachExternalDialog(QWidget *parent, const QString &pid)
+ : QDialog(parent)
+{
+ setupUi(this);
+ buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ m_defaultPID = pid;
+ m_model = new QStandardItemModel(this);
+
+ procView->setSortingEnabled(true);
+
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ connect(procView, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(procSelected(const QModelIndex &)));
+
+
+ pidLineEdit->setText(m_defaultPID);
+ rebuildProcessList();
+}
+
+static bool isProcessName(const QString &procname)
+{
+ for (int i = 0; i != procname.size(); ++i)
+ if (!procname.at(i).isDigit())
+ return false;
+ return true;
+}
+
+struct ProcData {
+ QString ppid;
+ QString name;
+ QString state;
+};
+
+static void insertItem(QStandardItem *root, const QString &pid,
+ const QMap<QString, ProcData> &procs, QMap<QString, QStandardItem *> &known)
+{
+ //qDebug() << "HANDLING " << pid;
+ QStandardItem *parent = 0;
+ const ProcData &proc = procs[pid];
+ if (1 || pid == "0") {
+ parent = root;
+ } else {
+ if (!known.contains(proc.ppid))
+ insertItem(root, proc.ppid, procs, known);
+ parent = known[proc.ppid];
+ }
+ QList<QStandardItem *> row;
+ row.append(new QStandardItem(pid));
+ row.append(new QStandardItem(proc.name));
+ //row.append(new QStandardItem(proc.ppid));
+ row.append(new QStandardItem(proc.state));
+ parent->appendRow(row);
+ known[pid] = row[0];
+}
+
+void AttachExternalDialog::rebuildProcessList()
+{
+ QStringList procnames = QDir("/proc/").entryList();
+ if (procnames.isEmpty()) {
+ procView->hide();
+ return;
+ }
+
+ typedef QMap<QString, ProcData> Procs;
+ Procs procs;
+
+ foreach (const QString &procname, procnames) {
+ if (!isProcessName(procname))
+ continue;
+ QString filename = "/proc/" + procname + "/stat";
+ QFile file(filename);
+ file.open(QIODevice::ReadOnly);
+ QStringList data = QString::fromLocal8Bit(file.readAll()).split(' ');
+ //qDebug() << filename << data;
+ ProcData proc;
+ proc.name = data.at(1);
+ if (proc.name.startsWith('(') && proc.name.endsWith(')'))
+ proc.name = proc.name.mid(1, proc.name.size() - 2);
+ proc.state = data.at(2);
+ proc.ppid = data.at(3);
+ procs[procname] = proc;
+ }
+
+ m_model->clear();
+ QMap<QString, QStandardItem *> known;
+ for (Procs::const_iterator it = procs.begin(); it != procs.end(); ++it)
+ insertItem(m_model->invisibleRootItem(), it.key(), procs, known);
+ m_model->setHeaderData(0, Qt::Horizontal, "Process ID", Qt::DisplayRole);
+ m_model->setHeaderData(1, Qt::Horizontal, "Name", Qt::DisplayRole);
+ //model->setHeaderData(2, Qt::Horizontal, "Parent", Qt::DisplayRole);
+ m_model->setHeaderData(2, Qt::Horizontal, "State", Qt::DisplayRole);
+
+ procView->setModel(m_model);
+ procView->expandAll();
+ procView->resizeColumnToContents(0);
+ procView->resizeColumnToContents(1);
+}
+
+#ifdef Q_OS_WINDOWS
+
+#include <windows.h>
+#include <tlhelp32.h>
+#include <tchar.h>
+#include <stdio.h>
+
+// Forward declarations:
+BOOL GetProcessList( );
+BOOL ListProcessModules( DWORD dwPID );
+BOOL ListProcessThreads( DWORD dwOwnerPID );
+void printError( TCHAR* msg );
+
+BOOL GetProcessList( )
+{
+ HANDLE hProcessSnap;
+ HANDLE hProcess;
+ PROCESSENTRY32 pe32;
+ DWORD dwPriorityClass;
+
+ // Take a snapshot of all processes in the system.
+ hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+ if( hProcessSnap == INVALID_HANDLE_VALUE )
+ {
+ printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
+ return( FALSE );
+ }
+
+ // Set the size of the structure before using it.
+ pe32.dwSize = sizeof( PROCESSENTRY32 );
+
+ // Retrieve information about the first process,
+ // and exit if unsuccessful
+ if( !Process32First( hProcessSnap, &pe32 ) )
+ {
+ printError( TEXT("Process32First") ); // show cause of failure
+ CloseHandle( hProcessSnap ); // clean the snapshot object
+ return( FALSE );
+ }
+
+ // Now walk the snapshot of processes, and
+ // display information about each process in turn
+ do
+ {
+ printf( "\n\n=====================================================" );
+ _tprintf( TEXT("\nPROCESS NAME: %s"), pe32.szExeFile );
+ printf( "\n-----------------------------------------------------" );
+
+ // Retrieve the priority class.
+ dwPriorityClass = 0;
+ hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
+ if( hProcess == NULL )
+ printError( TEXT("OpenProcess") );
+ else
+ {
+ dwPriorityClass = GetPriorityClass( hProcess );
+ if( !dwPriorityClass )
+ printError( TEXT("GetPriorityClass") );
+ CloseHandle( hProcess );
+ }
+
+ printf( "\n Process ID = 0x%08X", pe32.th32ProcessID );
+ printf( "\n Thread count = %d", pe32.cntThreads );
+ printf( "\n Parent process ID = 0x%08X", pe32.th32ParentProcessID );
+ printf( "\n Priority base = %d", pe32.pcPriClassBase );
+ if( dwPriorityClass )
+ printf( "\n Priority class = %d", dwPriorityClass );
+
+ // List the modules and threads associated with this process
+ ListProcessModules( pe32.th32ProcessID );
+ ListProcessThreads( pe32.th32ProcessID );
+
+ } while( Process32Next( hProcessSnap, &pe32 ) );
+
+ CloseHandle( hProcessSnap );
+ return( TRUE );
+}
+
+
+BOOL ListProcessModules( DWORD dwPID )
+{
+ HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
+ MODULEENTRY32 me32;
+
+ // Take a snapshot of all modules in the specified process.
+ hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
+ if( hModuleSnap == INVALID_HANDLE_VALUE )
+ {
+ printError( TEXT("CreateToolhelp32Snapshot (of modules)") );
+ return( FALSE );
+ }
+
+ // Set the size of the structure before using it.
+ me32.dwSize = sizeof( MODULEENTRY32 );
+
+ // Retrieve information about the first module,
+ // and exit if unsuccessful
+ if( !Module32First( hModuleSnap, &me32 ) )
+ {
+ printError( TEXT("Module32First") ); // show cause of failure
+ CloseHandle( hModuleSnap ); // clean the snapshot object
+ return( FALSE );
+ }
+
+ // Now walk the module list of the process,
+ // and display information about each module
+ do
+ {
+ _tprintf( TEXT("\n\n MODULE NAME: %s"), me32.szModule );
+ _tprintf( TEXT("\n Executable = %s"), me32.szExePath );
+ printf( "\n Process ID = 0x%08X", me32.th32ProcessID );
+ printf( "\n Ref count (g) = 0x%04X", me32.GlblcntUsage );
+ printf( "\n Ref count (p) = 0x%04X", me32.ProccntUsage );
+ printf( "\n Base address = 0x%08X", (DWORD) me32.modBaseAddr );
+ printf( "\n Base size = %d", me32.modBaseSize );
+
+ } while( Module32Next( hModuleSnap, &me32 ) );
+
+ CloseHandle( hModuleSnap );
+ return( TRUE );
+}
+
+BOOL ListProcessThreads( DWORD dwOwnerPID )
+{
+ HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
+ THREADENTRY32 te32;
+
+ // Take a snapshot of all running threads
+ hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
+ if( hThreadSnap == INVALID_HANDLE_VALUE )
+ return( FALSE );
+
+ // Fill in the size of the structure before using it.
+ te32.dwSize = sizeof(THREADENTRY32 );
+
+ // Retrieve information about the first thread,
+ // and exit if unsuccessful
+ if( !Thread32First( hThreadSnap, &te32 ) )
+ {
+ printError( TEXT("Thread32First") ); // show cause of failure
+ CloseHandle( hThreadSnap ); // clean the snapshot object
+ return( FALSE );
+ }
+
+ // Now walk the thread list of the system,
+ // and display information about each thread
+ // associated with the specified process
+ do
+ {
+ if( te32.th32OwnerProcessID == dwOwnerPID )
+ {
+ printf( "\n\n THREAD ID = 0x%08X", te32.th32ThreadID );
+ printf( "\n Base priority = %d", te32.tpBasePri );
+ printf( "\n Delta priority = %d", te32.tpDeltaPri );
+ }
+ } while( Thread32Next(hThreadSnap, &te32 ) );
+
+ CloseHandle( hThreadSnap );
+ return( TRUE );
+}
+
+void printError( TCHAR* msg )
+{
+ DWORD eNum;
+ TCHAR sysMsg[256];
+ TCHAR* p;
+
+ eNum = GetLastError( );
+ FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, eNum,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ sysMsg, 256, NULL );
+
+ // Trim the end of the line and terminate it with a null
+ p = sysMsg;
+ while( ( *p > 31 ) || ( *p == 9 ) )
+ ++p;
+ do { *p-- = 0; } while( ( p >= sysMsg ) &&
+ ( ( *p == '.' ) || ( *p < 33 ) ) );
+
+ // Display the message
+ _tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
+}
+
+#endif
+
+
+void AttachExternalDialog::procSelected(const QModelIndex &index0)
+{
+ QModelIndex index = index0.sibling(index0.row(), 0);
+ QStandardItem *item = m_model->itemFromIndex(index);
+ if (!item)
+ return;
+ pidLineEdit->setText(item->text());
+ accept();
+}
+
+int AttachExternalDialog::attachPID() const
+{
+ return pidLineEdit->text().toInt();
+}
diff --git a/src/plugins/debugger/attachexternaldialog.h b/src/plugins/debugger/attachexternaldialog.h
new file mode 100644
index 0000000000..6c77d206b6
--- /dev/null
+++ b/src/plugins/debugger/attachexternaldialog.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ATTACHEXTERNALDIALOG_H
+#define ATTACHEXTERNALDIALOG_H
+
+#include "ui_attachexternaldialog.h"
+
+QT_BEGIN_NAMESPACE
+class QStandardItemModel;
+QT_END_NAMESPACE
+
+namespace Debugger {
+namespace Internal {
+
+class AttachExternalDialog : public QDialog, Ui::AttachExternalDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AttachExternalDialog(QWidget *parent, const QString &pid);
+ int attachPID() const;
+
+private slots:
+ void rebuildProcessList();
+ void procSelected(const QModelIndex &);
+
+private:
+ QString m_defaultPID;
+ QStandardItemModel *m_model;
+};
+
+} // namespace Debugger
+} // namespace Internal
+
+#endif // ATTACHEEXTERNALDIALOG_H
diff --git a/src/plugins/debugger/attachexternaldialog.ui b/src/plugins/debugger/attachexternaldialog.ui
new file mode 100644
index 0000000000..63f214c51e
--- /dev/null
+++ b/src/plugins/debugger/attachexternaldialog.ui
@@ -0,0 +1,64 @@
+<ui version="4.0" >
+ <class>AttachExternalDialog</class>
+ <widget class="QDialog" name="AttachExternalDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>561</width>
+ <height>866</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="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QLabel" name="pidLabel" >
+ <property name="text" >
+ <string>Attach to Process ID:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="pidLineEdit" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="procView" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </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>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/attachremotedialog.cpp b/src/plugins/debugger/attachremotedialog.cpp
new file mode 100644
index 0000000000..ffd09e7b78
--- /dev/null
+++ b/src/plugins/debugger/attachremotedialog.cpp
@@ -0,0 +1,344 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "attachremotedialog.h"
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QPushButton>
+#include <QStandardItemModel>
+#include <QHeaderView>
+
+using namespace Debugger::Internal;
+
+AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid)
+ : QDialog(parent)
+{
+ setupUi(this);
+ buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ m_defaultPID = pid;
+ m_model = new QStandardItemModel(this);
+
+ procView->setSortingEnabled(true);
+
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ connect(procView, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(procSelected(const QModelIndex &)));
+
+
+ pidLineEdit->setText(m_defaultPID);
+ rebuildProcessList();
+}
+
+static bool isProcessName(const QString &procname)
+{
+ for (int i = 0; i != procname.size(); ++i)
+ if (!procname.at(i).isDigit())
+ return false;
+ return true;
+}
+
+struct ProcData {
+ QString ppid;
+ QString name;
+ QString state;
+};
+
+static void insertItem(QStandardItem *root, const QString &pid,
+ const QMap<QString, ProcData> &procs, QMap<QString, QStandardItem *> &known)
+{
+ //qDebug() << "HANDLING " << pid;
+ QStandardItem *parent = 0;
+ const ProcData &proc = procs[pid];
+ if (1 || pid == "0") {
+ parent = root;
+ } else {
+ if (!known.contains(proc.ppid))
+ insertItem(root, proc.ppid, procs, known);
+ parent = known[proc.ppid];
+ }
+ QList<QStandardItem *> row;
+ row.append(new QStandardItem(pid));
+ row.append(new QStandardItem(proc.name));
+ //row.append(new QStandardItem(proc.ppid));
+ row.append(new QStandardItem(proc.state));
+ parent->appendRow(row);
+ known[pid] = row[0];
+}
+
+void AttachRemoteDialog::rebuildProcessList()
+{
+ QStringList procnames = QDir("/proc/").entryList();
+ if (procnames.isEmpty()) {
+ procView->hide();
+ return;
+ }
+
+ typedef QMap<QString, ProcData> Procs;
+ Procs procs;
+
+ foreach (const QString &procname, procnames) {
+ if (!isProcessName(procname))
+ continue;
+ QString filename = "/proc/" + procname + "/stat";
+ QFile file(filename);
+ file.open(QIODevice::ReadOnly);
+ QStringList data = QString::fromLocal8Bit(file.readAll()).split(' ');
+ //qDebug() << filename << data;
+ ProcData proc;
+ proc.name = data.at(1);
+ if (proc.name.startsWith('(') && proc.name.endsWith(')'))
+ proc.name = proc.name.mid(1, proc.name.size() - 2);
+ proc.state = data.at(2);
+ proc.ppid = data.at(3);
+ procs[procname] = proc;
+ }
+
+ m_model->clear();
+ QMap<QString, QStandardItem *> known;
+ for (Procs::const_iterator it = procs.begin(); it != procs.end(); ++it)
+ insertItem(m_model->invisibleRootItem(), it.key(), procs, known);
+ m_model->setHeaderData(0, Qt::Horizontal, "Process ID", Qt::DisplayRole);
+ m_model->setHeaderData(1, Qt::Horizontal, "Name", Qt::DisplayRole);
+ //model->setHeaderData(2, Qt::Horizontal, "Parent", Qt::DisplayRole);
+ m_model->setHeaderData(2, Qt::Horizontal, "State", Qt::DisplayRole);
+
+ procView->setModel(m_model);
+ procView->expandAll();
+ procView->resizeColumnToContents(0);
+ procView->resizeColumnToContents(1);
+}
+
+#ifdef Q_OS_WINDOWS
+
+#include <windows.h>
+#include <tlhelp32.h>
+#include <tchar.h>
+#include <stdio.h>
+
+// Forward declarations:
+BOOL GetProcessList( );
+BOOL ListProcessModules( DWORD dwPID );
+BOOL ListProcessThreads( DWORD dwOwnerPID );
+void printError( TCHAR* msg );
+
+BOOL GetProcessList( )
+{
+ HANDLE hProcessSnap;
+ HANDLE hProcess;
+ PROCESSENTRY32 pe32;
+ DWORD dwPriorityClass;
+
+ // Take a snapshot of all processes in the system.
+ hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+ if( hProcessSnap == INVALID_HANDLE_VALUE )
+ {
+ printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
+ return( FALSE );
+ }
+
+ // Set the size of the structure before using it.
+ pe32.dwSize = sizeof( PROCESSENTRY32 );
+
+ // Retrieve information about the first process,
+ // and exit if unsuccessful
+ if( !Process32First( hProcessSnap, &pe32 ) )
+ {
+ printError( TEXT("Process32First") ); // show cause of failure
+ CloseHandle( hProcessSnap ); // clean the snapshot object
+ return( FALSE );
+ }
+
+ // Now walk the snapshot of processes, and
+ // display information about each process in turn
+ do
+ {
+ printf( "\n\n=====================================================" );
+ _tprintf( TEXT("\nPROCESS NAME: %s"), pe32.szExeFile );
+ printf( "\n-----------------------------------------------------" );
+
+ // Retrieve the priority class.
+ dwPriorityClass = 0;
+ hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
+ if( hProcess == NULL )
+ printError( TEXT("OpenProcess") );
+ else
+ {
+ dwPriorityClass = GetPriorityClass( hProcess );
+ if( !dwPriorityClass )
+ printError( TEXT("GetPriorityClass") );
+ CloseHandle( hProcess );
+ }
+
+ printf( "\n Process ID = 0x%08X", pe32.th32ProcessID );
+ printf( "\n Thread count = %d", pe32.cntThreads );
+ printf( "\n Parent process ID = 0x%08X", pe32.th32ParentProcessID );
+ printf( "\n Priority base = %d", pe32.pcPriClassBase );
+ if( dwPriorityClass )
+ printf( "\n Priority class = %d", dwPriorityClass );
+
+ // List the modules and threads associated with this process
+ ListProcessModules( pe32.th32ProcessID );
+ ListProcessThreads( pe32.th32ProcessID );
+
+ } while( Process32Next( hProcessSnap, &pe32 ) );
+
+ CloseHandle( hProcessSnap );
+ return( TRUE );
+}
+
+
+BOOL ListProcessModules( DWORD dwPID )
+{
+ HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
+ MODULEENTRY32 me32;
+
+ // Take a snapshot of all modules in the specified process.
+ hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
+ if( hModuleSnap == INVALID_HANDLE_VALUE )
+ {
+ printError( TEXT("CreateToolhelp32Snapshot (of modules)") );
+ return( FALSE );
+ }
+
+ // Set the size of the structure before using it.
+ me32.dwSize = sizeof( MODULEENTRY32 );
+
+ // Retrieve information about the first module,
+ // and exit if unsuccessful
+ if( !Module32First( hModuleSnap, &me32 ) )
+ {
+ printError( TEXT("Module32First") ); // show cause of failure
+ CloseHandle( hModuleSnap ); // clean the snapshot object
+ return( FALSE );
+ }
+
+ // Now walk the module list of the process,
+ // and display information about each module
+ do
+ {
+ _tprintf( TEXT("\n\n MODULE NAME: %s"), me32.szModule );
+ _tprintf( TEXT("\n Executable = %s"), me32.szExePath );
+ printf( "\n Process ID = 0x%08X", me32.th32ProcessID );
+ printf( "\n Ref count (g) = 0x%04X", me32.GlblcntUsage );
+ printf( "\n Ref count (p) = 0x%04X", me32.ProccntUsage );
+ printf( "\n Base address = 0x%08X", (DWORD) me32.modBaseAddr );
+ printf( "\n Base size = %d", me32.modBaseSize );
+
+ } while( Module32Next( hModuleSnap, &me32 ) );
+
+ CloseHandle( hModuleSnap );
+ return( TRUE );
+}
+
+BOOL ListProcessThreads( DWORD dwOwnerPID )
+{
+ HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
+ THREADENTRY32 te32;
+
+ // Take a snapshot of all running threads
+ hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
+ if( hThreadSnap == INVALID_HANDLE_VALUE )
+ return( FALSE );
+
+ // Fill in the size of the structure before using it.
+ te32.dwSize = sizeof(THREADENTRY32 );
+
+ // Retrieve information about the first thread,
+ // and exit if unsuccessful
+ if( !Thread32First( hThreadSnap, &te32 ) )
+ {
+ printError( TEXT("Thread32First") ); // show cause of failure
+ CloseHandle( hThreadSnap ); // clean the snapshot object
+ return( FALSE );
+ }
+
+ // Now walk the thread list of the system,
+ // and display information about each thread
+ // associated with the specified process
+ do
+ {
+ if( te32.th32OwnerProcessID == dwOwnerPID )
+ {
+ printf( "\n\n THREAD ID = 0x%08X", te32.th32ThreadID );
+ printf( "\n Base priority = %d", te32.tpBasePri );
+ printf( "\n Delta priority = %d", te32.tpDeltaPri );
+ }
+ } while( Thread32Next(hThreadSnap, &te32 ) );
+
+ CloseHandle( hThreadSnap );
+ return( TRUE );
+}
+
+void printError( TCHAR* msg )
+{
+ DWORD eNum;
+ TCHAR sysMsg[256];
+ TCHAR* p;
+
+ eNum = GetLastError( );
+ FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, eNum,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ sysMsg, 256, NULL );
+
+ // Trim the end of the line and terminate it with a null
+ p = sysMsg;
+ while( ( *p > 31 ) || ( *p == 9 ) )
+ ++p;
+ do { *p-- = 0; } while( ( p >= sysMsg ) &&
+ ( ( *p == '.' ) || ( *p < 33 ) ) );
+
+ // Display the message
+ _tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
+}
+
+#endif
+
+
+void AttachRemoteDialog::procSelected(const QModelIndex &index0)
+{
+ QModelIndex index = index0.sibling(index0.row(), 0);
+ QStandardItem *item = m_model->itemFromIndex(index);
+ if (!item)
+ return;
+ pidLineEdit->setText(item->text());
+ accept();
+}
+
+int AttachRemoteDialog::attachPID() const
+{
+ return pidLineEdit->text().toInt();
+}
diff --git a/src/plugins/debugger/attachremotedialog.h b/src/plugins/debugger/attachremotedialog.h
new file mode 100644
index 0000000000..ec732cd515
--- /dev/null
+++ b/src/plugins/debugger/attachremotedialog.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ATTACHREMOTE_DIALOG_H
+#define ATTACHREMOTE_DIALOG_H
+
+#include "ui_attachremotedialog.h"
+
+QT_BEGIN_NAMESPACE
+class QStandardItemModel;
+QT_END_NAMESPACE
+
+namespace Debugger {
+namespace Internal {
+
+class AttachRemoteDialog : public QDialog, Ui::AttachRemoteDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AttachRemoteDialog(QWidget *parent, const QString &pid);
+ int attachPID() const;
+
+private slots:
+ void rebuildProcessList();
+ void procSelected(const QModelIndex &);
+
+private:
+ QString m_defaultPID;
+ QStandardItemModel *m_model;
+};
+
+} // namespace Debugger
+} // namespace Internal
+
+#endif // ATTACHREMOTEDIALOG_H
diff --git a/src/plugins/debugger/attachremotedialog.ui b/src/plugins/debugger/attachremotedialog.ui
new file mode 100644
index 0000000000..4d478e3b0f
--- /dev/null
+++ b/src/plugins/debugger/attachremotedialog.ui
@@ -0,0 +1,64 @@
+<ui version="4.0" >
+ <class>AttachRemoteDialog</class>
+ <widget class="QDialog" name="AttachRemoteDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>561</width>
+ <height>866</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="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QLabel" name="pidLabel" >
+ <property name="text" >
+ <string>Attach to Process ID:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="pidLineEdit" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="procView" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </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>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/breakbyfunction.ui b/src/plugins/debugger/breakbyfunction.ui
new file mode 100644
index 0000000000..06cedb2e46
--- /dev/null
+++ b/src/plugins/debugger/breakbyfunction.ui
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BreakByFunctionDialog</class>
+ <widget class="QDialog" name="BreakByFunctionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>337</width>
+ <height>101</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="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="functionLabel">
+ <property name="text">
+ <string>Function to break on:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="functionLineEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </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>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/breakcondition.ui b/src/plugins/debugger/breakcondition.ui
new file mode 100644
index 0000000000..4de45fd29d
--- /dev/null
+++ b/src/plugins/debugger/breakcondition.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BreakCondition</class>
+ <widget class="QDialog" name="BreakCondition">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>435</width>
+ <height>142</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelCondition">
+ <property name="text">
+ <string>Condition:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEditCondition"/>
+ </item>
+ <item row="1" 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>
+ </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>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>BreakCondition</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>BreakCondition</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
new file mode 100644
index 0000000000..3d83b5e323
--- /dev/null
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -0,0 +1,559 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "breakhandler.h"
+
+#include "assert.h"
+#include "imports.h" // TextEditor::BaseTextMark
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakpointMarker
+//
+//////////////////////////////////////////////////////////////////
+
+namespace Debugger {
+namespace Internal {
+
+
+// The red blob on the left side in the cpp editor.
+class BreakpointMarker : public TextEditor::BaseTextMark
+{
+ Q_OBJECT
+public:
+ BreakpointMarker(BreakpointData *data, const QString &fileName, int lineNumber)
+ : BaseTextMark(fileName, lineNumber), m_data(data), m_pending(true)
+ {
+ //qDebug() << "CREATE MARKER " << fileName << lineNumber;
+ }
+
+ ~BreakpointMarker()
+ {
+ //qDebug() << "REMOVE MARKER ";
+ m_data = 0;
+ }
+
+ QIcon icon() const
+ {
+ static const QIcon icon(":/gdbdebugger/images/breakpoint.svg");
+ static const QIcon icon2(":/gdbdebugger/images/breakpoint_pending.svg");
+ return m_pending ? icon2 : icon;
+ }
+
+ void setPending(bool pending)
+ {
+ if (pending == m_pending)
+ return;
+ m_pending = pending;
+ updateMarker();
+ }
+
+ void updateBlock(const QTextBlock &)
+ {
+ //qDebug() << "BREAKPOINT MARKER UPDATE BLOCK";
+ }
+
+ void removedFromEditor()
+ {
+ if (!m_data)
+ return;
+
+ BreakHandler *handler = m_data->handler();
+ handler->removeBreakpoint(handler->indexOf(m_data));
+ handler->saveBreakpoints();
+ handler->updateMarkers();
+ }
+
+ void updateLineNumber(int lineNumber)
+ {
+ if (!m_data)
+ return;
+ //if (m_data->markerLineNumber == lineNumber)
+ // return;
+ if (m_data->markerLineNumber != lineNumber) {
+ m_data->markerLineNumber = lineNumber;
+ // FIXME: should we tell gdb about the change?
+ // Ignore it for now, as we would require re-compilation
+ // and debugger re-start anyway.
+ if (0 && !m_data->bpLineNumber.isEmpty()) {
+ if (!m_data->bpNumber.trimmed().isEmpty()) {
+ m_data->pending = true;
+ }
+ }
+ }
+ m_data->lineNumber = QString::number(lineNumber);
+ m_data->handler()->updateMarkers();
+ }
+
+private:
+ BreakpointData *m_data;
+ bool m_pending;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakpointData
+//
+//////////////////////////////////////////////////////////////////
+
+BreakpointData::BreakpointData(BreakHandler *handler)
+{
+ //qDebug() << "CREATE BREAKPOINTDATA" << this;
+ m_handler = handler;
+ pending = true;
+ marker = 0;
+ markerLineNumber = 0;
+ bpMultiple = false;
+}
+
+BreakpointData::~BreakpointData()
+{
+ removeMarker();
+ //qDebug() << "DESTROY BREAKPOINTDATA" << this;
+}
+
+void BreakpointData::removeMarker()
+{
+ BreakpointMarker *m = marker;
+ marker = 0;
+ delete m;
+}
+
+void BreakpointData::updateMarker()
+{
+ if (marker && (markerFileName != marker->fileName()
+ || markerLineNumber != marker->lineNumber()))
+ removeMarker();
+
+ if (!marker && !markerFileName.isEmpty() && markerLineNumber > 0)
+ marker = new BreakpointMarker(this, markerFileName, markerLineNumber);
+
+ if (marker)
+ marker->setPending(pending);
+}
+
+QString BreakpointData::toToolTip() const
+{
+ QString str;
+ str += "<table>";
+ str += "<tr><td>Marker File:</td><td>" + markerFileName + "</td></tr>";
+ str += "<tr><td>Marker Line:</td><td>" + QString::number(markerLineNumber) + "</td></tr>";
+ str += "<tr><td>BP Number:</td><td>" + bpNumber + "</td></tr>";
+ str += "<tr><td>BP Address:</td><td>" + bpAddress + "</td></tr>";
+ str += "<tr><td>----------</td><td></td><td></td></tr>";
+ str += "<tr><td>Property:</td><td>Wanted:</td><td>Actual:</td></tr>";
+ str += "<tr><td></td><td></td><td></td></tr>";
+ str += "<tr><td>Internal Number:</td><td>-</td><td>" + bpNumber + "</td></tr>";
+ str += "<tr><td>File Name:</td><td>" + fileName + "</td><td>" + bpFileName + "</td></tr>";
+ str += "<tr><td>Function Name:</td><td>" + funcName + "</td><td>" + bpFuncName + "</td></tr>";
+ str += "<tr><td>Line Number:</td><td>" + lineNumber + "</td><td>" + bpLineNumber + "</td></tr>";
+ str += "<tr><td>Condition:</td><td>" + condition + "</td><td>" + bpCondition + "</td></tr>";
+ str += "<tr><td>Ignore count:</td><td>" + ignoreCount + "</td><td>" + bpIgnoreCount + "</td></tr>";
+ str += "</table>";
+ return str;
+}
+
+bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) const
+{
+ /*
+ if (lineNumber != QString::number(lineNumber_))
+ return false;
+ if (fileName == fileName_)
+ return true;
+ if (fileName_.endsWith(fileName))
+ return true;
+ return false;
+ */
+ return lineNumber_ == markerLineNumber && fileName_ == markerFileName;
+}
+
+bool BreakpointData::conditionsMatch() const
+{
+ // same versions of gdb "beautify" the passed condition
+ QString s1 = condition;
+ s1.remove(QChar(' '));
+ QString s2 = bpCondition;
+ s2.remove(QChar(' '));
+ return s1 == s2;
+}
+
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakHandler
+//
+//////////////////////////////////////////////////////////////////
+
+BreakHandler::BreakHandler(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+}
+
+int BreakHandler::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : 6;
+}
+
+int BreakHandler::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : size();
+}
+
+void BreakHandler::removeAt(int index)
+{
+ BreakpointData *data = at(index);
+ m_bp.removeAt(index);
+ delete data;
+}
+
+void BreakHandler::clear()
+{
+ for (int index = size(); --index >= 0; )
+ removeAt(index);
+}
+
+int BreakHandler::findBreakpoint(const BreakpointData &needle)
+{
+ // looks for a breakpoint we might refer to
+ for (int index = 0; index != size(); ++index) {
+ const BreakpointData *data = at(index);
+ // clear hit.
+ if (data->bpNumber == needle.bpNumber)
+ return index;
+ // at least at a position we were looking for
+ // FIXME: breaks multiple breakpoints at the same location
+ if (data->fileName == needle.bpFileName
+ && data->lineNumber == needle.bpLineNumber)
+ return index;
+ }
+ return -1;
+}
+
+int BreakHandler::findBreakpoint(int bpNumber)
+{
+ for (int index = 0; index != size(); ++index)
+ if (at(index)->bpNumber == QString::number(bpNumber))
+ return index;
+ return -1;
+}
+
+void BreakHandler::saveBreakpoints()
+{
+ QList<QVariant> list;
+ for (int index = 0; index != size(); ++index) {
+ const BreakpointData *data = at(index);
+ QMap<QString, QVariant> map;
+ if (!data->fileName.isEmpty())
+ map["filename"] = data->fileName;
+ if (!data->lineNumber.isEmpty())
+ map["linenumber"] = data->lineNumber;
+ if (!data->funcName.isEmpty())
+ map["funcname"] = data->funcName;
+ if (!data->condition.isEmpty())
+ map["condition"] = data->condition;
+ if (!data->ignoreCount.isEmpty())
+ map["ignorecount"] = data->ignoreCount;
+ list.append(map);
+ }
+ setSessionValueRequested("Breakpoints", list);
+}
+
+void BreakHandler::loadBreakpoints()
+{
+ QVariant value;
+ sessionValueRequested("Breakpoints", &value);
+ QList<QVariant> list = value.toList();
+
+ clear();
+ foreach (const QVariant &var, list) {
+ const QMap<QString, QVariant> map = var.toMap();
+ BreakpointData *data = new BreakpointData(this);
+ data->fileName = map["filename"].toString();
+ data->lineNumber = map["linenumber"].toString();
+ data->condition = map["condition"].toString();
+ data->ignoreCount = map["ignorecount"].toString();
+ data->funcName = map["funcname"].toString();
+ data->markerFileName = data->fileName;
+ data->markerLineNumber = data->lineNumber.toInt();
+ append(data);
+ }
+}
+
+void BreakHandler::resetBreakpoints()
+{
+ for (int index = size(); --index >= 0;) {
+ BreakpointData *data = at(index);
+ data->pending = true;
+ data->bpNumber.clear();
+ data->bpFuncName.clear();
+ data->bpFileName.clear();
+ data->bpLineNumber.clear();
+ data->bpCondition.clear();
+ data->bpIgnoreCount.clear();
+ // keep marker data if it was primary
+ if (data->markerFileName != data->fileName)
+ data->markerFileName.clear();
+ if (data->markerLineNumber != data->lineNumber.toInt())
+ data->markerLineNumber = 0;
+ }
+}
+
+void BreakHandler::updateMarkers()
+{
+ for (int index = 0; index != size(); ++index)
+ at(index)->updateMarker();
+ emit layoutChanged();
+}
+
+QVariant BreakHandler::headerData(int section,
+ Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ static QString headers[] = {
+ tr("Number"), tr("Function"), tr("File"), tr("Line"),
+ tr("Condition"), tr("Ignore")
+ };
+ return headers[section];
+ }
+ return QVariant();
+}
+
+QVariant BreakHandler::data(const QModelIndex &mi, int role) const
+{
+ static const QIcon icon(":/gdbdebugger/images/breakpoint.svg");
+ static const QIcon icon2(":/gdbdebugger/images/breakpoint_pending.svg");
+ static const QString empty = QString(QLatin1Char('-'));
+
+ QWB_ASSERT(mi.isValid(), return QVariant());
+
+ if (mi.row() >= size())
+ return QVariant();
+
+ const BreakpointData *data = at(mi.row());
+ switch (mi.column()) {
+ case 0:
+ if (role == Qt::DisplayRole) {
+ QString str = data->bpNumber;
+ return str.isEmpty() ? empty : str;
+ }
+ if (role == Qt::DecorationRole)
+ return data->pending ? icon2 : icon;
+ break;
+ case 1:
+ if (role == Qt::DisplayRole) {
+ QString str = data->pending ? data->funcName : data->bpFuncName;
+ return str.isEmpty() ? empty : str;
+ }
+ break;
+ case 2:
+ if (role == Qt::DisplayRole) {
+ QString str = data->pending ? data->fileName : data->bpFileName;
+ str = QFileInfo(str).fileName();
+ //if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
+ // str = data->markerFileName;
+ return str.isEmpty() ? empty : str;
+ }
+ break;
+ case 3:
+ if (role == Qt::DisplayRole) {
+ QString str = data->pending ? data->lineNumber : data->bpLineNumber;
+ //if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
+ // str = data->markerLineNumber;
+ return str.isEmpty() ? empty : str;
+ }
+ 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.");
+ 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.");
+ break;
+ }
+ if (role == Qt::ToolTipRole)
+ return data->toToolTip();
+ return QVariant();
+}
+
+bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
+{
+ if (role != Qt::EditRole)
+ return false;
+
+ BreakpointData *data = at(mi.row());
+ switch (mi.column()) {
+ case 4: {
+ QString val = value.toString();
+ if (val != data->condition) {
+ data->condition = val;
+ dataChanged(mi, mi);
+ }
+ return true;
+ }
+ case 5: {
+ QString val = value.toString();
+ if (val != data->ignoreCount) {
+ data->ignoreCount = val;
+ dataChanged(mi, mi);
+ }
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints()
+{
+ QList<BreakpointData *> result = m_removed;
+ m_removed.clear();
+ return result;
+}
+
+void BreakHandler::removeBreakpointHelper(int index)
+{
+ BreakpointData *data = m_bp.at(index);
+ m_bp.removeAt(index);
+ data->removeMarker();
+ m_removed.append(data);
+}
+
+
+void BreakHandler::removeBreakpoint(int index)
+{
+ if (index < 0 || index >= size())
+ return;
+ BreakHandler::removeBreakpointHelper(index);
+ emit layoutChanged();
+ saveBreakpoints();
+}
+
+
+int BreakHandler::indexOf(const QString &fileName, int lineNumber)
+{
+ for (int index = 0; index != size(); ++index)
+ if (at(index)->isLocatedAt(fileName, lineNumber))
+ return index;
+ return -1;
+}
+
+void BreakHandler::setBreakpoint(const QString &fileName, int lineNumber)
+{
+ QFileInfo fi(fileName);
+
+ BreakpointData *data = new BreakpointData(this);
+ data->fileName = fileName;
+ data->lineNumber = QString::number(lineNumber);
+ data->pending = true;
+ data->markerFileName = fileName;
+ data->markerLineNumber = lineNumber;
+ append(data);
+ emit layoutChanged();
+ saveBreakpoints();
+ updateMarkers();
+}
+
+void BreakHandler::removeAllBreakpoints()
+{
+ for (int index = size(); --index >= 0;)
+ removeBreakpointHelper(index);
+ emit layoutChanged();
+ saveBreakpoints();
+ updateMarkers();
+}
+
+void BreakHandler::setAllPending()
+{
+ loadBreakpoints();
+ for (int index = size(); --index >= 0;)
+ at(index)->pending = true;
+ saveBreakpoints();
+ updateMarkers();
+}
+
+void BreakHandler::saveSessionData()
+{
+ saveBreakpoints();
+ updateMarkers();
+}
+
+void BreakHandler::loadSessionData()
+{
+ //resetBreakpoints();
+ loadBreakpoints();
+ updateMarkers();
+}
+
+void BreakHandler::activateBreakPoint(int index)
+{
+ const BreakpointData *data = at(index);
+ //qDebug() << "BREAKPOINT ACTIVATED: " << data->fileName;
+ if (!data->markerFileName.isEmpty())
+ emit gotoLocation(data->markerFileName, data->markerLineNumber, false);
+}
+
+void BreakHandler::breakByFunction(const QString &functionName)
+{
+ // One per function is enough for now
+ for (int index = size(); --index >= 0;) {
+ const BreakpointData *data = at(index);
+ QWB_ASSERT(data, break);
+ if (data->funcName == functionName && data->condition.isEmpty()
+ && data->ignoreCount.isEmpty())
+ return;
+ }
+ BreakpointData *data = new BreakpointData(this);
+ data->funcName = functionName;
+ append(data);
+ saveBreakpoints();
+ updateMarkers();
+}
+
+#include "breakhandler.moc"
diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h
new file mode 100644
index 0000000000..8ce63272b7
--- /dev/null
+++ b/src/plugins/debugger/breakhandler.h
@@ -0,0 +1,174 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_BREAKHANDLER_H
+#define DEBUGGER_BREAKHANDLER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QAbstractItemModel>
+
+namespace Debugger {
+namespace Internal {
+
+class BreakpointMarker;
+class BreakHandler;
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakpointData
+//
+//////////////////////////////////////////////////////////////////
+
+class BreakpointData
+{
+public:
+ explicit BreakpointData(BreakHandler *handler);
+ ~BreakpointData();
+
+ void removeMarker();
+ void updateMarker();
+ QString toToolTip() const;
+ BreakHandler *handler() { return m_handler; }
+
+ bool isLocatedAt(const QString &fileName, int lineNumber) const;
+ bool conditionsMatch() const;
+
+private:
+ // Intentionally unimplemented.
+ // Making it copiable is tricky because of the markers.
+ void operator=(const BreakpointData &);
+ BreakpointData(const BreakpointData &);
+
+ // Our owner
+ BreakHandler *m_handler; // not owned.
+
+public:
+ 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
+ QString condition; // condition associated with breakpoint
+ QString ignoreCount; // ignore count associated with breakpoint
+ QString lineNumber; // line in source file
+ QString funcName; // name of containing function
+
+ // this is what gdb produced in response
+ QString bpNumber; // breakpoint number assigned by the debugger engine
+ QString bpCondition; // condition acknowledged by the debugger engine
+ QString bpIgnoreCount; // ignore count acknowledged by the debugger engine
+ QString bpFileName; // file name acknowledged by the debugger engine
+ QString bpLineNumber; // line number acknowledged by the debugger engine
+ QString bpFuncName; // function name acknowledged by the debugger engine
+ QString bpAddress; // address acknowledged by the debugger engine
+ bool bpMultiple; // happens in constructors/gdb
+
+ // taken from either user input or gdb responses
+ QString markerFileName; // used to locate the marker
+ int markerLineNumber;
+
+ // our red blob in the editor
+ BreakpointMarker *marker;
+};
+
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakHandler
+//
+//////////////////////////////////////////////////////////////////
+
+class BreakHandler : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit BreakHandler(QObject *parent = 0);
+
+ void removeAllBreakpoints();
+ void setAllPending();
+ void loadSessionData();
+ void saveSessionData();
+
+ QAbstractItemModel *model() { return this; }
+
+ BreakpointData *at(int index) const { return index < size() ? m_bp.at(index) : 0; }
+ int size() const { return m_bp.size(); }
+ void append(BreakpointData *data) { m_bp.append(data); }
+ void removeAt(int index); // also deletes the marker
+ void clear(); // also deletes all the marker
+ int indexOf(BreakpointData *data) { return m_bp.indexOf(data); }
+ int indexOf(const QString &fileName, int lineNumber);
+ int findBreakpoint(const BreakpointData &data); // returns index
+ int findBreakpoint(int bpNumber); // returns index
+ void updateMarkers();
+
+ QList<BreakpointData *> takeRemovedBreakpoints();
+
+public slots:
+ void setBreakpoint(const QString &fileName, int lineNumber);
+ void breakByFunction(const QString &functionName);
+ void activateBreakPoint(int index);
+ void removeBreakpoint(int index);
+
+signals:
+ void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
+
+ void sessionValueRequested(const QString &name, QVariant *value);
+ void setSessionValueRequested(const QString &name, const QVariant &value);
+
+private:
+ friend class BreakpointMarker;
+
+ // QAbstractItemModel
+ int columnCount(const QModelIndex &parent) const;
+ int rowCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex &index, const QVariant &, int role);
+ QModelIndex parent(const QModelIndex &) const { return QModelIndex(); }
+ QModelIndex index(int row, int column, const QModelIndex &) const
+ { return createIndex(row, column); }
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ void markerUpdated(BreakpointMarker *, int lineNumber);
+ void loadBreakpoints();
+ void saveBreakpoints();
+ void resetBreakpoints();
+ void removeBreakpointHelper(int index);
+
+ QList<BreakpointData *> m_bp;
+ QList<BreakpointData *> m_removed;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_BREAKHANDLER_H
diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp
new file mode 100644
index 0000000000..11248f9a58
--- /dev/null
+++ b/src/plugins/debugger/breakwindow.cpp
@@ -0,0 +1,164 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "breakwindow.h"
+
+#include "ui_breakcondition.h"
+
+#include <QAction>
+#include <QDir>
+#include <QFileInfo>
+#include <QFileInfoList>
+#include <QHeaderView>
+#include <QKeyEvent>
+#include <QMenu>
+#include <QResizeEvent>
+#include <QToolButton>
+#include <QTreeView>
+
+using Debugger::Internal::BreakWindow;
+
+
+BreakWindow::BreakWindow(QWidget *parent)
+ : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
+{
+ setWindowTitle(tr("Breakpoints"));
+ setWindowIcon(QIcon(":/gdbdebugger/images/debugger_breakpoints.png"));
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+ setIconSize(QSize(10, 10));
+
+ connect(this, SIGNAL(activated(QModelIndex)),
+ this, SLOT(rowActivated(QModelIndex)));
+}
+
+void BreakWindow::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Delete)
+ deleteBreakpoint(currentIndex());
+ QTreeView::keyPressEvent(event);
+}
+
+void BreakWindow::resizeEvent(QResizeEvent *event)
+{
+ QHeaderView *hv = header();
+ int totalSize = event->size().width() - 180;
+ hv->resizeSection(0, 60);
+ hv->resizeSection(1, (totalSize * 30) / 100);
+ hv->resizeSection(2, (totalSize * 30) / 100);
+ hv->resizeSection(3, (totalSize * 30) / 100);
+ hv->resizeSection(4, 70);
+ hv->resizeSection(5, 50);
+ QTreeView::resizeEvent(event);
+}
+
+void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ QMenu menu;
+ QModelIndex index = indexAt(ev->pos());
+ QAction *act0 = new QAction("Delete breakpoint", &menu);
+ QAction *act1 = new QAction("Adjust column widths to contents", &menu);
+ QAction *act2 = new QAction("Always adjust column widths to contents", &menu);
+ QAction *act3 = new QAction("Edit condition...", &menu);
+ act2->setCheckable(true);
+ act2->setChecked(m_alwaysResizeColumnsToContents);
+ if (index.isValid()) {
+ menu.addAction(act0);
+ menu.addAction(act3);
+ menu.addSeparator();
+ }
+ menu.addAction(act1);
+ menu.addAction(act2);
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (act == act0)
+ deleteBreakpoint(index);
+ else if (act == act1)
+ resizeColumnsToContents();
+ else if (act == act2)
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+ else if (act == act3)
+ editCondition(index);
+}
+
+void BreakWindow::deleteBreakpoint(const QModelIndex &idx)
+{
+ int row = idx.row();
+ if (row == model()->rowCount() - 1)
+ --row;
+ setCurrentIndex(idx.sibling(row, 0));
+ emit breakPointDeleted(idx.row());
+}
+
+void BreakWindow::editCondition(const QModelIndex &idx)
+{
+ QDialog dlg(this);
+ Ui::BreakCondition ui;
+ ui.setupUi(&dlg);
+
+ 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());
+
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ model()->setData(idx.sibling(row, 4), ui.lineEditCondition->text());
+ model()->setData(idx.sibling(row, 5), ui.spinBoxIgnoreCount->value());
+}
+
+void BreakWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+ resizeColumnToContents(2);
+ resizeColumnToContents(3);
+}
+
+void BreakWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ header()->setResizeMode(1, mode);
+ header()->setResizeMode(2, mode);
+ header()->setResizeMode(3, mode);
+}
+
+void BreakWindow::rowActivated(const QModelIndex &index)
+{
+ emit breakPointActivated(index.row());
+}
+
diff --git a/src/plugins/debugger/breakwindow.h b/src/plugins/debugger/breakwindow.h
new file mode 100644
index 0000000000..8b17b55145
--- /dev/null
+++ b/src/plugins/debugger/breakwindow.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_BREAKWINDOW_H
+#define DEBUGGER_BREAKWINDOW_H
+
+#include <QTreeView>
+
+namespace Debugger {
+namespace Internal {
+
+class BreakWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ BreakWindow(QWidget *parent = 0);
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on);
+
+signals:
+ void breakPointDeleted(int index);
+ void breakPointActivated(int index);
+
+private slots:
+ void rowActivated(const QModelIndex &index);
+
+protected:
+ void resizeEvent(QResizeEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+ void keyPressEvent(QKeyEvent *ev);
+
+private:
+ void deleteBreakpoint(const QModelIndex &idx);
+ void editCondition(const QModelIndex &idx);
+
+ bool m_alwaysResizeColumnsToContents;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_BREAKWINDOW
+
diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro
new file mode 100644
index 0000000000..d21eb7cdc0
--- /dev/null
+++ b/src/plugins/debugger/debugger.pro
@@ -0,0 +1,92 @@
+TEMPLATE = lib
+TARGET = Debugger
+
+# CONFIG += single
+include(../../qworkbenchplugin.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/find/find.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/cpptools/cpptools.pri)
+include(../../libs/cplusplus/cplusplus.pri)
+
+# DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
+QT += gui network script
+
+HEADERS += assert.h \
+ attachexternaldialog.h \
+ attachremotedialog.h \
+ breakhandler.h \
+ breakwindow.h \
+ debuggerconstants.h \
+ debuggermanager.h \
+ debuggeroutputwindow.h \
+ debuggerplugin.h \
+ debuggerrunner.h \
+ mode.h \
+ disassemblerhandler.h \
+ disassemblerwindow.h \
+ gdbengine.h \
+ gdbmi.h \
+ gdboptionpage.h \
+ idebuggerengine.h \
+ imports.h \
+ moduleshandler.h \
+ moduleswindow.h \
+ procinterrupt.h \
+ registerhandler.h \
+ registerwindow.h \
+ scriptengine.h \
+ stackhandler.h \
+ stackwindow.h \
+ startexternaldialog.h \
+ threadswindow.h \
+ watchhandler.h \
+ watchwindow.h
+
+SOURCES += attachexternaldialog.cpp \
+ attachremotedialog.cpp \
+ breakhandler.cpp \
+ breakwindow.cpp \
+ breakwindow.h \
+ debuggermanager.cpp \
+ debuggeroutputwindow.cpp \
+ debuggerplugin.cpp \
+ debuggerrunner.cpp \
+ mode.cpp \
+ disassemblerhandler.cpp \
+ disassemblerwindow.cpp \
+ gdbengine.cpp \
+ gdbmi.cpp \
+ gdboptionpage.cpp \
+ gdbtypemacros.cpp \
+ gdbengine.h \
+ moduleshandler.cpp \
+ moduleswindow.cpp \
+ procinterrupt.cpp \
+ registerhandler.cpp \
+ registerwindow.cpp \
+ scriptengine.cpp \
+ stackhandler.cpp \
+ stackwindow.cpp \
+ startexternaldialog.cpp \
+ threadswindow.cpp \
+ watchhandler.cpp \
+ watchwindow.cpp
+
+FORMS += attachexternaldialog.ui \
+ attachremotedialog.ui \
+ breakbyfunction.ui \
+ breakcondition.ui \
+ mode.ui \
+ gdboptionpage.ui \
+ gdbtypemacros.ui \
+ startexternaldialog.ui \
+
+RESOURCES += debugger.qrc
+
+false {
+SOURCES += $$PWD/modeltest.cpp
+HEADERS += $$PWD/modeltest.h
+DEFINES += USE_MODEL_TEST=1
+}
diff --git a/src/plugins/debugger/debugger.qrc b/src/plugins/debugger/debugger.qrc
new file mode 100644
index 0000000000..548c27ac9f
--- /dev/null
+++ b/src/plugins/debugger/debugger.qrc
@@ -0,0 +1,24 @@
+<RCC>
+ <qresource prefix="/gdbdebugger" >
+ <file>images/breakpoint.svg</file>
+ <file>images/breakpoint_pending.svg</file>
+ <file>images/debugger_breakpoints.png</file>
+ <file>images/debugger_continue_small.png</file>
+ <file>images/debugger_interrupt_small.png</file>
+ <file>images/debugger_start.png</file>
+ <file>images/debugger_start_small.png</file>
+ <file>images/debugger_stepinto_small.png</file>
+ <file>images/debugger_stepout_small.png</file>
+ <file>images/debugger_stepover_small.png</file>
+ <file>images/debugger_steponeproc_small.png</file>
+ <file>images/debugger_stepoverproc_small.png</file>
+ <file>images/debugger_stop_small.png</file>
+ <file>images/delete.png</file>
+ <file>images/done.png</file>
+ <file>images/empty.svg</file>
+ <file>images/error.png</file>
+ <file>images/location.svg</file>
+ <file>images/newitem.png</file>
+ <file>images/running.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
new file mode 100644
index 0000000000..56d790e074
--- /dev/null
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGERCONSTANTS_H
+#define DEBUGGERCONSTANTS_H
+
+namespace Debugger {
+namespace Constants {
+
+// modes and their priorities
+const char * const MODE_DEBUG = "Debugger.Mode.Debug";
+const int P_MODE_DEBUG = 85;
+
+// common actions
+const char * const INTERRUPT = "Debugger.Interrupt";
+const char * const RESET = "Debugger.Reset";
+const char * const STEP = "Debugger.StepLine";
+const char * const STEPOUT = "Debugger.StepOut";
+const char * const NEXT = "Debugger.NextLine";
+const char * const STEPI = "Debugger.StepInstruction";
+const char * const NEXTI = "Debugger.NextInstruction";
+
+const char * const M_VIEW_DEBUG = "Debugger.Menu.View.Debug";
+const char * const G_DEBUG = "Debugger.Group.Debug";
+const char * const G_VIEW_DEBUG = "Debugger.Group.View.Debug";
+
+const char * const C_GDBDEBUGGER = "Gdb Debugger";
+const char * const GDBRUNNING = "Gdb.Running";
+
+const char * const PROPERTY_REGISTER_FORMAT = "Debugger.Property.RegisterFormat";
+
+} // namespace Constants
+} // namespace Debugger
+
+#endif // DEBUGGERCONSTANTS_H
+
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
new file mode 100644
index 0000000000..bcf314ae41
--- /dev/null
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -0,0 +1,1298 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "debuggermanager.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+#include "idebuggerengine.h"
+
+#include "breakwindow.h"
+#include "disassemblerwindow.h"
+#include "debuggeroutputwindow.h"
+#include "moduleswindow.h"
+#include "registerwindow.h"
+#include "stackwindow.h"
+#include "threadswindow.h"
+#include "watchwindow.h"
+
+#include "ui_breakbyfunction.h"
+
+#include "disassemblerhandler.h"
+#include "breakhandler.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+
+#include "startexternaldialog.h"
+#include "attachexternaldialog.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTime>
+
+#include <QtGui/QAction>
+#include <QtGui/QComboBox>
+#include <QtGui/QDockWidget>
+#include <QtGui/QErrorMessage>
+#include <QtGui/QFileDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QStatusBar>
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextCursor>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+#include <QtGui/QToolTip>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+static const QString tooltipIName = "tooltip";
+
+///////////////////////////////////////////////////////////////////////
+//
+// BreakByFunctionDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+class BreakByFunctionDialog : public QDialog, Ui::BreakByFunctionDialog
+{
+ Q_OBJECT
+
+public:
+ explicit BreakByFunctionDialog(QWidget *parent)
+ : QDialog(parent)
+ {
+ setupUi(this);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ }
+ QString functionName() const { return functionLineEdit->text(); }
+};
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// DebuggerManager
+//
+///////////////////////////////////////////////////////////////////////
+
+static IDebuggerEngine *gdbEngine = 0;
+static IDebuggerEngine *winEngine = 0;
+static IDebuggerEngine *scriptEngine = 0;
+
+extern IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
+extern IDebuggerEngine *createWinEngine(DebuggerManager *) { return 0; }
+extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
+
+DebuggerManager::DebuggerManager()
+{
+ init();
+}
+
+DebuggerManager::~DebuggerManager()
+{
+ delete gdbEngine;
+ delete winEngine;
+ delete scriptEngine;
+}
+
+void DebuggerManager::init()
+{
+ m_status = -1;
+ m_busy = false;
+
+ m_attachedPID = 0;
+ m_startMode = startInternal;
+
+ m_disassemblerHandler = 0;
+ m_modulesHandler = 0;
+ m_registerHandler = 0;
+
+ m_breakWindow = new BreakWindow;
+ m_disassemblerWindow = new DisassemblerWindow;
+ m_modulesWindow = new ModulesWindow;
+ m_outputWindow = new DebuggerOutputWindow;
+ m_registerWindow = new RegisterWindow;
+ m_stackWindow = new StackWindow;
+ m_threadsWindow = new ThreadsWindow;
+ m_localsWindow = new WatchWindow(WatchWindow::LocalsType);
+ m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
+ //m_tooltipWindow = new WatchWindow(WatchWindow::TooltipType);
+ //m_watchersWindow = new QTreeView;
+ m_tooltipWindow = new QTreeView;
+
+ m_mainWindow = new QMainWindow;
+ m_mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
+ m_mainWindow->setDocumentMode(true);
+
+ // Stack
+ m_stackHandler = new StackHandler;
+ QAbstractItemView *stackView =
+ qobject_cast<QAbstractItemView *>(m_stackWindow);
+ stackView->setModel(m_stackHandler->stackModel());
+ connect(stackView, SIGNAL(frameActivated(int)),
+ this, SLOT(activateFrame(int)));
+
+ // Threads
+ m_threadsHandler = new ThreadsHandler;
+ QAbstractItemView *threadsView =
+ qobject_cast<QAbstractItemView *>(m_threadsWindow);
+ threadsView->setModel(m_threadsHandler->threadsModel());
+ connect(threadsView, SIGNAL(threadSelected(int)),
+ this, SLOT(selectThread(int)));
+
+ // Disassembler
+ m_disassemblerHandler = new DisassemblerHandler;
+ QAbstractItemView *disassemblerView =
+ qobject_cast<QAbstractItemView *>(m_disassemblerWindow);
+ disassemblerView->setModel(m_disassemblerHandler->model());
+
+ // Breakpoints
+ m_breakHandler = new BreakHandler;
+ QAbstractItemView *breakView =
+ qobject_cast<QAbstractItemView *>(m_breakWindow);
+ breakView->setModel(m_breakHandler->model());
+ connect(breakView, SIGNAL(breakPointActivated(int)),
+ m_breakHandler, SLOT(activateBreakPoint(int)));
+ connect(breakView, SIGNAL(breakPointDeleted(int)),
+ m_breakHandler, SLOT(removeBreakpoint(int)));
+ connect(m_breakHandler, SIGNAL(gotoLocation(QString,int,bool)),
+ this, SLOT(gotoLocation(QString,int,bool)));
+ connect(m_breakHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
+ this, SIGNAL(sessionValueRequested(QString,QVariant*)));
+ connect(m_breakHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
+ this, SIGNAL(setSessionValueRequested(QString,QVariant)));
+
+ // Modules
+ QAbstractItemView *modulesView =
+ qobject_cast<QAbstractItemView *>(m_modulesWindow);
+ m_modulesHandler = new ModulesHandler;
+ modulesView->setModel(m_modulesHandler->model());
+ connect(modulesView, SIGNAL(reloadModulesRequested()),
+ this, SLOT(reloadModules()));
+ connect(modulesView, SIGNAL(loadSymbolsRequested(QString)),
+ this, SLOT(loadSymbols(QString)));
+ connect(modulesView, SIGNAL(loadAllSymbolsRequested()),
+ this, SLOT(loadAllSymbols()));
+
+
+ // Registers
+ QAbstractItemView *registerView =
+ qobject_cast<QAbstractItemView *>(m_registerWindow);
+ m_registerHandler = new RegisterHandler;
+ registerView->setModel(m_registerHandler->model());
+
+
+ m_watchHandler = new WatchHandler;
+
+ // Locals
+ QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
+ localsView->setModel(m_watchHandler->model());
+ connect(localsView, SIGNAL(requestExpandChildren(QModelIndex)),
+ this, SLOT(expandChildren(QModelIndex)));
+ connect(localsView, SIGNAL(requestCollapseChildren(QModelIndex)),
+ this, SLOT(collapseChildren(QModelIndex)));
+ connect(localsView, SIGNAL(requestAssignValue(QString,QString)),
+ this, SLOT(assignValueInDebugger(QString,QString)));
+ connect(localsView, SIGNAL(requestWatchExpression(QString)),
+ this, SLOT(watchExpression(QString)));
+
+ // Watchers
+ QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
+ watchersView->setModel(m_watchHandler->model());
+ connect(watchersView, SIGNAL(requestAssignValue(QString,QString)),
+ this, SLOT(assignValueInDebugger(QString,QString)));
+ connect(watchersView, SIGNAL(requestExpandChildren(QModelIndex)),
+ this, SLOT(expandChildren(QModelIndex)));
+ connect(watchersView, SIGNAL(requestCollapseChildren(QModelIndex)),
+ this, SLOT(collapseChildren(QModelIndex)));
+ connect(watchersView, SIGNAL(requestWatchExpression(QString)),
+ this, SLOT(watchExpression(QString)));
+ connect(watchersView, SIGNAL(requestRemoveWatchExpression(QString)),
+ this, SLOT(removeWatchExpression(QString)));
+
+ // Tooltip
+ QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
+ tooltipView->setModel(m_watchHandler->model());
+
+ connect(m_watchHandler, SIGNAL(watchModelUpdateRequested()),
+ this, SLOT(updateWatchModel()));
+
+ m_startExternalAction = new QAction(this);
+ m_startExternalAction->setText(tr("Start and Debug External Application..."));
+
+ m_attachExternalAction = new QAction(this);
+ m_attachExternalAction->setText(tr("Attach to Running External Application..."));
+
+ m_continueAction = new QAction(this);
+ m_continueAction->setText(tr("Continue"));
+ m_continueAction->setIcon(QIcon(":/gdbdebugger/images/debugger_continue_small.png"));
+
+ m_stopAction = new QAction(this);
+ m_stopAction->setText(tr("Interrupt"));
+ m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_interrupt_small.png"));
+
+ m_resetAction = new QAction(this);
+ m_resetAction->setText(tr("Reset Debugger"));
+
+ m_nextAction = new QAction(this);
+ m_nextAction->setText(tr("Step Over"));
+ //m_nextAction->setShortcut(QKeySequence(tr("F6")));
+ m_nextAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepover_small.png"));
+
+ m_stepAction = new QAction(this);
+ m_stepAction->setText(tr("Step Into"));
+ //m_stepAction->setShortcut(QKeySequence(tr("F7")));
+ m_stepAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepinto_small.png"));
+
+ m_nextIAction = new QAction(this);
+ m_nextIAction->setText(tr("Step Over Instruction"));
+ //m_nextIAction->setShortcut(QKeySequence(tr("Shift+F6")));
+ m_nextIAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepoverproc_small.png"));
+
+ m_stepIAction = new QAction(this);
+ m_stepIAction->setText(tr("Step One Instruction"));
+ //m_stepIAction->setShortcut(QKeySequence(tr("Shift+F9")));
+ m_stepIAction->setIcon(QIcon(":/gdbdebugger/images/debugger_steponeproc_small.png"));
+
+ m_stepOutAction = new QAction(this);
+ m_stepOutAction->setText(tr("Step Out"));
+ //m_stepOutAction->setShortcut(QKeySequence(tr("Shift+F7")));
+ m_stepOutAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepout_small.png"));
+
+ m_runToLineAction = new QAction(this);
+ m_runToLineAction->setText(tr("Run to Line"));
+
+ m_runToFunctionAction = new QAction(this);
+ m_runToFunctionAction->setText(tr("Run to Outermost Function"));
+
+ m_jumpToLineAction = new QAction(this);
+ m_jumpToLineAction->setText(tr("Jump to Line"));
+
+ m_breakAction = new QAction(this);
+ m_breakAction->setText(tr("Toggle Breakpoint"));
+
+ m_breakByFunctionAction = new QAction(this);
+ m_breakByFunctionAction->setText(tr("Set Breakpoint at Function..."));
+
+ m_breakAtMainAction = new QAction(this);
+ m_breakAtMainAction->setText(tr("Set Breakpoint at Function 'main'"));
+
+ m_debugDumpersAction = new QAction(this);
+ m_debugDumpersAction->setText(tr("Debug Custom Dumpers"));
+ m_debugDumpersAction->setCheckable(true);
+
+ m_skipKnownFramesAction = new QAction(this);
+ m_skipKnownFramesAction->setText(tr("Skip Known Frames When Stepping"));
+ m_skipKnownFramesAction->setCheckable(true);
+
+ m_useCustomDumpersAction = new QAction(this);
+ m_useCustomDumpersAction->setText(tr("Use Custom Display for Qt Objects"));
+ m_useCustomDumpersAction->setToolTip(tr("Checking this will make the debugger "
+ "try to use code to format certain data (QObject, QString, ...) nicely. "));
+ m_useCustomDumpersAction->setCheckable(true);
+ m_useCustomDumpersAction->setChecked(true);
+
+ m_useCustomDumpersAction = new QAction(this);
+ m_useCustomDumpersAction->setText(tr("Use Custom Display for Qt Objects"));
+ m_useCustomDumpersAction->setToolTip(tr("Checking this will make the debugger "
+ "try to use code to format certain data (QObject, QString, ...) nicely. "));
+ m_useCustomDumpersAction->setCheckable(true);
+ m_useCustomDumpersAction->setChecked(true);
+
+ m_useFastStartAction = new QAction(this);
+ m_useFastStartAction->setText(tr("Fast Debugger Start"));
+ m_useFastStartAction->setToolTip(tr("Checking this will make the debugger "
+ "start fast by loading only very few debug symbols on start up. This "
+ "might lead to situations where breakpoints can not be set properly. "
+ "So uncheck this option if you experience breakpoint related problems."));
+ m_useFastStartAction->setCheckable(true);
+ m_useFastStartAction->setChecked(true);
+
+ // FIXME
+ m_useFastStartAction->setChecked(false);
+ m_useFastStartAction->setEnabled(false);
+
+ m_dumpLogAction = new QAction(this);
+ m_dumpLogAction->setText(tr("Dump Log File for Debugging Purposes"));
+
+ m_watchAction = new QAction(this);
+ m_watchAction->setText(tr("Add to Watch Window"));
+
+ // For usuage hints oin focus{In,Out}
+ //connect(m_outputWindow, SIGNAL(statusMessageRequested(QString,int)),
+ // this, SLOT(showStatusMessage(QString,int)));
+
+ connect(m_continueAction, SIGNAL(triggered()),
+ this, SLOT(continueExec()));
+
+ connect(m_startExternalAction, SIGNAL(triggered()),
+ this, SLOT(startExternalApplication()));
+ connect(m_attachExternalAction, SIGNAL(triggered()),
+ this, SLOT(attachExternalApplication()));
+
+ connect(m_stopAction, SIGNAL(triggered()),
+ this, SLOT(interruptDebuggingRequest()));
+ connect(m_resetAction, SIGNAL(triggered()),
+ this, SLOT(exitDebugger()));
+ connect(m_nextAction, SIGNAL(triggered()),
+ this, SLOT(nextExec()));
+ connect(m_stepAction, SIGNAL(triggered()),
+ this, SLOT(stepExec()));
+ connect(m_nextIAction, SIGNAL(triggered()),
+ this, SLOT(nextIExec()));
+ connect(m_stepIAction, SIGNAL(triggered()),
+ this, SLOT(stepIExec()));
+ connect(m_stepOutAction, SIGNAL(triggered()),
+ this, SLOT(stepOutExec()));
+ connect(m_runToLineAction, SIGNAL(triggered()),
+ this, SLOT(runToLineExec()));
+ connect(m_runToFunctionAction, SIGNAL(triggered()),
+ this, SLOT(runToFunctionExec()));
+ connect(m_jumpToLineAction, SIGNAL(triggered()),
+ this, SLOT(jumpToLineExec()));
+ connect(m_watchAction, SIGNAL(triggered()),
+ this, SLOT(addToWatchWindow()));
+ connect(m_breakAction, SIGNAL(triggered()),
+ this, SLOT(toggleBreakpoint()));
+ connect(m_breakByFunctionAction, SIGNAL(triggered()),
+ this, SLOT(breakByFunction()));
+ connect(m_breakAtMainAction, SIGNAL(triggered()),
+ this, SLOT(breakAtMain()));
+
+ connect(m_useFastStartAction, SIGNAL(triggered()),
+ this, SLOT(saveSessionData()));
+ connect(m_useCustomDumpersAction, SIGNAL(triggered()),
+ this, SLOT(saveSessionData()));
+ connect(m_skipKnownFramesAction, SIGNAL(triggered()),
+ this, SLOT(saveSessionData()));
+ connect(m_dumpLogAction, SIGNAL(triggered()),
+ this, SLOT(dumpLog()));
+
+ connect(m_outputWindow, SIGNAL(commandExecutionRequested(QString)),
+ this, SLOT(executeDebuggerCommand(QString)));
+
+
+ m_breakDock = createDockForWidget(m_breakWindow);
+
+ m_disassemblerDock = createDockForWidget(m_disassemblerWindow);
+ connect(m_disassemblerDock->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(reloadDisassembler()), Qt::QueuedConnection);
+
+ m_modulesDock = createDockForWidget(m_modulesWindow);
+ connect(m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(reloadModules()), Qt::QueuedConnection);
+
+ m_registerDock = createDockForWidget(m_registerWindow);
+ connect(m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(reloadRegisters()), Qt::QueuedConnection);
+
+ m_outputDock = createDockForWidget(m_outputWindow);
+
+ m_stackDock = createDockForWidget(m_stackWindow);
+
+ m_threadsDock = createDockForWidget(m_threadsWindow);
+
+ setStatus(DebuggerProcessNotReady);
+ gdbEngine = createGdbEngine(this);
+ winEngine = createWinEngine(this);
+ scriptEngine = createScriptEngine(this);
+ setDebuggerType(GdbDebugger);
+}
+
+void DebuggerManager::setDebuggerType(DebuggerType type)
+{
+ switch (type) {
+ case GdbDebugger:
+ m_engine = gdbEngine;
+ break;
+ case ScriptDebugger:
+ m_engine = scriptEngine;
+ break;
+ case WinDebugger:
+ m_engine = winEngine;
+ break;
+ }
+}
+
+IDebuggerEngine *DebuggerManager::engine()
+{
+ return m_engine;
+}
+
+IDebuggerManagerAccessForEngines *DebuggerManager::engineInterface()
+{
+ return dynamic_cast<IDebuggerManagerAccessForEngines *>(this);
+}
+
+IDebuggerManagerAccessForDebugMode *DebuggerManager::debugModeInterface()
+{
+ return dynamic_cast<IDebuggerManagerAccessForDebugMode *>(this);
+}
+
+void DebuggerManager::createDockWidgets()
+{
+ QSplitter *localsAndWatchers = new QSplitter(Qt::Vertical, 0);
+ localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle());
+ localsAndWatchers->addWidget(m_localsWindow);
+ localsAndWatchers->addWidget(m_watchersWindow);
+ localsAndWatchers->setStretchFactor(0, 3);
+ localsAndWatchers->setStretchFactor(1, 1);
+ m_watchDock = createDockForWidget(localsAndWatchers);
+}
+
+QDockWidget *DebuggerManager::createDockForWidget(QWidget *widget)
+{
+ QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow);
+ dockWidget->setObjectName(widget->windowTitle());
+ //dockWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea);
+ dockWidget->setAllowedAreas(Qt::AllDockWidgetAreas); // that space is needed.
+ //dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
+ dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
+ dockWidget->setTitleBarWidget(new QWidget(dockWidget));
+ dockWidget->setWidget(widget);
+ connect(dockWidget->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(dockToggled(bool)), Qt::QueuedConnection);
+ m_dockWidgets.append(dockWidget);
+ return dockWidget;
+}
+
+void DebuggerManager::setSimpleDockWidgetArrangement()
+{
+ foreach (QDockWidget *dockWidget, m_dockWidgets)
+ m_mainWindow->removeDockWidget(dockWidget);
+
+ foreach (QDockWidget *dockWidget, m_dockWidgets) {
+ m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
+ dockWidget->show();
+ }
+
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_breakDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_disassemblerDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_modulesDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_outputDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_registerDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_threadsDock);
+
+ // They are rarely used even in ordinary debugging. Hiding them also saves
+ // cycles since the corresponding information won't be retrieved.
+ m_registerDock->hide();
+ m_disassemblerDock->hide();
+ m_modulesDock->hide();
+ m_outputDock->hide();
+}
+
+void DebuggerManager::setLocked(bool locked)
+{
+ const QDockWidget::DockWidgetFeatures features =
+ (locked) ? QDockWidget::NoDockWidgetFeatures :
+ QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable;
+
+ foreach (QDockWidget *dockWidget, m_dockWidgets) {
+ QWidget *titleBarWidget = dockWidget->titleBarWidget();
+ if (locked && !titleBarWidget)
+ titleBarWidget = new QWidget(dockWidget);
+ else if (!locked && titleBarWidget) {
+ delete titleBarWidget;
+ titleBarWidget = 0;
+ }
+ dockWidget->setTitleBarWidget(titleBarWidget);
+ dockWidget->setFeatures(features);
+ }
+}
+
+void DebuggerManager::dockToggled(bool on)
+{
+ QDockWidget *dw = qobject_cast<QDockWidget *>(sender()->parent());
+ if (on && dw)
+ dw->raise();
+}
+
+QAbstractItemModel *DebuggerManager::threadsModel()
+{
+ return qobject_cast<ThreadsWindow*>(m_threadsWindow)->model();
+}
+
+void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
+{
+ Q_UNUSED(timeout)
+ //qDebug() << "STATUS: " << msg;
+ showDebuggerOutput("status:", msg);
+ mainWindow()->statusBar()->showMessage(msg, timeout);
+#if 0
+ QString currentTime = QTime::currentTime().toString("hh:mm:ss.zzz");
+
+ ICore *core = m_pm->getObject<Core::ICore>();
+ //qDebug() << qPrintable(currentTime) << "Setting status: " << msg;
+ if (msg.isEmpty())
+ core->messageManager()->displayStatusBarMessage(msg);
+ else if (timeout == -1)
+ core->messageManager()->displayStatusBarMessage(tr("Debugger: ") + msg);
+ else
+ core->messageManager()->displayStatusBarMessage(tr("Debugger: ") + msg, timeout);
+#endif
+}
+
+void DebuggerManager::notifyStartupFinished()
+{
+ setStatus(DebuggerProcessReady);
+ showStatusMessage(tr("Startup finished. Debugger ready."), -1);
+ if (m_startMode == attachExternal) {
+ // we continue the execution
+ engine()->continueInferior();
+ } else {
+ engine()->runInferior();
+ }
+}
+
+void DebuggerManager::notifyInferiorStopped()
+{
+ resetLocation();
+ setStatus(DebuggerInferiorStopped);
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void DebuggerManager::notifyInferiorUpdateFinished()
+{
+ setStatus(DebuggerInferiorReady);
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void DebuggerManager::notifyInferiorRunningRequested()
+{
+ setStatus(DebuggerInferiorRunningRequested);
+ showStatusMessage(tr("Running..."), 5000);
+}
+
+void DebuggerManager::notifyInferiorRunning()
+{
+ setStatus(DebuggerInferiorRunning);
+ showStatusMessage(tr("Running..."), 5000);
+}
+
+void DebuggerManager::notifyInferiorExited()
+{
+ setStatus(DebuggerProcessReady);
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void DebuggerManager::notifyInferiorPidChanged(int pid)
+{
+ //QMessageBox::warning(0, "PID", "PID: " + QString::number(pid));
+ //qDebug() << "PID: " << pid;
+ emit inferiorPidChanged(pid);
+}
+
+void DebuggerManager::showApplicationOutput(const QString &prefix, const QString &str)
+{
+ applicationOutputAvailable(prefix, str);
+}
+
+void DebuggerManager::shutdown()
+{
+ //qDebug() << "DEBUGGER_MANAGER SHUTDOWN START";
+ engine()->shutdown();
+ // Delete these manually before deleting the manager
+ // (who will delete the models for most views)
+ delete m_breakWindow;
+ delete m_disassemblerWindow;
+ delete m_modulesWindow;
+ delete m_outputWindow;
+ delete m_registerWindow;
+ delete m_stackWindow;
+ delete m_threadsWindow;
+ delete m_tooltipWindow;
+ delete m_watchersWindow;
+ delete m_localsWindow;
+ // These widgets are all in some layout which will take care of deletion.
+ m_breakWindow = 0;
+ m_disassemblerWindow = 0;
+ m_modulesWindow = 0;
+ m_outputWindow = 0;
+ m_registerWindow = 0;
+ m_stackWindow = 0;
+ m_threadsWindow = 0;
+ m_tooltipWindow = 0;
+ m_watchersWindow = 0;
+ m_localsWindow = 0;
+
+ delete m_breakHandler;
+ delete m_disassemblerHandler;
+ delete m_modulesHandler;
+ delete m_registerHandler;
+ delete m_stackHandler;
+ delete m_watchHandler;
+ m_breakHandler = 0;
+ m_disassemblerHandler = 0;
+ m_modulesHandler = 0;
+ m_registerHandler = 0;
+ m_stackHandler = 0;
+ m_watchHandler = 0;
+ //qDebug() << "DEBUGGER_MANAGER SHUTDOWN END";
+}
+
+void DebuggerManager::toggleBreakpoint()
+{
+ QString fileName;
+ int lineNumber = -1;
+ queryCurrentTextEditor(&fileName, &lineNumber, 0);
+ if (lineNumber == -1)
+ return;
+ toggleBreakpoint(fileName, lineNumber);
+}
+
+void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
+{
+ int index = m_breakHandler->indexOf(fileName, lineNumber);
+ if (index == -1)
+ breakHandler()->setBreakpoint(fileName, lineNumber);
+ else
+ breakHandler()->removeBreakpoint(index);
+ engine()->attemptBreakpointSynchronization();
+}
+
+void DebuggerManager::setToolTipExpression(const QPoint &pos, const QString &exp)
+{
+ engine()->setToolTipExpression(pos, exp);
+}
+
+void DebuggerManager::updateWatchModel()
+{
+ engine()->updateWatchModel();
+}
+
+void DebuggerManager::expandChildren(const QModelIndex &idx)
+{
+ watchHandler()->expandChildren(idx);
+}
+
+void DebuggerManager::collapseChildren(const QModelIndex &idx)
+{
+ watchHandler()->collapseChildren(idx);
+}
+
+void DebuggerManager::removeWatchExpression(const QString &iname)
+{
+ watchHandler()->removeWatchExpression(iname);
+}
+
+QVariant DebuggerManager::sessionValue(const QString &name)
+{
+ QVariant value;
+ emit sessionValueRequested(name, &value);
+ return value;
+}
+
+void DebuggerManager::querySessionValue(const QString &name, QVariant *value)
+{
+ emit sessionValueRequested(name, value);
+}
+
+void DebuggerManager::setSessionValue(const QString &name, const QVariant &value)
+{
+ emit setSessionValueRequested(name, value);
+}
+
+QVariant DebuggerManager::configValue(const QString &name)
+{
+ QVariant value;
+ emit configValueRequested(name, &value);
+ return value;
+}
+
+void DebuggerManager::queryConfigValue(const QString &name, QVariant *value)
+{
+ emit configValueRequested(name, value);
+}
+
+void DebuggerManager::setConfigValue(const QString &name, const QVariant &value)
+{
+ emit setConfigValueRequested(name, value);
+}
+
+void DebuggerManager::startExternalApplication()
+{
+ if (!startNewDebugger(startExternal))
+ emit debuggingFinished();
+}
+
+void DebuggerManager::attachExternalApplication()
+{
+ if (!startNewDebugger(attachExternal))
+ emit debuggingFinished();
+}
+
+bool DebuggerManager::startNewDebugger(StartMode mode)
+{
+ m_startMode = mode;
+ // FIXME: Clean up
+
+ if (startMode() == startExternal) {
+ StartExternalDialog dlg(mainWindow());
+ dlg.setExecutableFile(
+ configValue(QLatin1String("LastExternalExecutableFile")).toString());
+ dlg.setExecutableArguments(
+ configValue(QLatin1String("LastExternalExecutableArguments")).toString());
+ if (dlg.exec() != QDialog::Accepted)
+ return false;
+ setConfigValue(QLatin1String("LastExternalExecutableFile"),
+ dlg.executableFile());
+ setConfigValue(QLatin1String("LastExternalExecutableArguments"),
+ dlg.executableArguments());
+ m_executable = dlg.executableFile();
+ m_processArgs = dlg.executableArguments().split(' ');
+ m_workingDir = QString();
+ m_attachedPID = -1;
+ } else if (startMode() == attachExternal) {
+ QString pid;
+ AttachExternalDialog dlg(mainWindow(), pid);
+ if (dlg.exec() != QDialog::Accepted)
+ return false;
+ m_executable = QString();
+ m_processArgs = QStringList();
+ m_workingDir = QString();
+ m_attachedPID = dlg.attachPID();
+ } else if (startMode() == startInternal) {
+ if (m_executable.isEmpty()) {
+ QString startDirectory = m_executable;
+ if (m_executable.isEmpty()) {
+ QString fileName;
+ emit currentTextEditorRequested(&fileName, 0, 0);
+ if (!fileName.isEmpty()) {
+ const QFileInfo editorFile(fileName);
+ startDirectory = editorFile.dir().absolutePath();
+ }
+ }
+ StartExternalDialog dlg(mainWindow());
+ dlg.setExecutableFile(startDirectory);
+ if (dlg.exec() != QDialog::Accepted)
+ return false;
+ m_executable = dlg.executableFile();
+ m_processArgs = dlg.executableArguments().split(' ');
+ m_workingDir = QString();
+ m_attachedPID = 0;
+ } else {
+ //m_executable = QDir::convertSeparators(m_executable);
+ //m_processArgs = sd.processArgs.join(QLatin1String(" "));
+ m_attachedPID = 0;
+ }
+ }
+
+ emit debugModeRequested();
+
+ if (m_executable.endsWith(".js"))
+ setDebuggerType(ScriptDebugger);
+ else
+ setDebuggerType(GdbDebugger);
+
+ if (!engine()->startDebugger())
+ return false;
+
+ m_busy = false;
+ setStatus(DebuggerProcessStartingUp);
+ return true;
+}
+
+void DebuggerManager::cleanupViews()
+{
+ resetLocation();
+ breakHandler()->setAllPending();
+ stackHandler()->removeAll();
+ threadsHandler()->removeAll();
+ disassemblerHandler()->removeAll();
+ modulesHandler()->removeAll();
+ watchHandler()->cleanup();
+}
+
+void DebuggerManager::exitDebugger()
+{
+ engine()->exitDebugger();
+ cleanupViews();
+ setStatus(DebuggerProcessNotReady);
+ setBusyCursor(false);
+ emit debuggingFinished();
+}
+
+void DebuggerManager::assignValueInDebugger(const QString &expr, const QString &value)
+{
+ engine()->assignValueInDebugger(expr, value);
+}
+
+void DebuggerManager::activateFrame(int index)
+{
+ engine()->activateFrame(index);
+}
+
+void DebuggerManager::selectThread(int index)
+{
+ engine()->selectThread(index);
+}
+
+void DebuggerManager::loadAllSymbols()
+{
+ engine()->loadAllSymbols();
+}
+
+void DebuggerManager::loadSymbols(const QString &module)
+{
+ engine()->loadSymbols(module);
+}
+
+void DebuggerManager::stepExec()
+{
+ resetLocation();
+ engine()->stepExec();
+}
+
+void DebuggerManager::stepOutExec()
+{
+ resetLocation();
+ engine()->stepOutExec();
+}
+
+void DebuggerManager::nextExec()
+{
+ resetLocation();
+ engine()->nextExec();
+}
+
+void DebuggerManager::stepIExec()
+{
+ resetLocation();
+ engine()->stepIExec();
+}
+
+void DebuggerManager::nextIExec()
+{
+ resetLocation();
+ engine()->nextIExec();
+}
+
+void DebuggerManager::executeDebuggerCommand(const QString &command)
+{
+ engine()->executeDebuggerCommand(command);
+}
+
+void DebuggerManager::sessionLoaded()
+{
+ exitDebugger();
+ loadSessionData();
+}
+
+void DebuggerManager::aboutToSaveSession()
+{
+ saveSessionData();
+}
+
+void DebuggerManager::loadSessionData()
+{
+ m_breakHandler->loadSessionData();
+
+ QVariant value;
+ querySessionValue(QLatin1String("UseFastStart"), &value);
+ m_useFastStartAction->setChecked(value.toBool());
+ querySessionValue(QLatin1String("UseCustomDumpers"), &value);
+ m_useCustomDumpersAction->setChecked(!value.isValid() || value.toBool());
+ querySessionValue(QLatin1String("SkipKnownFrames"), &value);
+ m_skipKnownFramesAction->setChecked(value.toBool());
+ engine()->loadSessionData();
+}
+
+void DebuggerManager::saveSessionData()
+{
+ m_breakHandler->saveSessionData();
+
+ setSessionValue(QLatin1String("UseFastStart"),
+ m_useFastStartAction->isChecked());
+ setSessionValue(QLatin1String("UseCustomDumpers"),
+ m_useCustomDumpersAction->isChecked());
+ setSessionValue(QLatin1String("SkipKnownFrames"),
+ m_skipKnownFramesAction->isChecked());
+ engine()->saveSessionData();
+}
+
+void DebuggerManager::dumpLog()
+{
+ QString fileName = QFileDialog::getSaveFileName(mainWindow(),
+ tr("Save Debugger Log"), QDir::tempPath());
+ if (fileName.isEmpty())
+ return;
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly))
+ return;
+ QTextStream ts(&file);
+ ts << m_outputWindow->inputContents();
+ ts << "\n\n=======================================\n\n";
+ ts << m_outputWindow->combinedContents();
+}
+
+#if 0
+// call after m_gdbProc exited.
+void GdbEngine::procFinished()
+{
+ //qDebug() << "GDB PROCESS FINISHED";
+ setStatus(DebuggerProcessNotReady);
+ showStatusMessage(tr("Done"), 5000);
+ q->m_breakHandler->procFinished();
+ q->m_watchHandler->cleanup();
+ m_stackHandler->m_stackFrames.clear();
+ m_stackHandler->resetModel();
+ m_threadsHandler->resetModel();
+ if (q->m_modulesHandler)
+ q->m_modulesHandler->procFinished();
+ q->resetLocation();
+ setStatus(DebuggerProcessNotReady);
+ emit q->previousModeRequested();
+ emit q->debuggingFinished();
+ //exitDebugger();
+ //showStatusMessage("Gdb killed");
+ m_shortToFullName.clear();
+ m_fullToShortName.clear();
+ m_shared = 0;
+ q->m_busy = false;
+}
+#endif
+
+void DebuggerManager::addToWatchWindow()
+{
+ // requires a selection, but that's the only case we want...
+ QObject *ob = 0;
+ queryCurrentTextEditor(0, 0, &ob);
+ QPlainTextEdit *editor = qobject_cast<QPlainTextEdit*>(ob);
+ if (!editor)
+ return;
+ QTextCursor tc = editor->textCursor();
+ watchExpression(tc.selectedText());
+}
+
+void DebuggerManager::watchExpression(const QString &expression)
+{
+ watchHandler()->watchExpression(expression);
+ //engine()->updateWatchModel();
+}
+
+void DebuggerManager::setBreakpoint(const QString &fileName, int lineNumber)
+{
+ breakHandler()->setBreakpoint(fileName, lineNumber);
+ engine()->attemptBreakpointSynchronization();
+}
+
+void DebuggerManager::breakByFunction(const QString &functionName)
+{
+ breakHandler()->breakByFunction(functionName);
+ engine()->attemptBreakpointSynchronization();
+}
+
+void DebuggerManager::breakByFunction()
+{
+ BreakByFunctionDialog dlg(m_mainWindow);
+ if (dlg.exec())
+ breakByFunction(dlg.functionName());
+}
+
+void DebuggerManager::breakAtMain()
+{
+#ifdef Q_OS_WIN
+ breakByFunction("qMain");
+#else
+ breakByFunction("main");
+#endif
+}
+
+void DebuggerManager::setStatus(int status)
+{
+ //qDebug() << "STATUS CHANGE: from" << m_status << "to" << status;
+
+ if (status == m_status)
+ return;
+
+ m_status = status;
+
+ const bool started = status == DebuggerInferiorRunning
+ || status == DebuggerInferiorRunningRequested
+ || status == DebuggerInferiorStopRequested
+ || status == DebuggerInferiorStopped
+ || status == DebuggerInferiorUpdating
+ || status == DebuggerInferiorUpdateFinishing
+ || status == DebuggerInferiorReady;
+
+ const bool starting = status == DebuggerProcessStartingUp;
+ const bool running = status == DebuggerInferiorRunning;
+ const bool ready = status == DebuggerInferiorStopped
+ || status == DebuggerInferiorReady
+ || status == DebuggerProcessReady;
+
+ m_startExternalAction->setEnabled(!started && !starting);
+ m_attachExternalAction->setEnabled(!started && !starting);
+ m_watchAction->setEnabled(ready);
+ m_breakAction->setEnabled(true);
+
+ bool interruptIsExit = !running;
+ if (interruptIsExit) {
+ m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stop_small.png"));
+ m_stopAction->setText(tr("Stop Debugger"));
+ } else {
+ m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_interrupt_small.png"));
+ m_stopAction->setText(tr("Interrupt"));
+ }
+
+ m_stopAction->setEnabled(started);
+ m_resetAction->setEnabled(true);
+
+ m_stepAction->setEnabled(ready);
+ m_stepOutAction->setEnabled(ready);
+ m_runToLineAction->setEnabled(ready);
+ m_runToFunctionAction->setEnabled(ready);
+ m_jumpToLineAction->setEnabled(ready);
+ m_nextAction->setEnabled(ready);
+ m_stepIAction->setEnabled(ready);
+ m_nextIAction->setEnabled(ready);
+ //showStatusMessage(QString("started: %1, running: %2").arg(started).arg(running));
+ emit statusChanged(m_status);
+ const bool notbusy = ready || status == DebuggerProcessNotReady;
+ setBusyCursor(!notbusy);
+}
+
+void DebuggerManager::setBusyCursor(bool busy)
+{
+ if (busy == m_busy)
+ return;
+ //qDebug() << "BUSY: " << busy;
+ m_busy = busy;
+
+ QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
+ m_breakWindow->setCursor(cursor);
+ m_disassemblerWindow->setCursor(cursor);
+ m_localsWindow->setCursor(cursor);
+ m_modulesWindow->setCursor(cursor);
+ m_outputWindow->setCursor(cursor);
+ m_registerWindow->setCursor(cursor);
+ m_stackWindow->setCursor(cursor);
+ m_threadsWindow->setCursor(cursor);
+ m_tooltipWindow->setCursor(cursor);
+ m_watchersWindow->setCursor(cursor);
+}
+
+bool DebuggerManager::skipKnownFrames() const
+{
+ return m_skipKnownFramesAction->isChecked();
+}
+
+bool DebuggerManager::debugDumpers() const
+{
+ return m_debugDumpersAction->isChecked();
+}
+
+bool DebuggerManager::useCustomDumpers() const
+{
+ return m_useCustomDumpersAction->isChecked();
+}
+
+bool DebuggerManager::useFastStart() const
+{
+ return 0; // && m_useFastStartAction->isChecked();
+}
+
+void DebuggerManager::queryCurrentTextEditor(QString *fileName, int *lineNumber,
+ QObject **object)
+{
+ emit currentTextEditorRequested(fileName, lineNumber, object);
+}
+
+void DebuggerManager::continueExec()
+{
+ engine()->continueInferior();
+}
+
+void DebuggerManager::interruptDebuggingRequest()
+{
+ //qDebug() << "INTERRUPTING AT" << status();
+ bool interruptIsExit = (status() != DebuggerInferiorRunning);
+ if (interruptIsExit)
+ exitDebugger();
+ else {
+ setStatus(DebuggerInferiorStopRequested);
+ engine()->interruptInferior();
+ }
+}
+
+
+void DebuggerManager::runToLineExec()
+{
+ QString fileName;
+ int lineNumber = -1;
+ emit currentTextEditorRequested(&fileName, &lineNumber, 0);
+ if (!fileName.isEmpty())
+ engine()->runToLineExec(fileName, lineNumber);
+}
+
+void DebuggerManager::runToFunctionExec()
+{
+ QString fileName;
+ int lineNumber = -1;
+ QObject *object = 0;
+ emit currentTextEditorRequested(&fileName, &lineNumber, &object);
+ QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(object);
+ if (!ed)
+ return;
+ QTextCursor cursor = ed->textCursor();
+ QString functionName = cursor.selectedText();
+ if (functionName.isEmpty()) {
+ const QTextBlock block = cursor.block();
+ const QString line = block.text();
+ foreach (const QString &str, line.trimmed().split('(')) {
+ QString a;
+ for (int i = str.size(); --i >= 0; ) {
+ if (!str.at(i).isLetterOrNumber())
+ break;
+ a = str.at(i) + a;
+ }
+ if (!a.isEmpty()) {
+ functionName = a;
+ break;
+ }
+ }
+ }
+ //qDebug() << "RUN TO FUNCTION " << functionName;
+ if (!functionName.isEmpty())
+ engine()->runToFunctionExec(functionName);
+}
+
+void DebuggerManager::jumpToLineExec()
+{
+ QString fileName;
+ int lineNumber = -1;
+ emit currentTextEditorRequested(&fileName, &lineNumber, 0);
+ if (!fileName.isEmpty())
+ engine()->jumpToLineExec(fileName, lineNumber);
+}
+
+void DebuggerManager::resetLocation()
+{
+ //m_watchHandler->removeMouseMoveCatcher(editor->widget());
+ emit resetLocationRequested();
+}
+
+void DebuggerManager::gotoLocation(const QString &fileName, int line,
+ bool setMarker)
+{
+ emit gotoLocationRequested(fileName, line, setMarker);
+ //m_watchHandler->installMouseMoveCatcher(editor->widget());
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Disassembler specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::reloadDisassembler()
+{
+ if (!m_disassemblerDock || !m_disassemblerDock->isVisible())
+ return;
+ engine()->reloadDisassembler();
+}
+
+void DebuggerManager::disassemblerDockToggled(bool on)
+{
+ if (on)
+ reloadDisassembler();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Modules specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::reloadModules()
+{
+ if (!m_modulesDock || !m_modulesDock->isVisible())
+ return;
+ engine()->reloadModules();
+}
+
+void DebuggerManager::modulesDockToggled(bool on)
+{
+ if (on)
+ reloadModules();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Output specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::showDebuggerOutput(const QString &prefix, const QString &msg)
+{
+ m_outputWindow->showOutput(prefix, msg);
+}
+
+void DebuggerManager::showDebuggerInput(const QString &prefix, const QString &msg)
+{
+ m_outputWindow->showInput(prefix, msg);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Register specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::registerDockToggled(bool on)
+{
+ if (on)
+ reloadRegisters();
+}
+
+void DebuggerManager::reloadRegisters()
+{
+ if (!m_registerDock || !m_registerDock->isVisible())
+ return;
+ engine()->reloadRegisters();
+}
+
+
+#include "debuggermanager.moc"
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
new file mode 100644
index 0000000000..beaf876d4b
--- /dev/null
+++ b/src/plugins/debugger/debuggermanager.h
@@ -0,0 +1,451 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_DEBUGGERMANAGER_H
+#define DEBUGGER_DEBUGGERMANAGER_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QAbstractItemModel;
+class QDockWidget;
+class QMainWindow;
+class QModelIndex;
+class QSplitter;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerOutputWindow;
+class DebuggerPlugin;
+class DebugMode;
+
+class BreakHandler;
+class DisassemblerHandler;
+class ModulesHandler;
+class RegisterHandler;
+class StackHandler;
+class ThreadsHandler;
+class WatchHandler;
+class WatchData;
+class BreakpointData;
+
+
+// Note: the Debugger process itself is referred to as 'Debugger',
+// whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
+
+// DebuggerProcessNotReady
+// |
+// DebuggerProcessStartingUp
+// |
+// DebuggerReady [R] [N]
+// | <-------------------------------------.
+// DebuggerInferiorRunningRequested |
+// | |
+// DebuggerInferiorRunning |
+// | |
+// DebuggerInferiorStopRequested |
+// | |
+// DebuggerInferiorStopped |
+// | |
+// DebuggerInferiorUpdating |
+// | |
+// DebuggerInferiorUpdateFinishing |
+// | |
+// DebuggerInferiorReady [C] [N] |
+// | |
+// `---------------------------------------'
+//
+// Allowed actions:
+// [R] : Run
+// [C] : Continue
+// [N] : Step, Next
+
+
+
+enum DebuggerStatus
+{
+ DebuggerProcessNotReady, // Debugger not started
+ DebuggerProcessStartingUp, // Debugger starting up
+ DebuggerProcessReady, // Debugger started, Inferior not yet
+ // running or already finished
+
+ DebuggerInferiorRunningRequested, // Debuggee requested to run
+ DebuggerInferiorRunning, // Debuggee running
+ DebuggerInferiorStopRequested, // Debuggee running, stop requested
+ DebuggerInferiorStopped, // Debuggee stopped
+
+ DebuggerInferiorUpdating, // Debuggee updating data views
+ DebuggerInferiorUpdateFinishing, // Debuggee updating data views aborting
+ DebuggerInferiorReady,
+};
+
+
+class IDebuggerEngine;
+class GdbEngine;
+class ScriptEngine;
+class WinEngine;
+
+// The construct below is not nice but enforces a bit of order. The
+// DebuggerManager interfaces a lots of thing: The DebuggerPlugin,
+// the DebuggerEngines, the RunMode, the handlers and views.
+// Instead of making the whole interface public, we split in into
+// smaller parts and grant friend access only to the classes that
+// need it.
+
+
+//
+// IDebuggerManagerAccessForEngines
+//
+
+class IDebuggerManagerAccessForEngines
+{
+public:
+ virtual ~IDebuggerManagerAccessForEngines() {}
+
+private:
+ // This is the part of the interface that's exclusively seen by the
+ // debugger engines.
+ friend class GdbEngine;
+ friend class ScriptEngine;
+ friend class WinEngine;
+
+ // called from the engines after successful startup
+ virtual void notifyStartupFinished() = 0;
+ virtual void notifyInferiorStopped() = 0;
+ virtual void notifyInferiorUpdateFinished() = 0;
+ virtual void notifyInferiorRunningRequested() = 0;
+ virtual void notifyInferiorRunning() = 0;
+ virtual void notifyInferiorExited() = 0;
+ virtual void notifyInferiorPidChanged(int) = 0;
+
+ virtual DisassemblerHandler *disassemblerHandler() = 0;
+ virtual ModulesHandler *modulesHandler() = 0;
+ virtual BreakHandler *breakHandler() = 0;
+ virtual RegisterHandler *registerHandler() = 0;
+ virtual StackHandler *stackHandler() = 0;
+ virtual ThreadsHandler *threadsHandler() = 0;
+ virtual WatchHandler *watchHandler() = 0;
+
+ virtual void showApplicationOutput(const QString &prefix, const QString &data) = 0;
+ virtual QAction *useCustomDumpersAction() const = 0;
+ virtual QAction *debugDumpersAction() const = 0;
+ virtual bool skipKnownFrames() const = 0;
+ virtual bool debugDumpers() const = 0;
+ virtual bool useCustomDumpers() const = 0;
+ virtual bool useFastStart() const = 0;
+
+ virtual void reloadDisassembler() = 0;
+ virtual void reloadModules() = 0;
+ virtual void reloadRegisters() = 0;
+};
+
+
+//
+// IDebuggerManagerAccessForDebugMode
+//
+
+class IDebuggerManagerAccessForDebugMode
+{
+public:
+ virtual ~IDebuggerManagerAccessForDebugMode() {}
+
+private:
+ friend class DebugMode;
+
+ virtual QWidget *threadsWindow() = 0;
+ virtual QList<QDockWidget*> dockWidgets() const = 0;
+ virtual void createDockWidgets() = 0;
+};
+
+
+//
+// DebuggerManager
+//
+
+class DebuggerManager : public QObject,
+ public IDebuggerManagerAccessForEngines,
+ public IDebuggerManagerAccessForDebugMode
+{
+ Q_OBJECT
+
+public:
+ DebuggerManager();
+ ~DebuggerManager();
+
+ IDebuggerManagerAccessForEngines *engineInterface();
+ IDebuggerManagerAccessForDebugMode *debugModeInterface();
+ QMainWindow *mainWindow() const { return m_mainWindow; }
+
+ enum StartMode { startInternal, startExternal, attachExternal };
+ enum DebuggerType { GdbDebugger, ScriptDebugger, WinDebugger };
+
+public slots:
+ bool startNewDebugger(StartMode mode);
+ void exitDebugger();
+
+ void setSimpleDockWidgetArrangement();
+ void setLocked(bool locked);
+ void dockToggled(bool on);
+
+ void setBusyCursor(bool on);
+ void queryCurrentTextEditor(QString *fileName, int *lineNumber, QObject **ed);
+ void querySessionValue(const QString &name, QVariant *value);
+ void setSessionValue(const QString &name, const QVariant &value);
+ QVariant configValue(const QString &name);
+ void queryConfigValue(const QString &name, QVariant *value);
+ void setConfigValue(const QString &name, const QVariant &value);
+ QVariant sessionValue(const QString &name);
+
+ void gotoLocation(const QString &file, int line, bool setLocationMarker);
+ void resetLocation();
+
+ void interruptDebuggingRequest();
+ void startExternalApplication();
+ void attachExternalApplication();
+
+ void jumpToLineExec();
+ void runToLineExec();
+ void runToFunctionExec();
+ void toggleBreakpoint();
+ void breakByFunction();
+ void breakByFunction(const QString &functionName);
+ void setBreakpoint(const QString &fileName, int lineNumber);
+ void watchExpression(const QString &expression);
+ void breakAtMain();
+ void activateFrame(int index);
+ void selectThread(int index);
+
+ void stepExec();
+ void stepOutExec();
+ void nextExec();
+ void stepIExec();
+ void nextIExec();
+ void continueExec();
+
+ void addToWatchWindow();
+ void updateWatchModel();
+ void removeWatchExpression(const QString &iname);
+ void expandChildren(const QModelIndex &idx);
+ void collapseChildren(const QModelIndex &idx);
+
+ void sessionLoaded();
+ void aboutToSaveSession();
+
+ void assignValueInDebugger(const QString &expr, const QString &value);
+ void executeDebuggerCommand(const QString &command);
+
+ void showStatusMessage(const QString &msg, int timeout); // -1 forever
+
+private slots:
+ void showDebuggerOutput(const QString &prefix, const QString &msg);
+ void showDebuggerInput(const QString &prefix, const QString &msg);
+ void showApplicationOutput(const QString &prefix, const QString &msg);
+
+ void reloadDisassembler();
+ void disassemblerDockToggled(bool on);
+
+ void reloadModules();
+ void modulesDockToggled(bool on);
+ void loadSymbols(const QString &moduleName);
+ void loadAllSymbols();
+
+ void reloadRegisters();
+ void registerDockToggled(bool on);
+ void setStatus(int status);
+
+private:
+ //
+ // Implementation of IDebuggerManagerAccessForEngines
+ //
+ DisassemblerHandler *disassemblerHandler() { return m_disassemblerHandler; }
+ ModulesHandler *modulesHandler() { return m_modulesHandler; }
+ BreakHandler *breakHandler() { return m_breakHandler; }
+ RegisterHandler *registerHandler() { return m_registerHandler; }
+ StackHandler *stackHandler() { return m_stackHandler; }
+ ThreadsHandler *threadsHandler() { return m_threadsHandler; }
+ WatchHandler *watchHandler() { return m_watchHandler; }
+ QAction *useCustomDumpersAction() const { return m_useCustomDumpersAction; }
+ QAction *debugDumpersAction() const { return m_debugDumpersAction; }
+ bool skipKnownFrames() const;
+ bool debugDumpers() const;
+ bool useCustomDumpers() const;
+ bool useFastStart() const;
+
+ void notifyStartupFinished();
+ void notifyInferiorStopped();
+ void notifyInferiorUpdateFinished();
+ void notifyInferiorRunningRequested();
+ void notifyInferiorRunning();
+ void notifyInferiorExited();
+ void notifyInferiorPidChanged(int);
+
+ void cleanupViews();
+
+ //
+ // Implementation of IDebuggerManagerAccessForDebugMode
+ //
+ QWidget *threadsWindow() { return m_threadsWindow; }
+ QList<QDockWidget*> dockWidgets() const { return m_dockWidgets; }
+ void createDockWidgets();
+
+ //
+ // internal implementation
+ //
+ Q_SLOT void loadSessionData();
+ Q_SLOT void saveSessionData();
+ Q_SLOT void dumpLog();
+
+public:
+ // stuff in this block should be made private by moving it to
+ // one of the interfaces
+ QAbstractItemModel *threadsModel();
+ int status() const { return m_status; }
+ StartMode startMode() const { return m_startMode; }
+
+signals:
+ void debuggingFinished();
+ void inferiorPidChanged(qint64 pid);
+ void statusChanged(int newstatus);
+ void debugModeRequested();
+ void previousModeRequested();
+ void statusMessageRequested(const QString &msg, int timeout); // -1 for 'forever'
+ void gotoLocationRequested(const QString &file, int line, bool setLocationMarker);
+ void resetLocationRequested();
+ void currentTextEditorRequested(QString *fileName, int *lineNumber, QObject **ob);
+ void currentMainWindowRequested(QWidget **);
+ void sessionValueRequested(const QString &name, QVariant *value);
+ void setSessionValueRequested(const QString &name, const QVariant &value);
+ void configValueRequested(const QString &name, QVariant *value);
+ void setConfigValueRequested(const QString &name, const QVariant &value);
+ void applicationOutputAvailable(const QString &prefix, const QString &msg);
+
+
+public:
+ // FIXME: make private
+ QString m_executable;
+ QStringList m_environment;
+ QString m_workingDir;
+ QString m_buildDir;
+ QStringList m_processArgs;
+ int m_attachedPID;
+
+private:
+ void init();
+ void setDebuggerType(DebuggerType type);
+ QDockWidget *createDockForWidget(QWidget *widget);
+
+ void shutdown();
+
+ void toggleBreakpoint(const QString &fileName, int lineNumber);
+ void setToolTipExpression(const QPoint &pos, const QString &exp0);
+
+ StartMode m_startMode;
+ DebuggerType m_debuggerType;
+
+ /// Views
+ QMainWindow *m_mainWindow;
+ QDockWidget *m_breakDock;
+ QDockWidget *m_disassemblerDock;
+ QDockWidget *m_modulesDock;
+ QDockWidget *m_outputDock;
+ QDockWidget *m_registerDock;
+ QDockWidget *m_stackDock;
+ QDockWidget *m_threadsDock;
+ QDockWidget *m_watchDock;
+ QList<QDockWidget*> m_dockWidgets;
+
+ BreakHandler *m_breakHandler;
+ DisassemblerHandler *m_disassemblerHandler;
+ ModulesHandler *m_modulesHandler;
+ RegisterHandler *m_registerHandler;
+ StackHandler *m_stackHandler;
+ ThreadsHandler *m_threadsHandler;
+ WatchHandler *m_watchHandler;
+
+ /// Actions
+ friend class DebuggerPlugin;
+ QAction *m_startExternalAction;
+ QAction *m_attachExternalAction;
+ QAction *m_continueAction;
+ QAction *m_stopAction;
+ QAction *m_resetAction; // FIXME: Should not be needed in a stable release
+ QAction *m_stepAction;
+ QAction *m_stepOutAction;
+ QAction *m_runToLineAction;
+ QAction *m_runToFunctionAction;
+ QAction *m_jumpToLineAction;
+ QAction *m_nextAction;
+ QAction *m_watchAction;
+ QAction *m_breakAction;
+ QAction *m_breakByFunctionAction;
+ QAction *m_breakAtMainAction;
+ QAction *m_sepAction;
+ QAction *m_stepIAction;
+ QAction *m_nextIAction;
+ QAction *m_skipKnownFramesAction;
+
+ QAction *m_debugDumpersAction;
+ QAction *m_useCustomDumpersAction;
+ QAction *m_useFastStartAction;
+ QAction *m_dumpLogAction;
+
+ QWidget *m_breakWindow;
+ QWidget *m_disassemblerWindow;
+ QWidget *m_localsWindow;
+ QWidget *m_registerWindow;
+ QWidget *m_modulesWindow;
+ QWidget *m_tooltipWindow;
+ QWidget *m_stackWindow;
+ QWidget *m_threadsWindow;
+ QWidget *m_watchersWindow;
+ DebuggerOutputWindow *m_outputWindow;
+
+ int m_status;
+ bool m_busy;
+
+ IDebuggerEngine *engine();
+ IDebuggerEngine *m_engine;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_DEBUGGERMANAGER_H
diff --git a/src/plugins/debugger/debuggeroutputwindow.cpp b/src/plugins/debugger/debuggeroutputwindow.cpp
new file mode 100644
index 0000000000..7f6bef85d7
--- /dev/null
+++ b/src/plugins/debugger/debuggeroutputwindow.cpp
@@ -0,0 +1,318 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "debuggeroutputwindow.h"
+
+#include <QtCore/QDebug>
+
+#include <QtGui/QAction>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QSplitter>
+#include <QtGui/QTextBlock>
+
+#ifndef GDBDEBUGGERLEAN
+
+#include <aggregation/aggregate.h>
+#include <find/basetextfind.h>
+
+using namespace Find;
+
+#endif // GDBDEBUGGERLEAN
+
+using Debugger::Internal::DebuggerOutputWindow;
+
+/////////////////////////////////////////////////////////////////////
+//
+// InputPane
+//
+/////////////////////////////////////////////////////////////////////
+
+class DebuggerPane : public QTextEdit
+{
+public:
+ DebuggerPane(QWidget *parent)
+ : QTextEdit(parent)
+ {
+ m_clearContentsAction = new QAction(this);
+ m_clearContentsAction->setText("Clear contents");
+ m_clearContentsAction->setEnabled(true);
+ m_clearContentsAction->setShortcut(Qt::ControlModifier + Qt::Key_R);
+ connect(m_clearContentsAction, SIGNAL(triggered(bool)),
+ parent, SLOT(clearContents()));
+
+ m_saveContentsAction = new QAction(this);
+ m_saveContentsAction->setText("Save contents");
+ m_saveContentsAction->setEnabled(true);
+ }
+
+ void contextMenuEvent(QContextMenuEvent *ev)
+ {
+ QMenu *menu = createStandardContextMenu();
+ menu->addAction(m_clearContentsAction);
+ //menu->addAction(m_saveContentsAction);
+ addContextActions(menu);
+ menu->exec(ev->globalPos());
+ delete menu;
+ }
+
+ virtual void addContextActions(QMenu *) {}
+
+public:
+ QAction *m_clearContentsAction;
+ QAction *m_saveContentsAction;
+};
+
+class InputPane : public DebuggerPane
+{
+ Q_OBJECT
+public:
+ InputPane(QWidget *parent) : DebuggerPane(parent)
+ {
+ m_commandExecutionAction = new QAction(this);
+ m_commandExecutionAction->setText("Execute line");
+ m_commandExecutionAction->setEnabled(true);
+ //m_commandExecutionAction->setShortcut
+ // (Qt::ControlModifier + Qt::Key_Return);
+
+ connect(m_commandExecutionAction, SIGNAL(triggered(bool)),
+ this, SLOT(executeCommand()));
+ }
+
+signals:
+ void commandExecutionRequested(const QString &);
+ void clearContentsRequested();
+ void statusMessageRequested(const QString &, int);
+ void commandSelected(int);
+
+private slots:
+ void executeCommand()
+ {
+ emit commandExecutionRequested(textCursor().block().text());
+ }
+
+private:
+ void keyPressEvent(QKeyEvent *ev)
+ {
+ if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return)
+ emit commandExecutionRequested(textCursor().block().text());
+ else if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_R)
+ emit clearContentsRequested();
+ else
+ QTextEdit::keyPressEvent(ev);
+ }
+
+ void mouseDoubleClickEvent(QMouseEvent *ev)
+ {
+ QString line = cursorForPosition(ev->pos()).block().text();
+ int n = 0;
+
+ // cut time string
+ if (line.size() > 18 && line.at(0) == '[')
+ line = line.mid(18);
+ //qDebug() << line;
+
+ for (int i = 0; i != line.size(); ++i) {
+ QChar c = line.at(i);
+ if (!c.isDigit())
+ break;
+ n = 10 * n + c.unicode() - '0';
+ }
+ emit commandSelected(n);
+ }
+
+ void addContextActions(QMenu *menu)
+ {
+ menu->addAction(m_commandExecutionAction);
+ }
+
+ void focusInEvent(QFocusEvent *ev)
+ {
+ emit statusMessageRequested("Type Ctrl-<Return> to execute a line.", -1);
+ QTextEdit::focusInEvent(ev);
+ }
+
+ void focusOutEvent(QFocusEvent *ev)
+ {
+ emit statusMessageRequested(QString(), -1);
+ QTextEdit::focusOutEvent(ev);
+ }
+
+ QAction *m_commandExecutionAction;
+};
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// CombinedPane
+//
+/////////////////////////////////////////////////////////////////////
+
+class CombinedPane : public DebuggerPane
+{
+ Q_OBJECT
+public:
+ CombinedPane(QWidget *parent)
+ : DebuggerPane(parent)
+ {}
+
+public slots:
+ void gotoResult(int i)
+ {
+ QString needle = QString::number(i) + '^';
+ QString needle2 = "stdout:" + needle;
+ QTextCursor cursor(document());
+ do {
+ const QString line = cursor.block().text();
+ if (line.startsWith(needle) || line.startsWith(needle2)) {
+ setFocus();
+ setTextCursor(cursor);
+ ensureCursorVisible();
+ cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor);
+ setTextCursor(cursor);
+ break;
+ }
+ } while (cursor.movePosition(QTextCursor::Down));
+ }
+};
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// DebuggerOutputWindow
+//
+/////////////////////////////////////////////////////////////////////
+
+DebuggerOutputWindow::DebuggerOutputWindow(QWidget *parent)
+ : QWidget(parent)
+{
+ setWindowTitle(tr("Gdb"));
+
+ QSplitter *m_splitter = new QSplitter(Qt::Horizontal, this);
+ // mixed input/output
+ m_combinedText = new CombinedPane(this);
+ m_combinedText->setReadOnly(true);
+ m_combinedText->setReadOnly(false);
+ m_combinedText->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+
+ // input only
+ m_inputText = new InputPane(this);
+ m_inputText->setReadOnly(false);
+ m_inputText->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+
+ m_splitter->addWidget(m_inputText);
+ m_splitter->addWidget(m_combinedText);
+
+ QGridLayout *layout = new QGridLayout(this);
+ layout->setMargin(0);
+ layout->addWidget(m_splitter);
+ setLayout(layout);
+
+#ifndef GDBDEBUGGERLEAN
+ Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
+ aggregate->add(m_combinedText);
+ aggregate->add(new BaseTextFind(m_combinedText));
+
+ aggregate = new Aggregation::Aggregate;
+ aggregate->add(m_inputText);
+ aggregate->add(new BaseTextFind(m_inputText));
+#endif
+
+ connect(m_inputText, SIGNAL(commandExecutionRequested(QString)),
+ this, SIGNAL(commandExecutionRequested(QString)));
+ connect(m_inputText, SIGNAL(statusMessageRequested(QString,int)),
+ this, SIGNAL(statusMessageRequested(QString,int)));
+ connect(m_inputText, SIGNAL(commandSelected(int)),
+ m_combinedText, SLOT(gotoResult(int)));
+};
+
+void DebuggerOutputWindow::onReturnPressed()
+{
+ emit commandExecutionRequested(m_commandEdit->text());
+}
+
+void DebuggerOutputWindow::showOutput(const QString &prefix, const QString &output)
+{
+ if (output.isEmpty())
+ return;
+ foreach (QString line, output.split("\n")) {
+ // FIXME: QTextEdit asserts on really long lines...
+ const int n = 3000;
+ if (line.size() > n)
+ line = line.left(n) + " [...] <cut off>";
+ m_combinedText->append(prefix + line);
+ }
+ QTextCursor cursor = m_combinedText->textCursor();
+ cursor.movePosition(QTextCursor::End);
+ m_combinedText->setTextCursor(cursor);
+ m_combinedText->ensureCursorVisible();
+}
+
+void DebuggerOutputWindow::showInput(const QString &prefix, const QString &input)
+{
+ m_inputText->append(input);
+ QTextCursor cursor = m_inputText->textCursor();
+ cursor.movePosition(QTextCursor::End);
+ m_inputText->setTextCursor(cursor);
+ m_inputText->ensureCursorVisible();
+ showOutput("input:", input);
+}
+
+void DebuggerOutputWindow::clearContents()
+{
+ m_combinedText->clear();
+ m_inputText->clear();
+}
+
+void DebuggerOutputWindow::setCursor(const QCursor &cursor)
+{
+ m_combinedText->setCursor(cursor);
+ m_inputText->setCursor(cursor);
+ QWidget::setCursor(cursor);
+}
+
+QString DebuggerOutputWindow::combinedContents() const
+{
+ return m_combinedText->toPlainText();
+}
+
+QString DebuggerOutputWindow::inputContents() const
+{
+ return m_inputText->toPlainText();
+}
+
+#include "debuggeroutputwindow.moc"
diff --git a/src/plugins/debugger/debuggeroutputwindow.h b/src/plugins/debugger/debuggeroutputwindow.h
new file mode 100644
index 0000000000..f844c0fff9
--- /dev/null
+++ b/src/plugins/debugger/debuggeroutputwindow.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_OUTPUTWINDOW_H
+#define DEBUGGER_OUTPUTWINDOW_H
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QSplitter>
+#include <QtGui/QTextEdit>
+#include <QtGui/QWidget>
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerOutputWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ DebuggerOutputWindow(QWidget *parent = 0);
+
+ QWidget *outputWidget(QWidget *) { return this; }
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+
+ QString name() const { return windowTitle(); }
+ void visibilityChanged(bool /*visible*/) {}
+
+ void bringPaneToForeground() { emit showPage(); }
+ void setCursor(const QCursor &cursor);
+
+ QString combinedContents() const;
+ QString inputContents() const;
+
+public slots:
+ void clearContents();
+ void showOutput(const QString &prefix, const QString &output);
+ void showInput(const QString &prefix, const QString &input);
+
+signals:
+ void showPage();
+ void statusMessageRequested(const QString &msg, int);
+ void commandExecutionRequested(const QString &cmd);
+
+private slots:
+ void onReturnPressed();
+
+private:
+ QTextEdit *m_combinedText; // combined input/output
+ QTextEdit *m_inputText; // scriptable input alone
+ QLineEdit *m_commandEdit;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_OUTPUTWINDOW_H
+
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
new file mode 100644
index 0000000000..8fe6cb0250
--- /dev/null
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -0,0 +1,610 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "debuggerplugin.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+#include "debuggerrunner.h"
+#include "gdboptionpage.h"
+#include "gdbengine.h"
+#include "mode.h"
+
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <cplusplus/ExpressionUnderCursor.h>
+#include <cppeditor/cppeditorconstants.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/session.h>
+#include <texteditor/basetextmark.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/texteditorconstants.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/qplugin.h>
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QSettings>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextCursor>
+
+
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+using namespace TextEditor;
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace CPlusPlus;
+
+
+namespace Debugger {
+namespace Constants {
+
+const char * const STARTEXTERNAL = "Debugger.StartExternal";
+const char * const ATTACHEXTERNAL = "Debugger.AttachExternal";
+
+const char * const RUN_TO_LINE = "Debugger.RunToLine";
+const char * const RUN_TO_FUNCTION = "Debugger.RunToFunction";
+const char * const JUMP_TO_LINE = "Debugger.JumpToLine";
+const char * const TOGGLE_BREAK = "Debugger.ToggleBreak";
+const char * const BREAK_BY_FUNCTION = "Debugger.BreakByFunction";
+const char * const BREAK_AT_MAIN = "Debugger.BreakAtMain";
+const char * const DEBUG_DUMPERS = "Debugger.DebugDumpers";
+const char * const ADD_TO_WATCH = "Debugger.AddToWatch";
+const char * const USE_CUSTOM_DUMPERS = "Debugger.UseCustomDumpers";
+const char * const USE_FAST_START = "Debugger.UseFastStart";
+const char * const SKIP_KNOWN_FRAMES = "Debugger.SkipKnownFrames";
+const char * const DUMP_LOG = "Debugger.DumpLog";
+
+#ifdef Q_OS_MAC
+const char * const INTERRUPT_KEY = "Shift+F5";
+const char * const RESET_KEY = "Ctrl+Shift+F5";
+const char * const STEP_KEY = "F7";
+const char * const STEPOUT_KEY = "Shift+F7";
+const char * const NEXT_KEY = "F6";
+const char * const STEPI_KEY = "Shift+F9";
+const char * const NEXTI_KEY = "Shift+F6";
+const char * const RUN_TO_LINE_KEY = "Shift+F8";
+const char * const RUN_TO_FUNCTION_KEY = "Ctrl+F6";
+const char * const JUMP_TO_LINE_KEY = "Alt+D,Alt+L";
+const char * const TOGGLE_BREAK_KEY = "F8";
+const char * const BREAK_BY_FUNCTION_KEY = "Alt+D,Alt+F";
+const char * const BREAK_AT_MAIN_KEY = "Alt+D,Alt+M";
+const char * const ADD_TO_WATCH_KEY = "Alt+D,Alt+W";
+#else
+const char * const INTERRUPT_KEY = "Shift+F5";
+const char * const RESET_KEY = "Ctrl+Shift+F5";
+const char * const STEP_KEY = "F11";
+const char * const STEPOUT_KEY = "Shift+F11";
+const char * const NEXT_KEY = "F10";
+const char * const STEPI_KEY = "";
+const char * const NEXTI_KEY = "";
+const char * const RUN_TO_LINE_KEY = "";
+const char * const RUN_TO_FUNCTION_KEY = "";
+const char * const JUMP_TO_LINE_KEY = "";
+const char * const TOGGLE_BREAK_KEY = "F9";
+const char * const BREAK_BY_FUNCTION_KEY = "";
+const char * const BREAK_AT_MAIN_KEY = "";
+const char * const ADD_TO_WATCH_KEY = "Ctrl+Alt+Q";
+#endif
+
+} // namespace Constants
+} // namespace Debugger
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// LocationMark
+//
+///////////////////////////////////////////////////////////////////////
+
+class Debugger::Internal::LocationMark
+ : public TextEditor::BaseTextMark
+{
+ Q_OBJECT
+
+public:
+ LocationMark(const QString &fileName, int linenumber)
+ : BaseTextMark(fileName, linenumber)
+ {
+ }
+ ~LocationMark();
+
+ QIcon icon() const;
+ void updateLineNumber(int /*lineNumber*/) {}
+ void updateBlock(const QTextBlock & /*block*/) {}
+ void removedFromEditor() { deleteLater(); }
+private:
+};
+
+LocationMark::~LocationMark()
+{
+ //qDebug() << "LOCATIONMARK DESTRUCTOR" << m_editor;
+}
+
+QIcon LocationMark::icon() const
+{
+ static const QIcon icon(":/gdbdebugger/images/location.svg");
+ return icon;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// DebuggerPlugin
+//
+///////////////////////////////////////////////////////////////////////
+
+DebuggerPlugin::DebuggerPlugin()
+{
+ m_pm = 0;
+ m_generalOptionPage = 0;
+ m_typeMacroPage = 0;
+ m_locationMark = 0;
+ m_manager = 0;
+}
+
+DebuggerPlugin::~DebuggerPlugin()
+{}
+
+void DebuggerPlugin::shutdown()
+{
+ if (m_debugMode)
+ m_debugMode->shutdown(); // saves state including manager information
+ QWB_ASSERT(m_manager, /**/);
+ if (m_manager)
+ m_manager->shutdown();
+
+ //qDebug() << "DebuggerPlugin::~DebuggerPlugin";
+ removeObject(m_debugMode);
+ removeObject(m_generalOptionPage);
+ removeObject(m_typeMacroPage);
+
+ // FIXME: when using the line below, BreakWindow etc gets deleted twice.
+ // so better leak for now...
+ delete m_debugMode;
+ m_debugMode = 0;
+
+ delete m_generalOptionPage;
+ m_generalOptionPage = 0;
+
+ delete m_typeMacroPage;
+ m_typeMacroPage = 0;
+
+ delete m_locationMark;
+ m_locationMark = 0;
+
+ delete m_manager;
+ m_manager = 0;
+}
+
+bool DebuggerPlugin::initialize(const QStringList &arguments, QString *error_message)
+{
+ Q_UNUSED(arguments);
+ Q_UNUSED(error_message);
+
+ m_manager = new DebuggerManager;
+
+ m_pm = ExtensionSystem::PluginManager::instance();
+
+ ICore *core = m_pm->getObject<Core::ICore>();
+ QWB_ASSERT(core, return false);
+
+ Core::ActionManagerInterface *actionManager = core->actionManager();
+ QWB_ASSERT(actionManager, return false);
+
+ Core::UniqueIDManager *uidm = core->uniqueIDManager();
+ QWB_ASSERT(uidm, return false);
+
+ QList<int> globalcontext;
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+
+ QList<int> cppcontext;
+ cppcontext << uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
+
+ QList<int> debuggercontext;
+ debuggercontext << uidm->uniqueIdentifier(C_GDBDEBUGGER);
+
+ QList<int> cppeditorcontext;
+ cppeditorcontext << uidm->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
+
+ QList<int> texteditorcontext;
+ texteditorcontext << uidm->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+
+ m_gdbRunningContext = uidm->uniqueIdentifier(Constants::GDBRUNNING);
+
+ //Core::IActionContainer *mcppcontext =
+ // actionManager->actionContainer(CppEditor::Constants::M_CONTEXT);
+
+ Core::IActionContainer *mdebug =
+ actionManager->actionContainer(ProjectExplorer::Constants::M_DEBUG);
+
+ Core::ICommand *cmd = 0;
+ cmd = actionManager->registerAction(m_manager->m_startExternalAction,
+ Constants::STARTEXTERNAL, globalcontext);
+ mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+
+#ifndef Q_OS_WIN
+ cmd = actionManager->registerAction(m_manager->m_attachExternalAction,
+ Constants::ATTACHEXTERNAL, globalcontext);
+ mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+#endif
+
+ cmd = actionManager->registerAction(m_manager->m_continueAction,
+ ProjectExplorer::Constants::DEBUG, QList<int>()<< m_gdbRunningContext);
+
+ cmd = actionManager->registerAction(m_manager->m_stopAction,
+ Constants::INTERRUPT, globalcontext);
+ cmd->setAttribute(Core::ICommand::CA_UpdateText);
+ cmd->setAttribute(Core::ICommand::CA_UpdateIcon);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::INTERRUPT_KEY));
+ cmd->setDefaultText(tr("Stop Debugger/Interrupt Debugger"));
+ mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+
+ cmd = actionManager->registerAction(m_manager->m_resetAction,
+ Constants::RESET, globalcontext);
+ cmd->setAttribute(Core::ICommand::CA_UpdateText);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::RESET_KEY));
+ cmd->setDefaultText(tr("Reset Debugger"));
+ //disabled mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+
+ QAction *sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = actionManager->registerAction(sep,
+ QLatin1String("GdbDebugger.Sep1"), globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_nextAction,
+ Constants::NEXT, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::NEXT_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_stepAction,
+ Constants::STEP, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::STEP_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_stepOutAction,
+ Constants::STEPOUT, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::STEPOUT_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_nextIAction,
+ Constants::NEXTI, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::NEXTI_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_stepIAction,
+ Constants::STEPI, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::STEPI_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_runToLineAction,
+ Constants::RUN_TO_LINE, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_LINE_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_runToFunctionAction,
+ Constants::RUN_TO_FUNCTION, debuggercontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_FUNCTION_KEY));
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_jumpToLineAction,
+ Constants::JUMP_TO_LINE, debuggercontext);
+ mdebug->addAction(cmd);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = actionManager->registerAction(sep,
+ QLatin1String("GdbDebugger.Sep3"), globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_breakAction,
+ Constants::TOGGLE_BREAK, cppeditorcontext);
+ cmd->setDefaultKeySequence(QKeySequence(Constants::TOGGLE_BREAK_KEY));
+ mdebug->addAction(cmd);
+ //mcppcontext->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_breakByFunctionAction,
+ Constants::BREAK_BY_FUNCTION, globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_breakAtMainAction,
+ Constants::BREAK_AT_MAIN, globalcontext);
+ mdebug->addAction(cmd);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = actionManager->registerAction(sep,
+ QLatin1String("GdbDebugger.Sep2"), globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_skipKnownFramesAction,
+ Constants::SKIP_KNOWN_FRAMES, globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_useCustomDumpersAction,
+ Constants::USE_CUSTOM_DUMPERS, globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_useFastStartAction,
+ Constants::USE_FAST_START, globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_dumpLogAction,
+ Constants::DUMP_LOG, globalcontext);
+ //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
+ mdebug->addAction(cmd);
+
+#ifdef QT_DEBUG
+ cmd = actionManager->registerAction(m_manager->m_debugDumpersAction,
+ Constants::DEBUG_DUMPERS, debuggercontext);
+ mdebug->addAction(cmd);
+#endif
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = actionManager->registerAction(sep,
+ QLatin1String("GdbDebugger.Sep4"), globalcontext);
+ mdebug->addAction(cmd);
+
+ cmd = actionManager->registerAction(m_manager->m_watchAction,
+ Constants::ADD_TO_WATCH, cppeditorcontext);
+ //cmd->setDefaultKeySequence(QKeySequence(tr("ALT+D,ALT+W")));
+ mdebug->addAction(cmd);
+
+ m_generalOptionPage = 0;
+ m_typeMacroPage = 0;
+
+ // FIXME:
+ m_generalOptionPage = new GdbOptionPage(&theGdbSettings());
+ addObject(m_generalOptionPage);
+ m_typeMacroPage = new TypeMacroPage(&theGdbSettings());
+ addObject(m_typeMacroPage);
+
+ m_locationMark = 0;
+
+ m_debugMode = new DebugMode(m_manager, this);
+ //addAutoReleasedObject(m_debugMode);
+ addObject(m_debugMode);
+
+ addAutoReleasedObject(new DebuggerRunner(m_manager));
+
+ // ProjectExplorer
+ connect(projectExplorer()->session(), SIGNAL(sessionLoaded()),
+ m_manager, SLOT(sessionLoaded()));
+ connect(projectExplorer()->session(), SIGNAL(aboutToSaveSession()),
+ m_manager, SLOT(aboutToSaveSession()));
+
+ // EditorManager
+ QObject *editorManager = core->editorManager();
+ connect(editorManager, SIGNAL(editorAboutToClose(Core::IEditor*)),
+ this, SLOT(editorAboutToClose(Core::IEditor*)));
+ connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)),
+ this, SLOT(editorOpened(Core::IEditor*)));
+
+ // Application interaction
+ connect(m_manager, SIGNAL(currentTextEditorRequested(QString*,int*,QObject**)),
+ this, SLOT(queryCurrentTextEditor(QString*,int*,QObject**)));
+
+ connect(m_manager, SIGNAL(setSessionValueRequested(QString,QVariant)),
+ this, SLOT(setSessionValue(QString,QVariant)));
+ connect(m_manager, SIGNAL(sessionValueRequested(QString,QVariant*)),
+ this, SLOT(querySessionValue(QString,QVariant*)));
+ connect(m_manager, SIGNAL(setConfigValueRequested(QString,QVariant)),
+ this, SLOT(setConfigValue(QString,QVariant)));
+ connect(m_manager, SIGNAL(configValueRequested(QString,QVariant*)),
+ this, SLOT(queryConfigValue(QString,QVariant*)));
+
+ connect(m_manager, SIGNAL(resetLocationRequested()),
+ this, SLOT(resetLocation()));
+ connect(m_manager, SIGNAL(gotoLocationRequested(QString,int,bool)),
+ this, SLOT(gotoLocation(QString,int,bool)));
+ connect(m_manager, SIGNAL(statusChanged(int)),
+ this, SLOT(changeStatus(int)));
+ connect(m_manager, SIGNAL(previousModeRequested()),
+ this, SLOT(activatePreviousMode()));
+ connect(m_manager, SIGNAL(debugModeRequested()),
+ this, SLOT(activateDebugMode()));
+
+ return true;
+}
+
+void DebuggerPlugin::extensionsInitialized()
+{
+}
+
+ProjectExplorer::ProjectExplorerPlugin *DebuggerPlugin::projectExplorer() const
+{
+ return m_pm->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+}
+
+/*! Activates the previous mode when the current mode is the debug mode. */
+void DebuggerPlugin::activatePreviousMode()
+{
+ ICore *core = m_pm->getObject<Core::ICore>();
+ Core::ModeManager *const modeManager = core->modeManager();
+
+ if (modeManager->currentMode() == modeManager->mode(Constants::MODE_DEBUG)
+ && !m_previousMode.isEmpty()) {
+ modeManager->activateMode(m_previousMode);
+ m_previousMode.clear();
+ }
+}
+
+void DebuggerPlugin::activateDebugMode()
+{
+ ICore *core = m_pm->getObject<Core::ICore>();
+ Core::ModeManager *modeManager = core->modeManager();
+ m_previousMode = QLatin1String(modeManager->currentMode()->uniqueModeName());
+ modeManager->activateMode(QLatin1String(MODE_DEBUG));
+}
+
+void DebuggerPlugin::queryCurrentTextEditor(QString *fileName, int *lineNumber, QObject **object)
+{
+ ICore *core = m_pm->getObject<Core::ICore>();
+ if (!core || !core->editorManager())
+ return;
+ Core::IEditor *editor = core->editorManager()->currentEditor();
+ ITextEditor *textEditor = qobject_cast<ITextEditor*>(editor);
+ if (!textEditor)
+ return;
+ if (fileName)
+ *fileName = textEditor->file()->fileName();
+ if (lineNumber)
+ *lineNumber = textEditor->currentLine();
+ if (object)
+ *object = textEditor->widget();
+}
+
+void DebuggerPlugin::editorOpened(Core::IEditor *editor)
+{
+ if (ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor)) {
+ connect(textEditor, SIGNAL(markRequested(TextEditor::ITextEditor*,int)),
+ this, SLOT(requestMark(TextEditor::ITextEditor*,int)));
+ connect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*,QPoint,int)),
+ this, SLOT(showToolTip(TextEditor::ITextEditor*,QPoint,int)));
+ }
+}
+
+void DebuggerPlugin::editorAboutToClose(Core::IEditor *editor)
+{
+ if (ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor)) {
+ disconnect(textEditor, SIGNAL(markRequested(TextEditor::ITextEditor*,int)),
+ this, SLOT(requestMark(TextEditor::ITextEditor*,int)));
+ disconnect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*,QPoint,int)),
+ this, SLOT(showToolTip(TextEditor::ITextEditor*,QPoint,int)));
+ }
+}
+
+void DebuggerPlugin::requestMark(TextEditor::ITextEditor *editor, int lineNumber)
+{
+ m_manager->toggleBreakpoint(editor->file()->fileName(), lineNumber);
+}
+
+void DebuggerPlugin::showToolTip(TextEditor::ITextEditor *editor,
+ const QPoint &point, int pos)
+{
+ QPlainTextEdit *plaintext = qobject_cast<QPlainTextEdit*>(editor->widget());
+ if (!plaintext)
+ return;
+
+ QString expr = plaintext->textCursor().selectedText();
+ if (expr.isEmpty()) {
+ QTextCursor tc(plaintext->document());
+ tc.setPosition(pos);
+
+ const QChar ch = editor->characterAt(pos);
+ if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
+ tc.movePosition(QTextCursor::EndOfWord);
+
+ // Fetch the expression's code.
+ ExpressionUnderCursor expressionUnderCursor;
+ expr = expressionUnderCursor(tc);
+ }
+ //qDebug() << " TOOLTIP EXPR " << expr;
+ m_manager->setToolTipExpression(point, expr);
+}
+
+void DebuggerPlugin::setSessionValue(const QString &name, const QVariant &value)
+{
+ //qDebug() << "SET SESSION VALUE" << name << value;
+ ProjectExplorerPlugin *pe = projectExplorer();
+ if (pe->session())
+ pe->session()->setValue(name, value);
+ else
+ qDebug() << "FIXME: Session does not exist yet";
+}
+
+void DebuggerPlugin::querySessionValue(const QString &name, QVariant *value)
+{
+ ProjectExplorerPlugin *pe = projectExplorer();
+ *value = pe->session()->value(name);
+ //qDebug() << "GET SESSION VALUE: " << name << value;
+}
+
+
+void DebuggerPlugin::setConfigValue(const QString &name, const QVariant &value)
+{
+ QWB_ASSERT(m_debugMode, return);
+ m_debugMode->settings()->setValue(name, value);
+}
+
+void DebuggerPlugin::queryConfigValue(const QString &name, QVariant *value)
+{
+ QWB_ASSERT(m_debugMode, return);
+ *value = m_debugMode->settings()->value(name);
+}
+
+void DebuggerPlugin::resetLocation()
+{
+ //qDebug() << "RESET_LOCATION: current:" << currentTextEditor();
+ //qDebug() << "RESET_LOCATION: locations:" << m_locationMark;
+ //qDebug() << "RESET_LOCATION: stored:" << m_locationMark->editor();
+ delete m_locationMark;
+ m_locationMark = 0;
+}
+
+void DebuggerPlugin::gotoLocation(const QString &fileName, int lineNumber,
+ bool setMarker)
+{
+ TextEditor::BaseTextEditor::openEditorAt(fileName, lineNumber);
+ if (setMarker) {
+ resetLocation();
+ m_locationMark = new LocationMark(fileName, lineNumber);
+ }
+}
+
+void DebuggerPlugin::changeStatus(int status)
+{
+ bool startIsContinue = (status == DebuggerInferiorStopped);
+ ICore *core = m_pm->getObject<Core::ICore>();
+ if (startIsContinue) {
+ core->addAdditionalContext(m_gdbRunningContext);
+ core->updateContext();
+ } else {
+ core->removeAdditionalContext(m_gdbRunningContext);
+ core->updateContext();
+ }
+}
+
+#include "debuggerplugin.moc"
+
+Q_EXPORT_PLUGIN(DebuggerPlugin)
diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h
new file mode 100644
index 0000000000..0d7cf83bd3
--- /dev/null
+++ b/src/plugins/debugger/debuggerplugin.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGERPLUGIN_H
+#define DEBUGGERPLUGIN_H
+
+#include <projectexplorer/projectexplorer.h>
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QCursor;
+class QAbstractItemView;
+QT_END_NAMESPACE
+
+namespace Core { class IEditor; }
+namespace TextEditor { class ITextEditor; }
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerManager;
+class DebugMode;
+class GdbOptionPage;
+class TypeMacroPage;
+class LocationMark;
+
+class DebuggerPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ DebuggerPlugin();
+ ~DebuggerPlugin();
+
+private:
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void shutdown();
+ void extensionsInitialized();
+
+private slots:
+ void activatePreviousMode();
+ void activateDebugMode();
+ void queryCurrentTextEditor(QString *fileName, int *line, QObject **object);
+ void editorOpened(Core::IEditor *);
+ void editorAboutToClose(Core::IEditor *);
+ void changeStatus(int status);
+ void requestMark(TextEditor::ITextEditor *editor, int lineNumber);
+ void showToolTip(TextEditor::ITextEditor *editor, const QPoint &pnt, int pos);
+
+ void querySessionValue(const QString &name, QVariant *value);
+ void setSessionValue(const QString &name, const QVariant &value);
+ void queryConfigValue(const QString &name, QVariant *value);
+ void setConfigValue(const QString &name, const QVariant &value);
+
+ void resetLocation();
+ void gotoLocation(const QString &fileName, int line, bool setMarker);
+
+private:
+ friend class DebuggerManager;
+ friend class DebugMode; // FIXME: Just a hack now so that it can access the views
+
+ ProjectExplorer::ProjectExplorerPlugin *projectExplorer() const;
+
+ DebuggerManager *m_manager;
+ DebugMode *m_debugMode;
+
+ ExtensionSystem::PluginManager *m_pm;
+ GdbOptionPage *m_generalOptionPage;
+ TypeMacroPage *m_typeMacroPage;
+
+ QString m_previousMode;
+ LocationMark *m_locationMark;
+ int m_gdbRunningContext;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGERPLUGIN_H
diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp
new file mode 100644
index 0000000000..0254bebb9b
--- /dev/null
+++ b/src/plugins/debugger/debuggerrunner.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "debuggerrunner.h"
+
+#include "assert.h"
+#include "debuggermanager.h"
+
+#include <projectexplorer/applicationrunconfiguration.h>
+#include <projectexplorer/environment.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+
+using namespace Debugger::Internal;
+
+using ProjectExplorer::RunConfiguration;
+using ProjectExplorer::RunControl;
+using ProjectExplorer::ApplicationRunConfiguration;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// DebuggerRunner
+//
+////////////////////////////////////////////////////////////////////////
+
+DebuggerRunner::DebuggerRunner(DebuggerManager *manager)
+ : m_manager(manager)
+{}
+
+bool DebuggerRunner::canRun(RunConfigurationPtr runConfiguration, const QString &mode)
+{
+ return mode == ProjectExplorer::Constants::DEBUGMODE
+ && !qSharedPointerCast<ApplicationRunConfiguration>(runConfiguration).isNull();
+}
+
+QString DebuggerRunner::displayName() const
+{
+ return QObject::tr("Debug");
+}
+
+RunControl* DebuggerRunner::run(RunConfigurationPtr runConfiguration, const QString &mode)
+{
+ Q_UNUSED(mode);
+ Q_ASSERT(mode == ProjectExplorer::Constants::DEBUGMODE);
+ ApplicationRunConfigurationPtr rc =
+ qSharedPointerCast<ApplicationRunConfiguration>(runConfiguration);
+ Q_ASSERT(rc);
+ //qDebug() << "***** Debugging" << rc->name() << rc->executable();
+ return new DebuggerRunControl(m_manager, rc);
+}
+
+QWidget *DebuggerRunner::configurationWidget(RunConfigurationPtr runConfiguration)
+{
+ // NBS TODO: Add GDB-specific configuration widget
+ Q_UNUSED(runConfiguration);
+ return 0;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// DebuggerRunControl
+//
+////////////////////////////////////////////////////////////////////////
+
+
+DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
+ QSharedPointer<ApplicationRunConfiguration> runConfiguration)
+ : RunControl(runConfiguration), m_manager(manager), m_running(false)
+{
+ connect(m_manager, SIGNAL(debuggingFinished()),
+ this, SLOT(debuggingFinished()));
+ connect(m_manager, SIGNAL(applicationOutputAvailable(QString, QString)),
+ this, SLOT(slotAddToOutputWindow(QString, QString)));
+ connect(m_manager, SIGNAL(inferiorPidChanged(qint64)),
+ this, SLOT(bringApplicationToForeground(qint64)));
+}
+
+void DebuggerRunControl::start()
+{
+ m_running = true;
+ ApplicationRunConfigurationPtr rc =
+ qSharedPointerCast<ApplicationRunConfiguration>(runConfiguration());
+ QWB_ASSERT(rc, return);
+ ProjectExplorer::Project *project = rc->project();
+ QWB_ASSERT(project, return);
+
+ m_manager->m_executable = rc->executable();
+ m_manager->m_environment = rc->environment().toStringList();
+ m_manager->m_workingDir = rc->workingDirectory();
+ m_manager->m_processArgs = rc->commandLineArguments();
+ m_manager->m_buildDir =
+ project->buildDirectory(project->activeBuildConfiguration());
+ //<daniel> andre: + "\qtc-gdbmacros\"
+
+ //emit addToOutputWindow(this, tr("Debugging %1").arg(m_executable));
+ if (m_manager->startNewDebugger(DebuggerManager::startInternal))
+ emit started();
+ else
+ debuggingFinished();
+}
+
+void DebuggerRunControl::slotAddToOutputWindow(const QString &prefix, const QString &line)
+{
+ Q_UNUSED(prefix);
+ foreach (const QString &l, line.split('\n'))
+ emit addToOutputWindow(this, prefix + l);
+ //emit addToOutputWindow(this, prefix + line);
+}
+
+void DebuggerRunControl::stop()
+{
+ m_manager->exitDebugger();
+}
+
+void DebuggerRunControl::debuggingFinished()
+{
+ m_running = false;
+ //emit addToOutputWindow(this, tr("Debugging %1 finished").arg(m_executable));
+ emit finished();
+}
+
+bool DebuggerRunControl::isRunning() const
+{
+ return m_running;
+}
diff --git a/src/plugins/debugger/debuggerrunner.h b/src/plugins/debugger/debuggerrunner.h
new file mode 100644
index 0000000000..cf8a8d2184
--- /dev/null
+++ b/src/plugins/debugger/debuggerrunner.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGERRUNNER_H
+#define DEBUGGERRUNNER_H
+
+#include <projectexplorer/runconfiguration.h>
+
+namespace ProjectExplorer {
+class ApplicationRunConfiguration;
+}
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerManager;
+class StartData;
+
+typedef QSharedPointer<ProjectExplorer::RunConfiguration>
+ RunConfigurationPtr;
+
+typedef QSharedPointer<ProjectExplorer::ApplicationRunConfiguration>
+ ApplicationRunConfigurationPtr;
+
+class DebuggerRunner : public ProjectExplorer::IRunConfigurationRunner
+{
+ Q_OBJECT
+
+public:
+ explicit DebuggerRunner(DebuggerManager *manager);
+
+ virtual bool canRun(RunConfigurationPtr runConfiguration, const QString &mode);
+ virtual QString displayName() const;
+ virtual ProjectExplorer::RunControl *run(RunConfigurationPtr runConfiguration,
+ const QString &mode);
+ virtual QWidget *configurationWidget(RunConfigurationPtr runConfiguration);
+
+private:
+ DebuggerManager *m_manager;
+};
+
+
+class DebuggerRunControl : public ProjectExplorer::RunControl
+{
+ Q_OBJECT
+
+public:
+ DebuggerRunControl(DebuggerManager *manager,
+ ApplicationRunConfigurationPtr runConfiguration);
+
+ virtual void start();
+ virtual void stop();
+ virtual bool isRunning() const;
+
+private slots:
+ void debuggingFinished();
+ void slotAddToOutputWindow(const QString &prefix, const QString &line);
+
+private:
+ DebuggerManager *m_manager;
+ bool m_running;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGERRUNNER_H
diff --git a/src/plugins/debugger/disassemblerhandler.cpp b/src/plugins/debugger/disassemblerhandler.cpp
new file mode 100644
index 0000000000..02d3172255
--- /dev/null
+++ b/src/plugins/debugger/disassemblerhandler.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "disassemblerhandler.h"
+
+#include "assert.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QAbstractTableModel>
+
+#include <QtGui/QIcon>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+
+
+//////////////////////////////////////////////////////////////////
+//
+// DisassemblerModel
+//
+//////////////////////////////////////////////////////////////////
+
+/*! A model to represent the stack in a QTreeView. */
+class Debugger::Internal::DisassemblerModel : public QAbstractTableModel
+{
+public:
+ DisassemblerModel(QObject *parent);
+
+ // ItemModel
+ 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;
+
+ // Properties
+ void setLines(const QList<DisassemblerLine> &lines);
+ QList<DisassemblerLine> lines() const;
+ void setCurrentLine(int line) { m_currentLine = line; }
+
+private:
+ friend class DisassemblerHandler;
+ QList<DisassemblerLine> m_lines;
+ int m_currentLine;
+ QIcon m_positionIcon;
+ QIcon m_emptyIcon;
+};
+
+DisassemblerModel::DisassemblerModel(QObject *parent)
+ : QAbstractTableModel(parent), m_currentLine(0)
+{
+ m_emptyIcon = QIcon(":/gdbdebugger/images/empty.svg");
+ m_positionIcon = QIcon(":/gdbdebugger/images/location.svg");
+}
+
+int DisassemblerModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_lines.size();
+}
+
+int DisassemblerModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 3;
+}
+
+QVariant DisassemblerModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= m_lines.size())
+ return QVariant();
+
+ const DisassemblerLine &line = m_lines.at(index.row());
+
+ if (role == Qt::DisplayRole) {
+ switch (index.column()) {
+ case 0:
+ return line.addressDisplay;
+ case 1:
+ return line.symbolDisplay;
+ case 2:
+ return line.mnemonic;
+ }
+ } else if (role == Qt::ToolTipRole) {
+ return QString();
+ } else if (role == Qt::DecorationRole && index.column() == 0) {
+ // Return icon that indicates whether this is the active stack frame
+ return (index.row() == m_currentLine) ? m_positionIcon : m_emptyIcon;
+ }
+
+ return QVariant();
+}
+
+QVariant DisassemblerModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ static const char * const headers[] = {
+ QT_TR_NOOP("Address"),
+ QT_TR_NOOP("Symbol"),
+ QT_TR_NOOP("Mnemonic"),
+ };
+ if (section < 3)
+ return tr(headers[section]);
+ }
+ return QVariant();
+}
+
+void DisassemblerModel::setLines(const QList<DisassemblerLine> &lines)
+{
+ m_lines = lines;
+ if (m_currentLine >= m_lines.size())
+ m_currentLine = m_lines.size() - 1;
+ reset();
+}
+
+QList<DisassemblerLine> DisassemblerModel::lines() const
+{
+ return m_lines;
+}
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// DisassemblerHandler
+//
+//////////////////////////////////////////////////////////////////
+
+DisassemblerHandler::DisassemblerHandler()
+{
+ m_model = new DisassemblerModel(this);
+}
+
+void DisassemblerHandler::removeAll()
+{
+ m_model->m_lines.clear();
+}
+
+QAbstractItemModel *DisassemblerHandler::model() const
+{
+ return m_model;
+}
+
+void DisassemblerHandler::setLines(const QList<DisassemblerLine> &lines)
+{
+ m_model->setLines(lines);
+}
+
+QList<DisassemblerLine> DisassemblerHandler::lines() const
+{
+ return m_model->lines();
+}
+
+void DisassemblerHandler::setCurrentLine(int line)
+{
+ m_model->setCurrentLine(line);
+}
diff --git a/src/plugins/debugger/disassemblerhandler.h b/src/plugins/debugger/disassemblerhandler.h
new file mode 100644
index 0000000000..9de497a1b4
--- /dev/null
+++ b/src/plugins/debugger/disassemblerhandler.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DISASSEMBLERHANDLER_H
+#define DISASSEMBLERHANDLER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QAbstractItemModel>
+
+#include <QtGui/QIcon>
+
+namespace Debugger {
+namespace Internal {
+
+class DisassemblerLine
+{
+public:
+ QString address;
+ QString symbol;
+ QString addressDisplay;
+ QString symbolDisplay;
+ QString mnemonic;
+};
+
+class DisassemblerModel;
+
+class DisassemblerHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ DisassemblerHandler();
+ QAbstractItemModel *model() const;
+
+public slots:
+ void removeAll();
+
+ void setLines(const QList<DisassemblerLine> &lines);
+ QList<DisassemblerLine> lines() const;
+ void setCurrentLine(int line);
+
+private:
+ DisassemblerModel *m_model;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DISASSEMBLERHANDLER_H
diff --git a/src/plugins/debugger/disassemblerwindow.cpp b/src/plugins/debugger/disassemblerwindow.cpp
new file mode 100644
index 0000000000..8130031d70
--- /dev/null
+++ b/src/plugins/debugger/disassemblerwindow.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "disassemblerwindow.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QHeaderView>
+#include <QMenu>
+#include <QResizeEvent>
+
+
+using namespace Debugger::Internal;
+
+DisassemblerWindow::DisassemblerWindow()
+ : m_alwaysResizeColumnsToContents(true), m_alwaysReloadContents(false)
+{
+ setWindowTitle(tr("Disassembler"));
+ setSortingEnabled(false);
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+ header()->hide();
+ //setIconSize(QSize(10, 10));
+ //setWindowIcon(QIcon(":/gdbdebugger/images/debugger_breakpoints.png"));
+ //QHeaderView *hv = header();
+ //hv->setDefaultAlignment(Qt::AlignLeft);
+ //hv->setClickable(true);
+ //hv->setSortIndicatorShown(true);
+}
+
+void DisassemblerWindow::resizeEvent(QResizeEvent *ev)
+{
+ //QHeaderView *hv = header();
+ //int totalSize = ev->size().width() - 110;
+ //hv->resizeSection(0, 60);
+ //hv->resizeSection(1, (totalSize * 50) / 100);
+ //hv->resizeSection(2, (totalSize * 50) / 100);
+ //hv->resizeSection(3, 50);
+ QTreeView::resizeEvent(ev);
+}
+
+void DisassemblerWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ QMenu menu;
+ //QTreeWidgetItem *item = itemAt(ev->pos());
+ QAction *act1 = new QAction("Adjust column widths to contents", &menu);
+ QAction *act2 = new QAction("Always adjust column widths to contents", &menu);
+ act2->setCheckable(true);
+ act2->setChecked(m_alwaysResizeColumnsToContents);
+ QAction *act3 = new QAction("Reload disassembler listing", &menu);
+ QAction *act4 = new QAction("Always reload disassembler listing", &menu);
+ act4->setCheckable(true);
+ act4->setChecked(m_alwaysReloadContents);
+ //if (item) {
+ // menu.addAction(act0);
+ // menu.addSeparator();
+ //}
+ menu.addAction(act3);
+ //menu.addAction(act4);
+ menu.addSeparator();
+ menu.addAction(act1);
+ menu.addAction(act2);
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (act == act1)
+ resizeColumnsToContents();
+ else if (act == act2)
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+ else if (act == act3)
+ reloadContents();
+ else if (act == act2)
+ setAlwaysReloadContents(!m_alwaysReloadContents);
+}
+
+void DisassemblerWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+ resizeColumnToContents(2);
+}
+
+void DisassemblerWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ header()->setResizeMode(1, mode);
+ header()->setResizeMode(2, mode);
+}
+
+void DisassemblerWindow::setAlwaysReloadContents(bool on)
+{
+ m_alwaysReloadContents = on;
+ if (m_alwaysReloadContents)
+ reloadContents();
+}
+
+void DisassemblerWindow::reloadContents()
+{
+ emit reloadDisassemblerRequested();
+}
+
+
+void DisassemblerWindow::setModel(QAbstractItemModel *model)
+{
+ QTreeView::setModel(model);
+ setAlwaysResizeColumnsToContents(true);
+}
+
diff --git a/src/plugins/debugger/disassemblerwindow.h b/src/plugins/debugger/disassemblerwindow.h
new file mode 100644
index 0000000000..3715afca21
--- /dev/null
+++ b/src/plugins/debugger/disassemblerwindow.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_DISASSEMBLERWINDOW_H
+#define DEBUGGER_DISASSEMBLERWINDOW_H
+
+#include <QTreeView>
+
+namespace Debugger {
+namespace Internal {
+
+class DisassemblerWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ DisassemblerWindow();
+ void setModel(QAbstractItemModel *model);
+
+signals:
+ void reloadDisassemblerRequested();
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on);
+ void reloadContents();
+ void setAlwaysReloadContents(bool on);
+
+protected:
+ void resizeEvent(QResizeEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+
+private:
+ bool m_alwaysResizeColumnsToContents;
+ bool m_alwaysReloadContents;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_DISASSEMBLERWINDOW_H
+
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
new file mode 100644
index 0000000000..9a29bc8675
--- /dev/null
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -0,0 +1,4035 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "gdbengine.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+#include "gdbmi.h"
+#include "procinterrupt.h"
+
+#include "disassemblerhandler.h"
+#include "breakhandler.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+
+#include "startexternaldialog.h"
+#include "attachexternaldialog.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTime>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QLabel>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QToolTip>
+
+#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
+#include <unistd.h>
+#include <dlfcn.h>
+#endif
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+Q_DECLARE_METATYPE(Debugger::Internal::GdbMi);
+
+//#define DEBUG_PENDING 1
+//#define DEBUG_SUBITEM 1
+
+#if DEBUG_PENDING
+# define PENDING_DEBUG(s) qDebug() << s
+#else
+# define PENDING_DEBUG(s)
+#endif
+
+static const QString tooltipIName = "tooltip";
+
+///////////////////////////////////////////////////////////////////////
+//
+// GdbSettings
+//
+///////////////////////////////////////////////////////////////////////
+
+GdbSettings &Debugger::Internal::theGdbSettings()
+{
+ static GdbSettings settings;
+ return settings;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// GdbCommandType
+//
+///////////////////////////////////////////////////////////////////////
+
+enum GdbCommandType
+{
+ GdbInvalidCommand = 0,
+
+ GdbShowVersion = 100,
+ GdbFileExecAndSymbols,
+ GdbQueryPwd,
+ GdbQuerySources,
+ GdbQuerySources2,
+ GdbAsyncOutput2,
+ GdbExecRun,
+ GdbExecRunToFunction,
+ GdbExecStep,
+ GdbExecNext,
+ GdbExecStepI,
+ GdbExecNextI,
+ GdbExecContinue,
+ GdbExecFinish,
+ GdbExecJumpToLine,
+ GdbExecInterrupt,
+ GdbInfoShared,
+ GdbInfoProc,
+ GdbQueryDataDumper1,
+ GdbQueryDataDumper2,
+ GdbInitializeSocket1,
+
+ BreakCondition = 200,
+ BreakEnablePending,
+ BreakSetAnnotate,
+ BreakDelete,
+ BreakList,
+ BreakIgnore,
+ BreakInfo,
+ BreakInsert,
+ BreakInsert1,
+
+ DisassemblerList = 300,
+
+ ModulesList = 400,
+
+ RegisterListNames = 500,
+ RegisterListValues,
+
+ StackSelectThread = 600,
+ StackListThreads,
+ StackListFrames,
+ StackListLocals,
+ StackListArguments,
+
+ WatchVarAssign = 700, // data changed by user
+ WatchVarListChildren,
+ WatchVarCreate,
+ WatchEvaluateExpression,
+ WatchToolTip,
+ WatchDumpCustomSetup,
+ WatchDumpCustomValue1, // waiting for gdb ack
+ WatchDumpCustomValue2, // waiting for actual data
+ WatchDumpCustomEditValue,
+};
+
+QString dotEscape(QString str)
+{
+ str.replace(' ', '.');
+ str.replace('\\', '.');
+ str.replace('/', '.');
+ return str;
+}
+
+QString currentTime()
+{
+ return QTime::currentTime().toString("hh:mm:ss.zzz");
+}
+
+static int &currentToken()
+{
+ static int token = 0;
+ return token;
+}
+
+static bool isSkippableFunction(const QString &funcName, const QString &fileName)
+{
+ if (fileName.endsWith("kernel/qobject.cpp"))
+ return true;
+ if (fileName.endsWith("kernel/moc_qobject.cpp"))
+ return true;
+ if (fileName.endsWith("kernel/qmetaobject.cpp"))
+ return true;
+ if (fileName.endsWith(".moc"))
+ return true;
+
+ if (funcName.endsWith("::qt_metacall"))
+ return true;
+
+ return false;
+}
+
+static bool isLeavableFunction(const QString &funcName, const QString &fileName)
+{
+ if (funcName.endsWith("QObjectPrivate::setCurrentSender"))
+ return true;
+ if (fileName.endsWith("kernel/qmetaobject.cpp")
+ && funcName.endsWith("QMetaObject::methodOffset"))
+ return true;
+ if (fileName.endsWith("kernel/qobject.h"))
+ return true;
+ if (fileName.endsWith("kernel/qobject.cpp")
+ && funcName.endsWith("QObjectConnectionListVector::at"))
+ return true;
+ if (fileName.endsWith("kernel/qobject.cpp")
+ && funcName.endsWith("~QObject"))
+ return true;
+ if (fileName.endsWith("thread/qmutex.cpp"))
+ return true;
+ if (fileName.endsWith("thread/qthread.cpp"))
+ return true;
+ if (fileName.endsWith("thread/qthread_unix.cpp"))
+ return true;
+ if (fileName.endsWith("thread/qmutex.h"))
+ return true;
+ if (fileName.contains("thread/qbasicatomic"))
+ return true;
+ if (fileName.contains("thread/qorderedmutexlocker_p"))
+ return true;
+ if (fileName.contains("arch/qatomic"))
+ return true;
+ if (fileName.endsWith("tools/qvector.h"))
+ return true;
+ if (fileName.endsWith("tools/qlist.h"))
+ return true;
+ if (fileName.endsWith("tools/qhash.h"))
+ return true;
+ if (fileName.endsWith("tools/qmap.h"))
+ return true;
+ if (fileName.endsWith("tools/qstring.h"))
+ return true;
+ if (fileName.endsWith("global/qglobal.h"))
+ return true;
+
+ return false;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// GdbEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+GdbEngine::GdbEngine(DebuggerManager *parent)
+{
+ q = parent;
+ qq = parent->engineInterface();
+ init();
+}
+
+GdbEngine::~GdbEngine()
+{
+}
+
+void GdbEngine::init()
+{
+ m_pendingRequests = 0;
+ m_gdbVersion = 100;
+ m_shared = 0;
+ qq->debugDumpersAction()->setChecked(false);
+
+ m_oldestAcceptableToken = -1;
+
+ // Gdb Process interaction
+ connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this,
+ SLOT(gdbProcError(QProcess::ProcessError)));
+ connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), this,
+ SLOT(readGdbStandardOutput()));
+ connect(&m_gdbProc, SIGNAL(readyReadStandardError()), this,
+ SLOT(readGdbStandardError()));
+ connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), q,
+ SLOT(exitDebugger()));
+
+ // Custom dumpers
+ //m_dumperServerConnection = 0;
+ //m_dumperServer = new DumperServer(this);
+ //QString name = "gdb-" +
+ // QDateTime::currentDateTime().toString("yyyy_MM_dd-hh_mm_ss_zzz");
+ //m_dumperServer->listen(name);
+ //connect(m_dumperServer, SIGNAL(newConnection()),
+ // this, SLOT(acceptConnection()));
+
+ //if (!m_dumperServer->isListening()) {
+ // QMessageBox::critical(q->mainWindow(), tr("Dumper Server Setup Failed"),
+ // tr("Unable to create server listening for data: %1.\n"
+ // "Server name: %2").arg(m_dumperServer->errorString(), name),
+ // QMessageBox::Retry | QMessageBox::Cancel);
+ // }
+
+ connect(qq->debugDumpersAction(), SIGNAL(toggled(bool)),
+ this, SLOT(setDebugDumpers(bool)));
+
+ connect(qq->useCustomDumpersAction(), SIGNAL(toggled(bool)),
+ this, SLOT(setCustomDumpersWanted(bool)));
+
+ // Output
+ connect(this, SIGNAL(gdbResponseAvailable()),
+ this, SLOT(handleResponse()), Qt::QueuedConnection);
+
+ connect(this, SIGNAL(gdbOutputAvailable(QString,QString)),
+ q, SLOT(showDebuggerOutput(QString,QString)),
+ Qt::QueuedConnection);
+ connect(this, SIGNAL(gdbInputAvailable(QString,QString)),
+ q, SLOT(showDebuggerInput(QString,QString)),
+ Qt::QueuedConnection);
+ connect(this, SIGNAL(applicationOutputAvailable(QString,QString)),
+ q, SLOT(showApplicationOutput(QString,QString)),
+ Qt::QueuedConnection);
+}
+
+void GdbEngine::gdbProcError(QProcess::ProcessError error)
+{
+ QString msg;
+ switch (error) {
+ case QProcess::FailedToStart:
+ msg = QString(tr("The Gdb process failed to start. Either the "
+ "invoked program '%1' is missing, or you may have insufficient "
+ "permissions to invoke the program.")).arg(theGdbSettings().m_gdbCmd);
+ break;
+ case QProcess::Crashed:
+ msg = tr("The Gdb process crashed some time after starting "
+ "successfully.");
+ break;
+ case QProcess::Timedout:
+ msg = tr("The last waitFor...() function timed out. "
+ "The state of QProcess is unchanged, and you can try calling "
+ "waitFor...() again.");
+ break;
+ case QProcess::WriteError:
+ msg = tr("An error occurred when attempting to write "
+ "to the Gdb process. For example, the process may not be running, "
+ "or it may have closed its input channel.");
+ break;
+ case QProcess::ReadError:
+ msg = tr("An error occurred when attempting to read from "
+ "the Gdb process. For example, the process may not be running.");
+ break;
+ default:
+ msg = tr("An unknown error in the Gdb process occurred. "
+ "This is the default return value of error().");
+ }
+
+ q->showStatusMessage(msg, 5000);
+ QMessageBox::critical(q->mainWindow(), tr("Error"), msg);
+ // act as if it was closed by the core
+ q->exitDebugger();
+}
+
+static void skipSpaces(const char *&from, const char *to)
+{
+ while (from != to && QChar(*from).isSpace())
+ ++from;
+}
+
+static inline bool isNameChar(char c)
+{
+ // could be 'stopped' or 'shlibs-added'
+ return (c >= 'a' && c <= 'z') || c == '-';
+}
+
+#if 0
+static void dump(const char *first, const char *middle, const QString & to)
+{
+ QByteArray ba(first, middle - first);
+ Q_UNUSED(to);
+ // note that qDebug cuts off output after a certain size... (bug?)
+ qDebug("\n>>>>> %s\n%s\n====\n%s\n<<<<<\n",
+ qPrintable(currentTime()),
+ qPrintable(QString(ba).trimmed()),
+ qPrintable(to.trimmed()));
+ //qDebug() << "";
+ //qDebug() << qPrintable(currentTime())
+ // << " Reading response: " << QString(ba).trimmed() << "\n";
+}
+#endif
+
+static void skipTerminator(const char *&from, const char *to)
+{
+ skipSpaces(from, to);
+ // skip '(gdb)'
+ if (from[0] == '(' && from[1] == 'g' && from[3] == 'b' && from[4] == ')')
+ from += 5;
+ skipSpaces(from, to);
+}
+
+// called asyncronously as response to Gdb stdout output in
+// gdbResponseAvailable()
+void GdbEngine::handleResponse()
+{
+ static QTime lastTime;
+
+ emit gdbOutputAvailable(" ", currentTime());
+ emit gdbOutputAvailable("stdout:", m_inbuffer);
+
+#if 0
+ qDebug() // << "#### start response handling #### "
+ << currentTime()
+ << lastTime.msecsTo(QTime::currentTime()) << "ms,"
+ << "buf: " << m_inbuffer.left(1500) << "..."
+ //<< "buf: " << m_inbuffer
+ << "size:" << m_inbuffer.size();
+#else
+ //qDebug() << "buf: " << m_inbuffer;
+#endif
+
+ lastTime = QTime::currentTime();
+
+ while (1) {
+ if (m_inbuffer.isEmpty())
+ break;
+
+ const char *from = m_inbuffer.constData();
+ // FIXME: check for line ending in '\n(gdb)\n'
+ const char *to = from + m_inbuffer.size();
+ const char *inner;
+
+ //const char *oldfrom = from;
+
+ //skipSpaces(from, to);
+ skipTerminator(from, to);
+ int token = -1;
+
+ // token is a sequence of numbers
+ for (inner = from; inner != to; ++inner)
+ if (*inner < '0' || *inner > '9')
+ break;
+ if (from != inner) {
+ token = QString(QByteArray(from, inner - from)).toInt();
+ from = inner;
+ //qDebug() << "found token " << token;
+ }
+
+ if (from == to) {
+ //qDebug() << "Returning: " << toString();
+ break;
+ }
+
+ if (token == -1 && *from != '&' && *from != '~') {
+ // FIXME: On Linux the application's std::out is merged in here.
+ // High risk of falsely interpreting this as MI output.
+ // We assume that we _always_ use tokens, so not finding a token
+ // is a positive indication for the presence of application output.
+ QString s;
+ while (from != to && *from != '\n')
+ s += *from++;
+ //qDebug() << "UNREQUESTED DATA " << s << " TAKEN AS APPLICATION OUTPUT";
+ s += '\n';
+
+ m_inbuffer = QByteArray(from, to - from);
+ emit applicationOutputAvailable("app-stdout: ", s);
+ continue;
+ }
+
+ // next char decides kind of record
+ const char c = *from++;
+ //qDebug() << "CODE:" << c;
+
+ switch (c) {
+ case '*':
+ case '+':
+ case '=': {
+ QByteArray asyncClass;
+ for (; from != to; ++from) {
+ const char c = *from;
+ if (!isNameChar(c))
+ break;
+ asyncClass += *from;
+ }
+ //qDebug() << "ASYNCCLASS" << asyncClass;
+
+ GdbMi record;
+ while (from != to && *from == ',') {
+ ++from; // skip ','
+ GdbMi data;
+ data.parseResultOrValue(from, to);
+ if (data.isValid()) {
+ //qDebug() << "parsed response: " << data.toString();
+ record.m_children += data;
+ record.m_type = GdbMi::Tuple;
+ }
+ }
+ //dump(oldfrom, from, record.toString());
+ skipTerminator(from, to);
+ m_inbuffer = QByteArray(from, to - from);
+ if (asyncClass == "stopped") {
+ handleAsyncOutput(record);
+ } else {
+ qDebug() << "INGNORED ASYNC OUTPUT " << record.toString();
+ }
+ break;
+ }
+
+ case '~':
+ case '@':
+ case '&': {
+ QString data = GdbMi::parseCString(from, to);
+ handleStreamOutput(data, c);
+ //dump(oldfrom, from, record.toString());
+ m_inbuffer = QByteArray(from, to - from);
+ break;
+ }
+
+ case '#': {
+ //qDebug() << "CUSTOM OUTPUT, TOKEN" << token;
+ QString str;
+ for (; from != to && *from >= '0' && *from <= '9'; ++from)
+ str += QLatin1Char(*from);
+ ++from; // skip the ' '
+ int len = str.toInt();
+ QByteArray ba(from, len);
+ from += len;
+ m_inbuffer = QByteArray(from, to - from);
+ m_customOutputForToken[token] += QString(ba);
+ break;
+ }
+
+ case '^': {
+ GdbResultRecord record;
+
+ record.token = token;
+
+ for (inner = from; inner != to; ++inner)
+ if (*inner < 'a' || *inner > 'z')
+ break;
+
+ QByteArray resultClass(from, inner - from);
+
+ if (resultClass == "done")
+ record.resultClass = GdbResultDone;
+ else if (resultClass == "running")
+ record.resultClass = GdbResultRunning;
+ else if (resultClass == "connected")
+ record.resultClass = GdbResultConnected;
+ else if (resultClass == "error")
+ record.resultClass = GdbResultError;
+ else if (resultClass == "exit")
+ record.resultClass = GdbResultExit;
+ else
+ record.resultClass = GdbResultUnknown;
+
+ from = inner;
+ skipSpaces(from, to);
+ if (from != to && *from == ',') {
+ ++from;
+ record.data.parseTuple_helper(from, to);
+ record.data.m_type = GdbMi::Tuple;
+ record.data.m_name = "data";
+ }
+ skipSpaces(from, to);
+ skipTerminator(from, to);
+
+ //qDebug() << "\nLOG STREAM:" + m_pendingLogStreamOutput;
+ //qDebug() << "\nTARGET STREAM:" + m_pendingTargetStreamOutput;
+ //qDebug() << "\nCONSOLE STREAM:" + m_pendingConsoleStreamOutput;
+ record.data.setStreamOutput("logstreamoutput",
+ m_pendingLogStreamOutput);
+ record.data.setStreamOutput("targetstreamoutput",
+ m_pendingTargetStreamOutput);
+ record.data.setStreamOutput("consolestreamoutput",
+ m_pendingConsoleStreamOutput);
+ QByteArray custom = m_customOutputForToken[token];
+ if (!custom.isEmpty())
+ record.data.setStreamOutput("customvaluecontents",
+ '{' + custom + '}');
+ //m_customOutputForToken.remove(token);
+ m_pendingLogStreamOutput.clear();
+ m_pendingTargetStreamOutput.clear();
+ m_pendingConsoleStreamOutput.clear();
+
+ //dump(oldfrom, from, record.toString());
+ m_inbuffer = QByteArray(from, to - from);
+ handleResultRecord(record);
+ break;
+ }
+ default: {
+ qDebug() << "FIXME: UNKNOWN CODE: " << c << " IN " << m_inbuffer;
+ m_inbuffer = QByteArray(from, to - from);
+ break;
+ }
+ }
+ }
+
+ //qDebug() << "##### end response handling ####\n\n\n"
+ // << currentTime() << lastTime.msecsTo(QTime::currentTime());
+ lastTime = QTime::currentTime();
+}
+
+#ifdef Q_OS_MAC
+static void fixMac(QByteArray &out)
+{
+ // HACK: gdb on Mac mixes MI1 and MI2 syntax. Not nice.
+ // it returns: 9^done,locals={{name="a"},{name="w"}}
+ // instead of: 9^done,locals=[{name="a"},{name="w"}]
+ if (!out.contains("locals={{name"))
+ return;
+
+ static const QByteArray termArray("(gdb) ");
+ int pos = out.indexOf(termArray);
+ if (pos == -1)
+ return;
+
+ int pos1 = out.indexOf("={{");
+ if (pos1 == -1)
+ return;
+
+ int pos2 = out.indexOf("]]");
+ if (pos2 == -1)
+ return;
+
+ if (pos1 < pos && pos2 < pos) {
+ out[pos1 + 1] = '[';
+ out[pos2 + 1] = ']';
+ }
+}
+#endif
+
+void GdbEngine::readGdbStandardError()
+{
+ QByteArray err = m_gdbProc.readAllStandardError();
+ emit applicationOutputAvailable("app-stderr:", err);
+}
+
+void GdbEngine::readGdbStandardOutput()
+{
+ // This is the function called whenever the Gdb process created
+ // output. As a rule of thumb, stdout contains _real_ Gdb output
+ // as responses to our command (with exception of the data dumpers)
+ // and "spontaneous" events like messages on loaded shared libraries.
+ // Otoh, stderr contains application output produced by qDebug etc.
+ // There is no organized way to pass application stdout output
+
+ // The result of custom data dumpers arrives over the socket _before_
+ // the corresponding Gdb "^done" message arrives here over stdout
+ // and is merged into the response via m_pendingCustomValueContents.
+
+ // Note that this code here runs syncronized to the arriving
+ // output. The completed response will be signalled by a queued
+ // connection to the handlers.
+
+ QByteArray out = m_gdbProc.readAllStandardOutput();
+
+ //qDebug() << "\n\n\nPLUGIN OUT: '" << out.data() << "'\n\n\n";
+
+ #ifdef Q_OS_MAC
+ fixMac(out);
+ #endif
+
+ m_inbuffer.append(out);
+ //QWB_ASSERT(!m_inbuffer.isEmpty(), return);
+
+ char c = m_inbuffer[m_inbuffer.size() - 1];
+ static const QByteArray termArray("(gdb) ");
+ if (out.indexOf(termArray) == -1 && c != 10 && c != 13) {
+ //qDebug() << "\n\nBuffer not yet filled, waiting for more data to arrive";
+ //qDebug() << m_inbuffer.data() << m_inbuffer.size();
+ //qDebug() << "\n\n";
+ return;
+ }
+
+ emit gdbResponseAvailable();
+}
+
+void GdbEngine::interruptInferior()
+{
+ if (m_gdbProc.state() == QProcess::NotRunning)
+ return;
+
+ if (q->m_attachedPID) {
+ if (interruptProcess(q->m_attachedPID))
+ qq->notifyInferiorStopped();
+ return;
+ }
+
+#ifdef Q_OS_MAC
+ sendCommand("-exec-interrupt", GdbExecInterrupt);
+ qq->notifyInferiorStopped();
+#else
+ if (interruptChildProcess(m_gdbProc.pid()))
+ qq->notifyInferiorStopped();
+#endif
+}
+
+void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
+{
+ int pid = pid0.toInt();
+ if (pid == 0) {
+ qDebug() << "Cannot parse PID from " << pid0;
+ return;
+ }
+ if (pid == m_inferiorPid)
+ return;
+ m_inferiorPid = pid;
+ qq->notifyInferiorPidChanged(pid);
+}
+
+void GdbEngine::sendSynchronizedCommand(const QString & command,
+ int type, const QVariant &cookie, bool needStop)
+{
+ sendCommand(command, type, cookie, needStop, true);
+}
+
+void GdbEngine::sendCommand(const QString &command, int type,
+ const QVariant &cookie, bool needStop, bool synchronized)
+{
+ if (m_gdbProc.state() == QProcess::NotRunning) {
+ //qDebug() << "NO GDB PROCESS RUNNING, CMD IGNORED:" << command;
+ return;
+ }
+
+ bool temporarilyStopped = false;
+ if (needStop && q->status() == DebuggerInferiorRunning) {
+ q->showStatusMessage(tr("Temporarily stopped"), -1);
+ interruptInferior();
+ temporarilyStopped = true;
+ }
+
+ ++currentToken();
+ if (synchronized) {
+ ++m_pendingRequests;
+ PENDING_DEBUG(" TYPE " << type << " INCREMENTS PENDING TO: "
+ << m_pendingRequests << command);
+ } else {
+ PENDING_DEBUG(" UNKNOWN TYPE " << type << " LEAVES PENDING AT: "
+ << m_pendingRequests << command);
+ }
+
+ GdbCookie cmd;
+ cmd.synchronized = synchronized;
+ cmd.command = command;
+ cmd.command = QString::number(currentToken()) + cmd.command;
+ if (cmd.command.contains("%1"))
+ cmd.command = cmd.command.arg(currentToken());
+ cmd.type = type;
+ cmd.cookie = cookie;
+
+ m_cookieForToken[currentToken()] = cmd;
+
+ //qDebug() << "";
+ if (!command.isEmpty()) {
+ //qDebug() << qPrintable(currentTime()) << "RUNNING << cmd.command;
+ m_gdbProc.write(cmd.command.toLatin1() + "\r\n");
+ //emit gdbInputAvailable(QString(), " " + currentTime());
+ emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command);
+ //emit gdbInputAvailable(QString(), cmd.command);
+ }
+
+ if (temporarilyStopped)
+ sendCommand("-exec-continue");
+
+ // slows down
+ //qApp->processEvents();
+}
+
+void GdbEngine::handleResultRecord(const GdbResultRecord &record)
+{
+ //qDebug() << "TOKEN: " << record.token
+ // << " ACCEPTABLE: " << m_oldestAcceptableToken;
+ //qDebug() << "";
+ //qDebug() << qPrintable(currentTime()) << "Reading response: "
+ // << record.toString() << "\n";
+ //qDebug() << "\nRESULT" << record.token << record.toString();
+
+ int token = record.token;
+ if (token == -1)
+ return;
+
+ if (!m_cookieForToken.contains(token)) {
+ qDebug() << "NO SUCH TOKEN (ANYMORE): " << token;
+ return;
+ }
+
+ GdbCookie cmd = m_cookieForToken.take(token);
+
+ // FIXME: this falsely rejects results from the custom dumper recognition
+ // procedure, too...
+ if (record.token < m_oldestAcceptableToken) {
+ //qDebug() << "### SKIPPING OLD RESULT " << record.toString();
+ //QMessageBox::information(m_mainWindow, tr("Skipped"), "xxx");
+ return;
+ }
+
+ // We get _two_ results for a '-exec-foo' command: First a
+ // 'running' notification, then a 'stopped' or similar.
+ // So put it back.
+ if (record.resultClass == GdbResultRunning)
+ m_cookieForToken[token] = cmd;
+
+#if 0
+ qDebug() << "# handleOutput, "
+ << "cmd type: " << cmd.type
+ << "cmd synchronized: " << cmd.synchronized
+ << "\n record: " << record.toString();
+#endif
+
+ // << "\n data: " << record.data.toString(true);
+
+ if (cmd.type != GdbInvalidCommand)
+ handleResult(record, cmd.type, cmd.cookie);
+
+ if (cmd.synchronized) {
+ --m_pendingRequests;
+ PENDING_DEBUG(" TYPE " << cmd.type << " DECREMENTS PENDING TO: "
+ << m_pendingRequests << cmd.command);
+ if (m_pendingRequests == 0)
+ updateWatchModel2();
+ } else {
+ PENDING_DEBUG(" UNKNOWN TYPE " << cmd.type << " LEAVES PENDING AT: "
+ << m_pendingRequests << cmd.command);
+ }
+}
+
+void GdbEngine::handleResult(const GdbResultRecord & record, int type,
+ const QVariant & cookie)
+{
+ switch (type) {
+ case GdbExecNext:
+ case GdbExecStep:
+ case GdbExecNextI:
+ case GdbExecStepI:
+ case GdbExecContinue:
+ case GdbExecFinish:
+ // evil code sharing
+ case GdbExecRun:
+ handleExecRun(record);
+ break;
+ case GdbInfoProc:
+ handleInfoProc(record);
+ break;
+
+ case GdbShowVersion:
+ handleShowVersion(record);
+ break;
+ case GdbFileExecAndSymbols:
+ handleFileExecAndSymbols(record);
+ break;
+ case GdbExecRunToFunction:
+ // that should be "^running". We need to handle the resulting
+ // "Stopped"
+ //handleExecRunToFunction(record);
+ break;
+ case GdbExecInterrupt:
+ break;
+ case GdbExecJumpToLine:
+ handleExecJumpToLine(record);
+ break;
+ case GdbQueryPwd:
+ handleQueryPwd(record);
+ break;
+ case GdbQuerySources:
+ handleQuerySources(record);
+ break;
+ case GdbQuerySources2:
+ handleQuerySources2(record, cookie);
+ break;
+ case GdbAsyncOutput2:
+ handleAsyncOutput2(cookie.value<GdbMi>());
+ break;
+ case GdbInfoShared:
+ handleInfoShared(record);
+ break;
+ case GdbInitializeSocket1:
+ //qDebug() << " INIT SOCKET" << record.toString();
+ break;
+ case GdbQueryDataDumper1:
+ handleQueryDataDumper1(record);
+ break;
+ case GdbQueryDataDumper2:
+ handleQueryDataDumper2(record);
+ break;
+
+ case BreakList:
+ handleBreakList(record);
+ break;
+ case BreakInsert:
+ handleBreakInsert(record, cookie.toInt());
+ break;
+ case BreakInsert1:
+ handleBreakInsert1(record, cookie.toInt());
+ break;
+ case BreakInfo:
+ handleBreakInfo(record, cookie.toInt());
+ break;
+ case BreakEnablePending:
+ case BreakDelete:
+ // nothing
+ break;
+ case BreakIgnore:
+ handleBreakIgnore(record, cookie.toInt());
+ break;
+ case BreakCondition:
+ handleBreakCondition(record, cookie.toInt());
+ break;
+
+ case DisassemblerList:
+ handleDisassemblerList(record, cookie.toString());
+ break;
+
+ case ModulesList:
+ handleModulesList(record);
+ break;
+
+ case RegisterListNames:
+ handleRegisterListNames(record);
+ break;
+ case RegisterListValues:
+ handleRegisterListValues(record);
+ break;
+
+ case StackListFrames:
+ handleStackListFrames(record);
+ break;
+ case StackListThreads:
+ handleStackListThreads(record, cookie.toInt());
+ break;
+ case StackSelectThread:
+ handleStackSelectThread(record, cookie.toInt());
+ break;
+ case StackListLocals:
+ handleStackListLocals(record);
+ break;
+ case StackListArguments:
+ handleStackListArguments(record);
+ break;
+
+ case WatchVarListChildren:
+ handleVarListChildren(record, cookie.value<WatchData>());
+ break;
+ case WatchVarCreate:
+ handleVarCreate(record, cookie.value<WatchData>());
+ break;
+ case WatchVarAssign:
+ handleVarAssign();
+ break;
+ case WatchEvaluateExpression:
+ handleEvaluateExpression(record, cookie.value<WatchData>());
+ break;
+ case WatchToolTip:
+ handleToolTip(record, cookie.toString());
+ break;
+ case WatchDumpCustomValue1:
+ handleDumpCustomValue1(record, cookie.value<WatchData>());
+ break;
+ case WatchDumpCustomValue2:
+ handleDumpCustomValue2(record, cookie.value<WatchData>());
+ break;
+ case WatchDumpCustomSetup:
+ handleDumpCustomSetup(record);
+ break;
+
+ default:
+ qDebug() << "FIXME: GdbEngine::handleResult: "
+ "should not happen" << type;
+ break;
+ }
+}
+
+void GdbEngine::executeDebuggerCommand(const QString &command)
+{
+ //createGdbProcessIfNeeded();
+ if (m_gdbProc.state() == QProcess::NotRunning) {
+ qDebug() << "NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: " << command;
+ return;
+ }
+
+ GdbCookie cmd;
+ cmd.command = command;
+ cmd.type = -1;
+
+ //m_cookieForToken[currentToken()] = cmd;
+ //++currentToken();
+
+ //qDebug() << "";
+ //qDebug() << currentTime() << "Running command: " << cmd.command;
+ emit gdbInputAvailable(QString(), cmd.command);
+ m_gdbProc.write(cmd.command.toLatin1() + "\r\n");
+}
+
+void GdbEngine::handleQueryPwd(const GdbResultRecord &record)
+{
+ // FIXME: remove this special case as soon as 'pwd'
+ // is supported by MI
+ //qDebug() << "PWD OUTPUT:" << record.toString();
+ // Gdb responses _unless_ we get an error first.
+ if (record.resultClass == GdbResultDone) {
+#ifdef Q_OS_LINUX
+ // "5^done,{logstreamoutput="pwd ",consolestreamoutput
+ // ="Working directory /home/apoenitz/dev/work/test1. "}
+ m_pwd = record.data.findChild("consolestreamoutput").data();
+ int pos = m_pwd.indexOf("Working directory");
+ m_pwd = m_pwd.mid(pos + 18);
+ m_pwd = m_pwd.trimmed();
+ if (m_pwd.endsWith('.'))
+ m_pwd.chop(1);
+#endif
+#ifdef Q_OS_WIN
+ // ~"Working directory C:\\Users\\Thomas\\Documents\\WBTest3\\debug.\n"
+ m_pwd = record.data.findChild("consolestreamoutput").data();
+ m_pwd = m_pwd.trimmed();
+#endif
+ //qDebug() << "PWD RESULT:" << m_pwd;
+ }
+}
+
+void GdbEngine::handleQuerySources(const GdbResultRecord &record)
+{
+ if (record.resultClass == GdbResultDone) {
+ m_shortToFullName.clear();
+ m_fullToShortName.clear();
+ // "^done,files=[{file="../../../../bin/gdbmacros/gdbmacros.cpp",
+ // fullname="/data5/dev/ide/main/bin/gdbmacros/gdbmacros.cpp"},
+ GdbMi files = record.data.findChild("files");
+ foreach (const GdbMi &item, files.children()) {
+ QString fileName = item.findChild("file").data();
+ GdbMi fullName = item.findChild("fullname");
+ QString full = fullName.data();
+ #ifdef Q_OS_WIN
+ full = QDir::cleanPath(full);
+ #endif
+ if (fullName.isValid() && QFileInfo(full).isReadable()) {
+ //qDebug() << "STORING 2: " << fileName << full;
+ m_shortToFullName[fileName] = full;
+ m_fullToShortName[full] = fileName;
+ }
+ }
+ }
+}
+
+void GdbEngine::handleInfoProc(const GdbResultRecord &record)
+{
+ if (record.resultClass == GdbResultDone) {
+ #if defined(Q_OS_MAC)
+ //^done,process-id="85075"
+ maybeHandleInferiorPidChanged(record.data.findChild("process-id").data());
+ #endif
+
+ #if defined(Q_OS_LINUX) || defined(Q_OS_WIN)
+ // FIXME: use something more robust
+ QRegExp re(QLatin1String("process (\\d+)"));
+ QString data = record.data.findChild("consolestreamoutput").data();
+ if (re.indexIn(data) != -1)
+ maybeHandleInferiorPidChanged(re.cap(1));
+ #endif
+ }
+}
+
+void GdbEngine::handleInfoShared(const GdbResultRecord &record)
+{
+ if (record.resultClass == GdbResultDone) {
+ // let the modules handler do the parsing
+ handleModulesList(record);
+ QList<Module> modules = qq->modulesHandler()->modules();
+ bool reloadNeeded = false;
+ foreach (const Module &module, modules) {
+ // FIXME: read this from some list
+ if (!module.symbolsRead && !module.moduleName.contains("Q")) {
+ reloadNeeded = true;
+ sendCommand("sharedlibrary " + dotEscape(module.moduleName));
+ }
+ }
+ if (reloadNeeded)
+ reloadModules();
+ continueInferior();
+ }
+}
+
+void GdbEngine::handleQuerySources2(const GdbResultRecord &record,
+ const QVariant &cookie)
+{
+ if (record.resultClass == GdbResultDone)
+ handleAsyncOutput2(cookie.value<GdbMi>());
+}
+
+void GdbEngine::handleExecJumpToLine(const GdbResultRecord &record)
+{
+ // FIXME: remove this special case as soon as 'jump'
+ // is supported by MI
+ // "&"jump /home/apoenitz/dev/work/test1/test1.cpp:242"
+ // ~"Continuing at 0x4058f3."
+ // ~"run1 (argc=1, argv=0x7fffb213a478) at test1.cpp:242"
+ // ~"242\t x *= 2;"
+ //109^done"
+ qq->notifyInferiorStopped();
+ q->showStatusMessage(tr("Jumped. Stopped."), -1);
+ QString output = record.data.findChild("logstreamoutput").data();
+ if (!output.isEmpty())
+ return;
+ QString fileAndLine = output.section(' ', 1, 1);
+ QString file = fileAndLine.section(':', 0, 0);
+ int line = fileAndLine.section(':', 1, 1).toInt();
+ q->gotoLocation(file, line, true);
+}
+
+void GdbEngine::handleExecRunToFunction(const GdbResultRecord &record)
+{
+ // FIXME: remove this special case as soon as there's a real
+ // reason given when the temporary breakpoint is hit.
+ // reight now we get:
+ // 14*stopped,thread-id="1",frame={addr="0x0000000000403ce4",
+ // func="foo",args=[{name="str",value="@0x7fff0f450460"}],
+ // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
+ qq->notifyInferiorStopped();
+ q->showStatusMessage(tr("Run to Function finished. Stopped."), -1);
+ GdbMi frame = record.data.findChild("frame");
+ QString file = frame.findChild("fullname").data();
+ int line = frame.findChild("line").data().toInt();
+ qDebug() << "HIT: " << file << line << " IN " << frame.toString()
+ << " -- " << record.toString();
+ q->gotoLocation(file, line, true);
+}
+
+void GdbEngine::handleStreamOutput(const QString &data, char code)
+{
+ // Linux
+ if (data.contains("[New Thread")) {
+ QRegExp re("\\[New Thread 0x([0-9a-f]*) \\(LWP ([0-9]*)\\)\\]");
+ if (re.indexIn(data) != -1)
+ maybeHandleInferiorPidChanged(re.cap(2));
+ }
+
+ // Mac
+ if (data.contains("[Switching to process ")) {
+ QRegExp re("\\[Switching to process ([0-9]*) local thread 0x([0-9a-f]*)\\]");
+ if (re.indexIn(data) != -1)
+ maybeHandleInferiorPidChanged(re.cap(1));
+ }
+
+ // present it twice: now and together with the next 'real' result
+ switch (code) {
+ case '~':
+ m_pendingConsoleStreamOutput += data;
+ break;
+ case '@':
+ m_pendingTargetStreamOutput += data;
+ break;
+ case '&':
+ m_pendingLogStreamOutput += data;
+ // On Windows, the contents seem to depend on the debugger
+ // version and/or OS version used.
+ if (data.startsWith("warning:"))
+ qq->showApplicationOutput(QString(), data);
+ break;
+ }
+
+#ifdef Q_OS_LINUX
+ if (data.startsWith("Pending break") && data.contains("\" resolved")) {
+ qDebug() << "SCHEDULING -break-list";
+ //m_breakListOnStopNeeded = true;
+ }
+#endif
+
+#if 0
+ if (m_slurpingPTypeOutput)
+ qDebug() << "SLURP: " << output.data;
+
+ // "No symbol \"__dlopen\" in current context."
+ // "No symbol \"dlopen\" in current context."
+ if (output.data.startsWith("No symbol ")
+ && output.data.contains("dlopen")) {
+ m_dlopened = true;
+ return;
+ }
+
+ // output of 'ptype <foo>'
+ if (output.data.startsWith("type = ")) {
+ if (output.data.endsWith("{") || output.data.endsWith("{\\n")) {
+ // multi-line output started here...
+ m_slurpingPTypeOutput = true;
+ m_slurpedPTypeOutput = output.data;
+ } else {
+ // Happens for simple types. Process it immediately
+ m_watchHandler->handleTypeContents(output.data);
+ }
+ return;
+ }
+ if (m_slurpingPTypeOutput) {
+ m_slurpedPTypeOutput += '\n';
+ m_slurpedPTypeOutput += output.data;
+ if (output.data.startsWith("}")) {
+ // this is the last line...
+ m_slurpingPTypeOutput = false;
+ m_watchHandler->handleTypeContents(m_slurpedPTypeOutput);
+ m_slurpedPTypeOutput.clear();
+ }
+ return;
+ }
+#endif
+}
+
+static bool isExitedReason(const QString &reason)
+{
+ return reason == QLatin1String("exited-normally") // inferior exited normally
+ || reason == QLatin1String("exited-signalled") // inferior exited because of a signal
+ //|| reason == QLatin1String("signal-received") // inferior received signal
+ || reason == QLatin1String("exited"); // inferior exited
+}
+
+static bool isStoppedReason(const QString &reason)
+{
+ return reason == QLatin1String("function-finished") // -exec-finish
+ || reason == QLatin1String("signal-received") // handled as "isExitedReason"
+ || reason == QLatin1String("breakpoint-hit") // -exec-continue
+ || reason == QLatin1String("end-stepping-range") // -exec-next, -exec-step
+ || reason == QLatin1String("location-reached") // -exec-until
+ || reason == QLatin1String("access-watchpoint-trigger")
+ || reason == QLatin1String("read-watchpoint-trigger")
+#ifdef Q_OS_MAC
+ || reason.isEmpty()
+#endif
+ ;
+}
+
+void GdbEngine::handleAsyncOutput(const GdbMi &data)
+{
+ const QString reason = data.findChild("reason").data();
+
+ QString console = data.findChild("consolestreamoutput").data();
+ if (console.contains("Stopped due to shared library event") || reason.isEmpty()) {
+ ++m_shared;
+ //if (m_shared == 2)
+ // tryLoadCustomDumpers();
+ //qDebug() << "SHARED LIBRARY EVENT " << data.toString() << m_shared;
+ if (qq->useFastStart()) {
+ if (1 || m_shared <= 16) { // libpthread?
+ sendCommand("info shared", GdbInfoShared);
+ //sendCommand("sharedlibrary gdbdebugger ");
+ //continueInferior();
+ } else {
+ // auto-load from now on
+ sendCommand("info shared");
+ sendCommand("set auto-solib-add on");
+ sendCommand("-file-list-exec-source-files", GdbQuerySources);
+ sendCommand("-break-list", BreakList);
+ //sendCommand("bt");
+ //QVariant var = QVariant::fromValue<GdbMi>(data);
+ //sendCommand("p 1", GdbAsyncOutput2, var); // dummy
+ continueInferior();
+ }
+ } else {
+ // slow start requested.
+ q->showStatusMessage("Loading " + data.toString(), -1);
+ continueInferior();
+ }
+ return;
+ }
+
+ if (isExitedReason(reason)) {
+ qq->notifyInferiorExited();
+ QString msg = "Program exited normally";
+ if (reason == "exited") {
+ msg = "Program exited with exit code "
+ + data.findChild("exit-code").toString();
+ } else if (reason == "exited-signalled") {
+ msg = "Program exited after receiving signal "
+ + data.findChild("signal-name").toString();
+ } else if (reason == "signal-received") {
+ msg = "Program exited after receiving signal "
+ + data.findChild("signal-name").toString();
+ }
+ q->showStatusMessage(msg, -1);
+ q->exitDebugger();
+ return;
+ }
+
+ tryLoadCustomDumpers();
+
+ // jump over well-known frames
+ static int stepCounter = 0;
+ if (qq->skipKnownFrames()) {
+ if (reason == "end-stepping-range" || reason == "function-finished") {
+ GdbMi frame = data.findChild("frame");
+ //qDebug() << frame.toString();
+ m_currentFrame = frame.findChild("addr").data() + '%' +
+ frame.findChild("func").data() + '%';
+
+ QString funcName = frame.findChild("func").data();
+ QString fileName = frame.findChild("file").data();
+ if (isLeavableFunction(funcName, fileName)) {
+ //qDebug() << "LEAVING" << funcName;
+ ++stepCounter;
+ q->stepOutExec();
+ //stepExec();
+ return;
+ }
+ if (isSkippableFunction(funcName, fileName)) {
+ //qDebug() << "SKIPPING" << funcName;
+ ++stepCounter;
+ q->stepExec();
+ return;
+ }
+ //if (stepCounter)
+ // qDebug() << "STEPCOUNTER:" << stepCounter;
+ stepCounter = 0;
+ }
+ }
+
+ if (isStoppedReason(reason) || reason.isEmpty()) {
+ // Need another round trip
+ if (reason == "breakpoint-hit") {
+ GdbMi frame = data.findChild("frame");
+ //qDebug() << frame.toString();
+ m_currentFrame = frame.findChild("addr").data() + '%' +
+ frame.findChild("func").data() + '%';
+
+ QApplication::alert(q->mainWindow(), 200);
+ sendCommand("-file-list-exec-source-files", GdbQuerySources);
+ sendCommand("-break-list", BreakList);
+ QVariant var = QVariant::fromValue<GdbMi>(data);
+ sendCommand("p 0", GdbAsyncOutput2, var); // dummy
+ } else {
+ handleAsyncOutput2(data);
+ }
+ return;
+ }
+
+ qDebug() << "STOPPED FOR UNKNOWN REASON" << data.toString();
+ // Ignore it. Will be handled with full response later in the
+ // JumpToLine or RunToFunction handlers
+#if 1
+ // FIXME: remove this special case as soon as there's a real
+ // reason given when the temporary breakpoint is hit.
+ // reight now we get:
+ // 14*stopped,thread-id="1",frame={addr="0x0000000000403ce4",
+ // func="foo",args=[{name="str",value="@0x7fff0f450460"}],
+ // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
+ //
+ // MAC yields sometimes:
+ // stdout:3661*stopped,time={wallclock="0.00658",user="0.00142",
+ // system="0.00136",start="1218810678.805432",end="1218810678.812011"}
+ q->resetLocation();
+ qq->notifyInferiorStopped();
+ q->showStatusMessage(tr("Run to Function finished. Stopped."), -1);
+ GdbMi frame = data.findChild("frame");
+ QString file = frame.findChild("fullname").data();
+ int line = frame.findChild("line").data().toInt();
+ qDebug() << "HIT: " << file << line << " IN " << frame.toString()
+ << " -- " << data.toString();
+ q->gotoLocation(file, line, true);
+#endif
+}
+
+
+void GdbEngine::handleAsyncOutput2(const GdbMi &data)
+{
+ qq->notifyInferiorStopped();
+
+ //
+ // Breakpoints
+ //
+ //qDebug() << "BREAK ASYNC: " << output.toString();
+ //sendListBreakpoints();
+ //attemptBreakpointSynchronization();
+ //if (m_breakListOnStopNeeded)
+ // sendListBreakpoints();
+
+ // something reasonably 'invariant'
+ // Linux:
+ //"79*stopped,reason="end-stepping-range",reason="breakpoint-hit",bkptno="1",
+ //thread-id="1",frame={addr="0x0000000000405d8f",func="run1",
+ //args=[{name="argc",value="1"},{name="argv",value="0x7fffb7c23058"}],
+ //file="test1.cpp",fullname="/home/apoenitz/dev/work/test1/test1.cpp"
+ //,line="261"}"
+ // Mac: (but only sometimes)
+ // "82*stopped,bkpt={number="0",type="step
+ // resume",disp="keep",enabled="y",addr="0x43127171",at="<Find::
+ // Internal::FindToolWindow::invokeFindIncremental()
+ // +225>",thread="1",shlib="/Users/epreuss/dev/ide/main/bin/
+ // workbench.app/Contents/PlugIns/Trolltech/libFind.1.0.0.dylib",
+ // frame="0xbfffd800",thread="1",times="1"},
+
+ //
+ // Stack
+ //
+ qq->stackHandler()->setCurrentIndex(0);
+ updateLocals(); // Quick shot
+
+ int currentId = data.findChild("thread-id").data().toInt();
+ sendSynchronizedCommand("-stack-list-frames", StackListFrames);
+ if (supportsThreads())
+ sendSynchronizedCommand("-thread-list-ids", StackListThreads, currentId);
+
+ //
+ // Disassembler
+ //
+ // Linux:
+ //"79*stopped,reason="end-stepping-range",reason="breakpoint-hit",bkptno="1",
+ //thread-id="1",frame={addr="0x0000000000405d8f",func="run1",
+ //args=[{name="argc",value="1"},{name="argv",value="0x7fffb7c23058"}],
+ //file="test1.cpp",fullname="/home/apoenitz/dev/work/test1/test1.cpp",line="261"}"
+ // Mac: (but only sometimes)
+ m_address = data.findChild("frame").findChild("addr").data();
+ qq->reloadDisassembler();
+
+ //
+ // Registers
+ //
+ qq->reloadRegisters();
+}
+
+void GdbEngine::handleShowVersion(const GdbResultRecord &response)
+{
+ if (response.resultClass == GdbResultDone) {
+ m_gdbVersion = 100;
+ QString msg = response.data.findChild("consolestreamoutput").data();
+ QRegExp supported("GNU gdb 6.[6789]");
+ if (msg.indexOf(supported) == -1) {
+ QStringList list = msg.split("\n");
+ while (list.size() > 2)
+ list.removeLast();
+ msg = tr("The debugger you are using identifies itself as:")
+ + "<p><p>" + list.join("<br>") + "<p><p>"
+ + tr("This version is not officially supported by Qt Creator.\n"
+ "Debugging will most likely not work well.\n"
+ "Using gdb 6.7 or later is strongly recommended.");
+#if 0
+ // ugly, but 'Show again' check box...
+ static QErrorMessage *err = new QErrorMessage(m_mainWindow);
+ err->setMinimumSize(400, 300);
+ err->showMessage(msg);
+#else
+ //QMessageBox::information(m_mainWindow, tr("Warning"), msg);
+#endif
+ }
+ int pos = msg.indexOf("GNU gdb 6.");
+ if (pos != -1) {
+ m_gdbVersion = 600 + (msg.at(pos + 10).unicode() - '0') * 10;
+ //qDebug() << "GDB VERSION " << m_gdbVersion << msg;
+ }
+ }
+}
+
+void GdbEngine::handleFileExecAndSymbols
+ (const GdbResultRecord &response)
+{
+ if (response.resultClass == GdbResultDone) {
+ //m_breakHandler->clearBreakMarkers();
+ } else if (response.resultClass == GdbResultError) {
+ QString msg = response.data.findChild("msg").data();
+ QMessageBox::critical(q->mainWindow(), tr("Error"),
+ tr("Starting executable failed:\n") + msg);
+ QWB_ASSERT(q->status() == DebuggerInferiorRunning, /**/);
+ interruptInferior();
+ }
+}
+
+void GdbEngine::handleExecRun(const GdbResultRecord &response)
+{
+ if (response.resultClass == GdbResultRunning) {
+ qq->notifyInferiorRunning();
+ q->showStatusMessage(tr("Running..."), -1);
+ //reloadModules();
+ } else if (response.resultClass == GdbResultError) {
+ QString msg = response.data.findChild("msg").data();
+ if (msg == "Cannot find bounds of current function") {
+ qq->notifyInferiorStopped();
+ //q->showStatusMessage(tr("No debug information available. "
+ // "Leaving function..."), -1);
+ //stepOutExec();
+ } else {
+ QMessageBox::critical(q->mainWindow(), tr("Error"),
+ tr("Starting executable failed:\n") + msg);
+ QWB_ASSERT(q->status() == DebuggerInferiorRunning, /**/);
+ interruptInferior();
+ }
+ }
+}
+
+void GdbEngine::queryFullName(const QString &fileName, QString *full)
+{
+ *full = fullName(fileName);
+}
+
+QString GdbEngine::shortName(const QString &fullName)
+{
+ return m_fullToShortName.value(fullName, QString());
+}
+
+QString GdbEngine::fullName(const QString &fileName)
+{
+ //QString absName = m_manager->currentWorkingDirectory() + "/" + file; ??
+ if (fileName.isEmpty())
+ return QString();
+ QString full = m_shortToFullName.value(fileName, QString());
+ //qDebug() << "RESOLVING: " << fileName << full;
+ if (!full.isEmpty())
+ return full;
+ QFileInfo fi(fileName);
+ if (!fi.isReadable())
+ return QString();
+ full = fi.absoluteFilePath();
+ #ifdef Q_OS_WIN
+ full = QDir::cleanPath(full);
+ #endif
+ //qDebug() << "STORING: " << fileName << full;
+ m_shortToFullName[fileName] = full;
+ m_fullToShortName[full] = fileName;
+ return full;
+}
+
+QString GdbEngine::fullName(const QStringList &candidates)
+{
+ QString full;
+ foreach (const QString &fileName, candidates) {
+ full = fullName(fileName);
+ if (!full.isEmpty())
+ return full;
+ }
+ foreach (const QString &fileName, candidates) {
+ if (!fileName.isEmpty())
+ return fileName;
+ }
+ return full;
+}
+
+void GdbEngine::shutdown()
+{
+ exitDebugger();
+}
+
+void GdbEngine::exitDebugger()
+{
+ //qDebug() << "EXITING: " << m_gdbProc.state();
+ if (m_gdbProc.state() == QProcess::Starting)
+ m_gdbProc.waitForStarted();
+ if (m_gdbProc.state() == QProcess::Running) {
+ interruptInferior();
+ sendCommand("kill");
+ sendCommand("-gdb-exit");
+ // 20s can easily happen when loading webkit debug information
+ m_gdbProc.waitForFinished(20000);
+ if (m_gdbProc.state() != QProcess::Running) {
+ m_gdbProc.terminate();
+ m_gdbProc.waitForFinished(20000);
+ }
+ }
+ if (m_gdbProc.state() != QProcess::NotRunning)
+ qDebug() << "PROBLEM STOPPING DEBUGGER";
+
+ m_shortToFullName.clear();
+ m_fullToShortName.clear();
+ m_varToType.clear();
+ m_dataDumperState = DataDumperUninitialized;
+ m_shared = 0;
+ qq->debugDumpersAction()->setChecked(false);
+}
+
+
+int GdbEngine::currentFrame() const
+{
+ return qq->stackHandler()->currentIndex();
+}
+
+
+bool GdbEngine::startDebugger()
+{
+ m_inferiorPid = 0;
+ QStringList gdbArgs;
+
+ QFileInfo fi(q->m_executable);
+ QString fileName = '"' + fi.absoluteFilePath() + '"';
+
+ if (m_gdbProc.state() != QProcess::NotRunning) {
+ qDebug() << "GDB IS ALREADY RUNNING!";
+ return false;
+ }
+
+ //gdbArgs.prepend(QLatin1String("--quiet"));
+ gdbArgs.prepend(QLatin1String("mi"));
+ gdbArgs.prepend(QLatin1String("-i"));
+
+ if (!q->m_workingDir.isEmpty())
+ m_gdbProc.setWorkingDirectory(q->m_workingDir);
+ if (!q->m_environment.isEmpty())
+ m_gdbProc.setEnvironment(q->m_environment);
+
+ #if 0
+ qDebug() << "Command: " << theGdbSettings().m_gdbCmd;
+ qDebug() << "WorkingDirectory: " << m_gdbProc.workingDirectory();
+ qDebug() << "Environment: " << m_gdbProc.environment();
+ qDebug() << "Arguments: " << gdbArgs;
+ qDebug() << "BuildDir: " << q->m_buildDir;
+ qDebug() << "ExeFile: " << q->m_executable;
+ #endif
+
+ q->showStatusMessage("Starting Debugger", -1);
+ emit gdbInputAvailable(QString(), theGdbSettings().m_gdbCmd + ' ' + gdbArgs.join(" "));
+
+ m_gdbProc.start(theGdbSettings().m_gdbCmd, gdbArgs);
+ m_gdbProc.waitForStarted();
+
+ if (m_gdbProc.state() != QProcess::Running)
+ return false;
+
+ q->showStatusMessage(tr("Gdb Running"), -1);
+
+ sendCommand("show version", GdbShowVersion);
+ if (qq->useFastStart()) {
+ sendCommand("set auto-solib-add off");
+ sendCommand("set stop-on-solib-events 1");
+ }
+ //sendCommand("-enable-timings");
+ //sendCommand("set stop-on-solib-events 1");
+ sendCommand("set print static-members off"); // Seemingly doesn't work.
+ //sendCommand("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend");
+ //sendCommand("define hook-stop\nprint 4\nend");
+ //sendCommand("define hookpost-stop\nprint 5\nend");
+ //sendCommand("define hook-call\nprint 6\nend");
+ //sendCommand("define hookpost-call\nprint 7\nend");
+ //sendCommand("set print object on"); // works with CLI, but not MI
+ //sendCommand("set step-mode on"); // we can't work with that yes
+ //sendCommand("set exec-done-display on");
+ //sendCommand("set print pretty on");
+ //sendCommand("set confirm off");
+ //sendCommand("set pagination off");
+ sendCommand("set breakpoint pending on", BreakEnablePending);
+
+ // one of the following is needed to prevent crashes in gdb on code like:
+ // template <class T> T foo() { return T(0); }
+ // int main() { return foo<int>(); }
+ // (gdb) call 'int foo<int>'()
+ // /build/buildd/gdb-6.8/gdb/valops.c:2069: internal-error:
+ sendCommand("set overload-resolution off");
+ //sendCommand("set demangle-style none");
+
+ // From the docs:
+ // Stop means reenter debugger if this signal happens (implies print).
+ // Print means print a message if this signal happens.
+ // Pass means let program see this signal;
+ // otherwise program doesn't know.
+ // Pass and Stop may be combined.
+ // We need "print" as otherwise we would get no feedback whatsoever
+ // Custom Dumper crashs which happen regularily for when accessing
+ // uninitialized variables.
+ sendCommand("handle SIGSEGV nopass stop print");
+
+ // This is useful to kill the inferior whenever gdb dies.
+ //sendCommand("handle SIGTERM pass nostop print");
+
+ sendCommand("set unwindonsignal on");
+ sendCommand("pwd", GdbQueryPwd);
+
+ #ifdef Q_OS_MAC
+ sendCommand("-gdb-set inferior-auto-start-cfm off");
+ sendCommand("-gdb-set sharedLibrary load-rules "
+ "dyld \".*libSystem.*\" "
+ "all dyld \".*libauto.*\" "
+ "all dyld \".*AppKit.*\" "
+ "all dyld \".*PBGDBIntrospectionSupport.*\" "
+ "all dyld \".*Foundation.*\" "
+ "all dyld \".*CFDataFormatters.*\" "
+ "all dyld \".*libobjc.*\" "
+ "all dyld \".*CarbonDataFormatters");
+ #endif
+
+ if (q->startMode() == q->attachExternal) {
+ sendCommand("attach " + QString::number(q->m_attachedPID));
+ }
+
+ if (q->startMode() == q->startInternal) {
+ sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols);
+ #ifdef Q_OS_MAC
+ sendCommand("sharedlibrary apply-load-rules all");
+ #endif
+ sendCommand("-file-list-exec-source-files", GdbQuerySources);
+ //sendCommand("-gdb-set stop-on-solib-events 1");
+ }
+
+ sendCommand("-data-list-register-names", RegisterListNames);
+
+ // set all to "pending"
+ if (q->startMode() == q->attachExternal)
+ qq->breakHandler()->removeAllBreakpoints();
+ else
+ qq->breakHandler()->setAllPending();
+
+ QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization()));
+
+ return true;
+}
+
+void GdbEngine::continueInferior()
+{
+ q->resetLocation();
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ emit gdbInputAvailable(QString(), QString());
+ sendCommand("-exec-continue", GdbExecContinue);
+}
+
+void GdbEngine::runInferior()
+{
+ q->resetLocation();
+ // FIXME: this ignores important startup messages
+ setTokenBarrier();
+ if (!q->m_processArgs.isEmpty())
+ sendCommand("-exec-arguments " + q->m_processArgs.join(" "));
+ qq->notifyInferiorRunningRequested();
+ emit gdbInputAvailable(QString(), QString());
+ sendCommand("-exec-run", GdbExecRun);
+#if defined(Q_OS_WIN)
+ sendCommand("info proc", GdbInfoProc);
+#endif
+#if defined(Q_OS_LINUX)
+ sendCommand("info proc", GdbInfoProc);
+#endif
+#if defined(Q_OS_MAC)
+ sendCommand("info pid", GdbInfoProc, QVariant(), true);
+#endif
+}
+
+void GdbEngine::stepExec()
+{
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ emit gdbInputAvailable(QString(), QString());
+ sendCommand("-exec-step", GdbExecStep);
+}
+
+void GdbEngine::stepIExec()
+{
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ sendCommand("-exec-step-instruction", GdbExecStepI);
+}
+
+void GdbEngine::stepOutExec()
+{
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ sendCommand("-exec-finish", GdbExecFinish);
+}
+
+void GdbEngine::nextExec()
+{
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ emit gdbInputAvailable(QString(), QString());
+ sendCommand("-exec-next", GdbExecNext);
+}
+
+void GdbEngine::nextIExec()
+{
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ sendCommand("-exec-next-instruction", GdbExecNextI);
+}
+
+void GdbEngine::runToLineExec(const QString &fileName, int lineNumber)
+{
+ setTokenBarrier();
+ qq->notifyInferiorRunningRequested();
+ sendCommand("-exec-until " + fileName + ":" + QString::number(lineNumber));
+}
+
+void GdbEngine::runToFunctionExec(const QString &functionName)
+{
+ setTokenBarrier();
+ sendCommand("-break-insert -t " + functionName);
+ qq->notifyInferiorRunningRequested();
+ sendCommand("-exec-continue", GdbExecRunToFunction);
+}
+
+void GdbEngine::jumpToLineExec(const QString &fileName, int lineNumber)
+{
+#if 1
+ // not available everywhere?
+ //sendCliCommand("tbreak " + fileName + ":" + QString::number(lineNumber));
+ sendCommand("-break-insert -t " + fileName + ":" + QString::number(lineNumber));
+ sendCommand("jump " + fileName + ":" + QString::number(lineNumber));
+ // will produce something like
+ // &"jump /home/apoenitz/dev/work/test1/test1.cpp:242"
+ // ~"Continuing at 0x4058f3."
+ // ~"run1 (argc=1, argv=0x7fffbf1f5538) at test1.cpp:242"
+ // ~"242\t x *= 2;"
+ // 23^done"
+ q->gotoLocation(fileName, lineNumber, true);
+ //setBreakpoint();
+ //sendCommand("jump " + fileName + ":" + QString::number(lineNumber));
+#else
+ q->gotoLocation(fileName, lineNumber, true);
+ setBreakpoint(fileName, lineNumber);
+ sendCommand("jump " + fileName + ":" + QString::number(lineNumber));
+#endif
+}
+
+/*!
+ \fn void GdbEngine::setTokenBarrier()
+ \brief Sets up internal structures to handle a new debugger turn.
+
+ This method is called at the beginnign of all step/next/finish etc.
+ debugger functions.
+*/
+
+void GdbEngine::setTokenBarrier()
+{
+ m_oldestAcceptableToken = currentToken();
+}
+
+void GdbEngine::setDebugDumpers(bool on)
+{
+ if (on) {
+ qDebug() << "SWITCHING ON DUMPER DEBUGGING";
+ sendCommand("set unwindonsignal off");
+ q->breakByFunction("qDumpObjectData440");
+ //updateLocals();
+ } else {
+ qDebug() << "SWITCHING OFF DUMPER DEBUGGING";
+ sendCommand("set unwindonsignal on");
+ }
+}
+
+//QByteArray GdbEngine::dumperChannel() const
+//{
+// return m_dumperServer->serverName().toLatin1();
+// //QByteArray ba;
+// //ba.setNum(m_dumperServer->serverPort());
+// //return ba;
+//}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Breakpoint specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt)
+{
+ if (!bkpt.isValid())
+ return;
+ if (!data)
+ return;
+ data->pending = false;
+ data->bpMultiple = false;
+ data->bpCondition.clear();
+ QStringList files;
+ foreach (const GdbMi &child, bkpt.children()) {
+ if (child.hasName("number")) {
+ data->bpNumber = child.data();
+ } else if (child.hasName("func")) {
+ data->bpFuncName = child.data();
+ } else if (child.hasName("addr")) {
+ // <MULTIPLE> happens in constructors. In this case there are
+ // _two_ fields named "addr" in the response. On Linux that is...
+ if (child.data() == "<MULTIPLE>")
+ data->bpMultiple = true;
+ else
+ data->bpAddress = child.data();
+ } else if (child.hasName("file")) {
+ files.append(child.data());
+ } else if (child.hasName("fullname")) {
+ QString fullName = child.data();
+ #ifdef Q_OS_WIN
+ fullName = QDir::cleanPath(fullName);
+ #endif
+ files.prepend(fullName);
+ } else if (child.hasName("line")) {
+ data->bpLineNumber = child.data();
+ if (child.data().toInt())
+ data->markerLineNumber = child.data().toInt();
+ } else if (child.hasName("cond")) {
+ data->bpCondition = child.data();
+ // gdb 6.3 likes to "rewrite" conditions. Just accept that fact.
+ if (data->bpCondition != data->condition && data->conditionsMatch())
+ data->condition = data->bpCondition;
+ }
+ else if (child.hasName("pending")) {
+ data->pending = true;
+ int pos = child.data().lastIndexOf(':');
+ if (pos > 0) {
+ data->bpLineNumber = child.data().mid(pos + 1);
+ data->markerLineNumber = child.data().mid(pos + 1).toInt();
+ files.prepend(child.data().left(pos));
+ } else {
+ files.prepend(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 = fullName(files);
+ if (data->bpFileName.isEmpty())
+ data->bpFileName = name;
+ if (data->markerFileName.isEmpty())
+ data->markerFileName = name;
+}
+
+void GdbEngine::sendInsertBreakpoint(int index)
+{
+ const BreakpointData *data = qq->breakHandler()->at(index);
+ QString where;
+ if (data->funcName.isEmpty()) {
+ where = data->fileName;
+#ifdef Q_OS_MAC
+ // full names do not work on Mac/MI
+ QFileInfo fi(data->fileName);
+ where = fi.fileName();
+ //where = fi.absoluteFilePath();
+#endif
+#ifdef Q_OS_WIN
+ // full names do not work on Mac/MI
+ QFileInfo fi(data->fileName);
+ where = fi.fileName();
+ //where = m_manager->shortName(data->fileName);
+ //if (where.isEmpty())
+ // where = data->fileName;
+#endif
+ // we need something like "\"file name.cpp\":100" to
+ // survive the gdb command line parser with file names intact
+ where = "\"\\\"" + where + "\\\":" + data->lineNumber + "\"";
+ } else {
+ where = data->funcName;
+ }
+
+ // set up fallback in case of pending breakpoints which aren't handled
+ // by the MI interface
+#ifdef Q_OS_LINUX
+ QString cmd = "-break-insert ";
+ //if (!data->condition.isEmpty())
+ // cmd += "-c " + data->condition + " ";
+ cmd += where;
+#endif
+#ifdef Q_OS_MAC
+ QString cmd = "-break-insert -l -1 ";
+ //if (!data->condition.isEmpty())
+ // cmd += "-c " + data->condition + " ";
+ cmd += where;
+#endif
+#ifdef Q_OS_WIN
+ QString cmd = "-break-insert ";
+ //if (!data->condition.isEmpty())
+ // cmd += "-c " + data->condition + " ";
+ cmd += where;
+#endif
+ sendCommand(cmd, BreakInsert, index, true);
+ //processQueueAndContinue();
+}
+
+void GdbEngine::handleBreakList(const GdbResultRecord &record)
+{
+ // 45^done,BreakpointTable={nr_rows="2",nr_cols="6",hdr=[
+ // {width="3",alignment="-1",col_name="number",colhdr="Num"}, ...
+ // body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
+ // addr="0x000000000040109e",func="main",file="app.cpp",
+ // fullname="/home/apoenitz/dev/work/plugintest/app/app.cpp",
+ // line="11",times="1"},
+ // bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
+ // addr="<PENDING>",pending="plugin.cpp:7",times="0"}] ... }
+
+ if (record.resultClass == GdbResultDone) {
+ GdbMi table = record.data.findChild("BreakpointTable");
+ if (table.isValid())
+ handleBreakList(table);
+ }
+}
+
+void GdbEngine::handleBreakList(const GdbMi &table)
+{
+ //qDebug() << "GdbEngine::handleOutput: table: "
+ // << table.toString();
+ GdbMi body = table.findChild("body");
+ //qDebug() << "GdbEngine::handleOutput: body: "
+ // << body.toString();
+ QList<GdbMi> bkpts;
+ if (body.isValid()) {
+ // Non-Mac
+ bkpts = body.children();
+ } else {
+ // Mac
+ bkpts = table.children();
+ // remove the 'hdr' and artificial items
+ //qDebug() << "FOUND " << bkpts.size() << " BREAKPOINTS";
+ for (int i = bkpts.size(); --i >= 0; ) {
+ int num = bkpts.at(i).findChild("number").data().toInt();
+ if (num <= 0) {
+ //qDebug() << "REMOVING " << i << bkpts.at(i).toString();
+ bkpts.removeAt(i);
+ }
+ }
+ //qDebug() << "LEFT " << bkpts.size() << " BREAKPOINTS";
+ }
+
+ BreakHandler *handler = qq->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();
+ }
+
+ attemptBreakpointSynchronization();
+ handler->updateMarkers();
+}
+
+
+void GdbEngine::handleBreakIgnore(const GdbResultRecord &record, int index)
+{
+ // gdb 6.8:
+ // ignore 2 0:
+ // ~"Will stop next time breakpoint 2 is reached.\n"
+ // 28^done
+ // ignore 2 12:
+ // &"ignore 2 12\n"
+ // ~"Will ignore next 12 crossings of breakpoint 2.\n"
+ // 29^done
+ //
+ // gdb 6.3 does not produce any console output
+ BreakHandler *handler = qq->breakHandler();
+ if (record.resultClass == GdbResultDone && index < handler->size()) {
+ QString msg = record.data.findChild("consolestreamoutput").data();
+ BreakpointData *data = handler->at(index);
+ //if (msg.contains("Will stop next time breakpoint")) {
+ // data->bpIgnoreCount = "0";
+ //} else if (msg.contains("Will ignore next")) {
+ // data->bpIgnoreCount = data->ignoreCount;
+ //}
+ // FIXME: this assumes it is doing the right thing...
+ data->bpIgnoreCount = data->ignoreCount;
+ attemptBreakpointSynchronization();
+ handler->updateMarkers();
+ }
+}
+
+void GdbEngine::handleBreakCondition(const GdbResultRecord &record, int index)
+{
+ BreakHandler *handler = qq->breakHandler();
+ if (record.resultClass == GdbResultDone) {
+ // we just assume it was successful. otherwise we had to parse
+ // the output stream data
+ BreakpointData *data = handler->at(index);
+ //qDebug() << "HANDLE BREAK CONDITION " << index << data->condition;
+ data->bpCondition = data->condition;
+ attemptBreakpointSynchronization();
+ handler->updateMarkers();
+ } else if (record.resultClass == GdbResultError) {
+ QString msg = record.data.findChild("msg").data();
+ // happens on Mac
+ if (1 || msg.startsWith("Error parsing breakpoint condition. "
+ " Will try again when we hit the breakpoint.")) {
+ BreakpointData *data = handler->at(index);
+ //qDebug() << "ERROR BREAK CONDITION " << index << data->condition;
+ data->bpCondition = data->condition;
+ attemptBreakpointSynchronization();
+ handler->updateMarkers();
+ }
+ }
+}
+
+void GdbEngine::handleBreakInsert(const GdbResultRecord &record, int index)
+{
+ BreakHandler *handler = qq->breakHandler();
+ if (record.resultClass == GdbResultDone) {
+ //qDebug() << "HANDLE BREAK INSERT " << index;
+//#ifdef Q_OS_MAC
+ // interesting only on Mac?
+ BreakpointData *data = handler->at(index);
+ GdbMi bkpt = record.data.findChild("bkpt");
+ //qDebug() << "BKPT: " << bkpt.toString() << " DATA" << data->toToolTip();
+ breakpointDataFromOutput(data, bkpt);
+//#endif
+ attemptBreakpointSynchronization();
+ handler->updateMarkers();
+ } else if (record.resultClass == GdbResultError) {
+ const BreakpointData *data = handler->at(index);
+#ifdef Q_OS_LINUX
+ //QString where = "\"\\\"" + data->fileName + "\\\":"
+ // + data->lineNumber + "\"";
+ QString where = "\"" + data->fileName + "\":"
+ + data->lineNumber;
+ sendCommand("break " + where, BreakInsert1, index);
+#endif
+#ifdef Q_OS_MAC
+ QFileInfo fi(data->fileName);
+ QString where = "\"" + fi.fileName() + "\":"
+ + data->lineNumber;
+ sendCommand("break " + where, BreakInsert1, index);
+#endif
+#ifdef Q_OS_WIN
+ QFileInfo fi(data->fileName);
+ QString where = "\"" + fi.fileName() + "\":"
+ + data->lineNumber;
+ //QString where = m_data->fileName + QLatin1Char(':') + data->lineNumber;
+ sendCommand("break " + where, BreakInsert1, index);
+#endif
+ }
+}
+
+void GdbEngine::extractDataFromInfoBreak(const QString &output, BreakpointData *data)
+{
+ data->bpFileName = "<MULTIPLE>";
+
+ //qDebug() << output;
+ if (output.isEmpty())
+ return;
+ // "Num Type Disp Enb Address What
+ // 4 breakpoint keep y <MULTIPLE> 0x00000000004066ad
+ // 4.1 y 0x00000000004066ad in CTorTester
+ // at /data5/dev/ide/main/tests/manual/gdbdebugger/simple/app.cpp:124
+ // - or -
+ // everything on a single line on Windows for constructors of classes
+ // within namespaces.
+ // Sometimes the path is relative too.
+
+ QRegExp re("MULTIPLE.*(0x[0-9a-f]+) in (.*)\\s+at (.*):([\\d]+)([^\\d]|$)");
+ re.setMinimal(true);
+
+ if (re.indexIn(output) != -1) {
+ data->bpAddress = re.cap(1);
+ data->bpFuncName = re.cap(2).trimmed();
+ data->bpLineNumber = re.cap(4);
+ QString full = fullName(re.cap(3));
+ data->markerLineNumber = data->bpLineNumber.toInt();
+ data->markerFileName = full;
+ data->bpFileName = full;
+ //qDebug() << "FOUND BREAKPOINT\n" << output
+ // << re.cap(1) << "\n" << re.cap(2) << "\n"
+ // << re.cap(3) << "\n" << re.cap(4) << "\n";
+ } else {
+ qDebug() << "COULD NOT MATCH " << re.pattern() << " AND " << output;
+ data->bpNumber = "<unavailable>";
+ }
+}
+
+void GdbEngine::handleBreakInfo(const GdbResultRecord &record, int bpNumber)
+{
+ BreakHandler *handler = qq->breakHandler();
+ if (record.resultClass == GdbResultDone) {
+ // Old-style output for multiple breakpoints, presumably in a
+ // constructor
+ int found = handler->findBreakpoint(bpNumber);
+ if (found != -1) {
+ QString str = record.data.findChild("consolestreamoutput").data();
+ extractDataFromInfoBreak(str, handler->at(found));
+ handler->updateMarkers();
+ attemptBreakpointSynchronization(); // trigger "ready"
+ }
+ }
+}
+
+void GdbEngine::handleBreakInsert1(const GdbResultRecord &record, int index)
+{
+ BreakHandler *handler = qq->breakHandler();
+ if (record.resultClass == GdbResultDone) {
+ // Pending breakpoints in dylibs on Mac only?
+ BreakpointData *data = handler->at(index);
+ GdbMi bkpt = record.data.findChild("bkpt");
+ breakpointDataFromOutput(data, bkpt);
+ attemptBreakpointSynchronization(); // trigger "ready"
+ handler->updateMarkers();
+ } else if (record.resultClass == GdbResultError) {
+ qDebug() << "INSERTING BREAKPOINT WITH BASE NAME FAILED. GIVING UP";
+ BreakpointData *data = handler->at(index);
+ data->bpNumber = "<unavailable>";
+ attemptBreakpointSynchronization(); // trigger "ready"
+ handler->updateMarkers();
+ }
+}
+
+void GdbEngine::attemptBreakpointSynchronization()
+{
+ BreakHandler *handler = qq->breakHandler();
+ //qDebug() << "BREAKPOINT SYNCHRONIZATION ";
+
+ foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) {
+ //qDebug() << " SYNCHRONIZATION REMOVING" << data;
+ QString bpNumber = data->bpNumber;
+ if (!bpNumber.trimmed().isEmpty())
+ sendCommand("-break-delete " + bpNumber, BreakDelete, 0, true);
+ //else
+ // qDebug() << "BP HAS NO NUMBER: " << data->markerFileName;
+ delete data;
+ }
+
+ bool updateNeeded = false;
+
+ for (int index = 0; index != handler->size(); ++index) {
+ BreakpointData *data = handler->at(index);
+ // multiple breakpoints?
+ if (data->bpMultiple && data->bpFileName.isEmpty()) {
+ sendCommand(QString("info break %1").arg(data->bpNumber),
+ BreakInfo, data->bpNumber.toInt());
+ updateNeeded = true;
+ break;
+ }
+ }
+
+ for (int index = 0; index != handler->size(); ++index) {
+ BreakpointData *data = handler->at(index);
+ // unset breakpoints?
+ if (data->bpNumber.isEmpty()) {
+ data->bpNumber = " ";
+ sendInsertBreakpoint(index);
+ //qDebug() << "UPDATE NEEDED BECAUSE OF UNKNOWN BREAKPOINT";
+ updateNeeded = true;
+ break;
+ }
+ }
+
+ if (!updateNeeded) {
+ for (int index = 0; index != handler->size(); ++index) {
+ BreakpointData *data = handler->at(index);
+ // update conditions if needed
+ if (data->bpNumber.toInt() && data->condition != data->bpCondition
+ && !data->conditionsMatch()) {
+ sendCommand(QString("condition %1 %2").arg(data->bpNumber)
+ .arg(data->condition), BreakCondition, index);
+ //qDebug() << "UPDATE NEEDED BECAUSE OF CONDITION"
+ // << data->condition << data->bpCondition;
+ updateNeeded = true;
+ break;
+ }
+ // update ignorecount if needed
+ if (data->bpNumber.toInt() && data->ignoreCount != data->bpIgnoreCount) {
+ sendCommand(QString("ignore %1 %2").arg(data->bpNumber)
+ .arg(data->ignoreCount), BreakIgnore, index);
+ updateNeeded = true;
+ break;
+ }
+ }
+ }
+
+ for (int index = 0; index != handler->size(); ++index) {
+ // happens sometimes on Mac. Brush over symptoms
+ BreakpointData *data = handler->at(index);
+ if (data->markerFileName.startsWith("../")) {
+ data->markerFileName = fullName(data->markerFileName);
+ handler->updateMarkers();
+ }
+ }
+
+ if (updateNeeded) {
+ //interruptAndContinue();
+ //sendListBreakpoints();
+ }
+
+ if (!updateNeeded && q->status() == DebuggerProcessStartingUp)
+ qq->notifyStartupFinished();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Disassembler specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void GdbEngine::reloadDisassembler()
+{
+ emit sendCommand("disassemble", DisassemblerList, m_address);
+}
+
+void GdbEngine::handleDisassemblerList(const GdbResultRecord &record,
+ const QString &cookie)
+{
+ QList<DisassemblerLine> lines;
+ static const QString pad = QLatin1String(" ");
+ int currentLine = -1;
+ if (record.resultClass == GdbResultDone) {
+ QString res = record.data.findChild("consolestreamoutput").data();
+ QTextStream ts(&res, QIODevice::ReadOnly);
+ while (!ts.atEnd()) {
+ //0x0000000000405fd8 <_ZN11QTextStreamD1Ev@plt+0>:
+ // jmpq *2151890(%rip) # 0x6135b0 <_GLOBAL_OFFSET_TABLE_+640>
+ //0x0000000000405fde <_ZN11QTextStreamD1Ev@plt+6>:
+ // pushq $0x4d
+ //0x0000000000405fe3 <_ZN11QTextStreamD1Ev@plt+11>:
+ // jmpq 0x405af8 <_init+24>
+ //0x0000000000405fe8 <_ZN9QHashData6rehashEi@plt+0>:
+ // jmpq *2151882(%rip) # 0x6135b8 <_GLOBAL_OFFSET_TABLE_+648>
+ QString str = ts.readLine();
+ if (!str.startsWith(QLatin1String("0x"))) {
+ //qDebug() << "IGNORING DISASSEMBLER" << str;
+ continue;
+ }
+ DisassemblerLine line;
+ QTextStream ts(&str, QIODevice::ReadOnly);
+ ts >> line.address >> line.symbol;
+ line.mnemonic = ts.readLine().trimmed();
+ if (line.symbol.endsWith(QLatin1Char(':')))
+ line.symbol.chop(1);
+ line.addressDisplay = line.address + pad;
+ if (line.addressDisplay.startsWith(QLatin1String("0x00000000")))
+ line.addressDisplay.replace(2, 8, QString());
+ line.symbolDisplay = line.symbol + pad;
+
+ if (line.address == cookie)
+ currentLine = lines.size();
+
+ lines.append(line);
+ }
+ } else {
+ DisassemblerLine line;
+ line.addressDisplay = tr("<could not retreive module information>");
+ lines.append(line);
+ }
+
+ qq->disassemblerHandler()->setLines(lines);
+ if (currentLine != -1)
+ qq->disassemblerHandler()->setCurrentLine(currentLine);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Modules specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void GdbEngine::loadSymbols(const QString &moduleName)
+{
+ // FIXME: gdb does not understand quoted names here (tested with 6.8)
+ sendCommand("sharedlibrary " + dotEscape(moduleName));
+ reloadModules();
+}
+
+void GdbEngine::loadAllSymbols()
+{
+ sendCommand("sharedlibrary .*");
+ reloadModules();
+}
+
+void GdbEngine::reloadModules()
+{
+ sendCommand("info shared", ModulesList, QVariant());
+}
+
+void GdbEngine::handleModulesList(const GdbResultRecord &record)
+{
+ QList<Module> modules;
+ if (record.resultClass == GdbResultDone) {
+ QString data = record.data.findChild("consolestreamoutput").data();
+ QTextStream ts(&data, QIODevice::ReadOnly);
+ while (!ts.atEnd()) {
+ QString line = ts.readLine();
+ if (!line.startsWith("0x"))
+ continue;
+ Module module;
+ QString symbolsRead;
+ QTextStream ts(&line, QIODevice::ReadOnly);
+ ts >> module.startAddress >> module.endAddress >> symbolsRead;
+ module.moduleName = ts.readLine().trimmed();
+ module.symbolsRead = (symbolsRead == "Yes");
+ modules.append(module);
+ }
+ }
+ qq->modulesHandler()->setModules(modules);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Stack specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void GdbEngine::handleStackSelectThread(const GdbResultRecord &record, int)
+{
+ Q_UNUSED(record);
+ qDebug("FIXME: StackHandler::handleOutput: SelectThread");
+ q->showStatusMessage(tr("Retrieving data for stack view..."), -1);
+ sendCommand("-stack-list-frames", StackListFrames);
+}
+
+
+void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
+{
+ QList<StackFrame> stackFrames;
+
+ const GdbMi stack = record.data.findChild("stack");
+ QString dummy = stack.toString();
+ if (!stack.isValid()) {
+ qDebug() << "FIXME: stack: " << stack.toString();
+ return;
+ }
+
+ int topFrame = -1;
+
+ for (int i = 0; i != stack.childCount(); ++i) {
+ //qDebug() << "HANDLING FRAME: " << stack.childAt(i).toString();
+ const GdbMi frameMi = stack.childAt(i);
+ StackFrame frame;
+ frame.level = i;
+ QStringList files;
+ files.append(frameMi.findChild("fullname").data());
+ files.append(frameMi.findChild("file").data());
+ frame.file = fullName(files);
+ frame.function = frameMi.findChild("func").data();
+ frame.from = frameMi.findChild("from").data();
+ frame.line = frameMi.findChild("line").data().toInt();
+ frame.address = frameMi.findChild("addr").data();
+
+ stackFrames.append(frame);
+
+#ifdef Q_OS_WIN
+ const bool isBogus =
+ // Assume this is wrong and points to some strange stl_algobase
+ // implementation. Happens on Karsten's XP system with Gdb 5.50
+ (frame.file.endsWith("/bits/stl_algobase.h") && frame.line == 150)
+ // Also wrong. Happens on Vista with Gdb 5.50
+ || (frame.function == "operator new" && frame.line == 151);
+
+ // immediately leave bogus frames
+ if (topFrame == -1 && isBogus) {
+ sendCommand("-exec-finish");
+ return;
+ }
+
+#endif
+
+ // Initialize top frame to the first valid frame
+ const bool isValid = !frame.file.isEmpty() && !frame.function.isEmpty();
+ if (isValid && topFrame == -1)
+ topFrame = i;
+ }
+
+ qq->stackHandler()->setFrames(stackFrames);
+
+#if 0
+ if (0 && topFrame != -1) {
+ // updates of locals already triggered early
+ const StackFrame &frame = qq->stackHandler()->currentFrame();
+ bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
+ if (usable)
+ q->gotoLocation(frame.file, frame.line, true);
+ else
+ qDebug() << "FULL NAME NOT USABLE 0: " << frame.file;
+ } else {
+ activateFrame(topFrame);
+ }
+#else
+ if (topFrame != -1) {
+ // updates of locals already triggered early
+ const StackFrame &frame = qq->stackHandler()->currentFrame();
+ bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
+ if (usable)
+ q->gotoLocation(frame.file, frame.line, true);
+ else
+ qDebug() << "FULL NAME NOT USABLE 0: " << frame.file;
+ }
+#endif
+}
+
+void GdbEngine::selectThread(int index)
+{
+ //reset location arrow
+ q->resetLocation();
+
+ ThreadsHandler *threadsHandler = qq->threadsHandler();
+ threadsHandler->setCurrentThread(index);
+
+ QList<ThreadData> threads = threadsHandler->threads();
+ QWB_ASSERT(index < threads.size(), return);
+ int id = threads.at(index).id;
+ q->showStatusMessage(tr("Retrieving data for stack view..."), -1);
+ sendCommand(QLatin1String("-thread-select ") + QString::number(id),
+ StackSelectThread);
+}
+
+void GdbEngine::activateFrame(int frameIndex)
+{
+ if (q->status() != DebuggerInferiorStopped)
+ return;
+
+ StackHandler *stackHandler = qq->stackHandler();
+ int oldIndex = stackHandler->currentIndex();
+ //qDebug() << "ACTIVATE FRAME: " << frameIndex << oldIndex
+ // << stackHandler->currentIndex();
+
+ QWB_ASSERT(frameIndex < stackHandler->stackSize(), return);
+
+ if (oldIndex != frameIndex) {
+ // Assuming this always succeeds saves a roundtrip.
+ // Otherwise the lines below would need to get triggered
+ // after a response to this -stack-select-frame here.
+ sendCommand("-stack-select-frame " + QString::number(frameIndex));
+
+ stackHandler->setCurrentIndex(frameIndex);
+ updateLocals();
+ }
+
+ const StackFrame &frame = stackHandler->currentFrame();
+
+ bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
+ if (usable)
+ q->gotoLocation(frame.file, frame.line, true);
+ else
+ qDebug() << "FULL NAME NOT USABLE: " << frame.file;
+}
+
+void GdbEngine::handleStackListThreads(const GdbResultRecord &record, int id)
+{
+ // "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
+ const QList<GdbMi> items = record.data.findChild("thread-ids").children();
+ QList<ThreadData> threads;
+ int currentIndex = -1;
+ for (int index = 0, n = items.size(); index != n; ++index) {
+ ThreadData thread;
+ thread.id = items.at(index).data().toInt();
+ threads.append(thread);
+ if (thread.id == id) {
+ //qDebug() << "SETTING INDEX TO: " << index << " ID: "<< id << "RECOD: "<< record.toString();
+ currentIndex = index;
+ }
+ }
+ ThreadsHandler *threadsHandler = qq->threadsHandler();
+ threadsHandler->setThreads(threads);
+ threadsHandler->setCurrentThread(currentIndex);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Register specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void GdbEngine::reloadRegisters()
+{
+ QString format = qq->registerHandler()->model()->property(PROPERTY_REGISTER_FORMAT).toString();
+ sendCommand("-data-list-register-values " + format, RegisterListValues);
+}
+
+void GdbEngine::handleRegisterListNames(const GdbResultRecord &record)
+{
+ if (record.resultClass != GdbResultDone)
+ return;
+
+ QList<Register> registers;
+ foreach (const GdbMi &item, record.data.findChild("register-names").children())
+ registers.append(Register(item.data()));
+
+ qq->registerHandler()->setRegisters(registers);
+}
+
+void GdbEngine::handleRegisterListValues(const GdbResultRecord &record)
+{
+ if (record.resultClass != GdbResultDone)
+ return;
+
+ QList<Register> registers = qq->registerHandler()->registers();
+
+ // 24^done,register-values=[{number="0",value="0xf423f"},...]
+ foreach (const GdbMi &item, record.data.findChild("register-values").children()) {
+ int index = item.findChild("number").data().toInt();
+ if (index < registers.size()) {
+ Register &reg = registers[index];
+ QString value = item.findChild("value").data();
+ reg.changed = (value != reg.value);
+ if (reg.changed)
+ reg.value = value;
+ }
+ }
+ qq->registerHandler()->setRegisters(registers);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Thread specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+bool GdbEngine::supportsThreads() const
+{
+ // 6.3 crashes happily on -thread-list-ids. So don't use it.
+ // The test below is a semi-random pick, 6.8 works fine
+ return m_gdbVersion > 650;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Tooltip specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static WatchData m_toolTip;
+static QString m_toolTipExpression;
+static QPoint m_toolTipPos;
+static QHash<QString, WatchData> m_toolTipCache;
+
+static bool hasLetterOrNumber(const QString &exp)
+{
+ for (int i = exp.size(); --i >= 0; )
+ if (exp[i].isLetterOrNumber() || exp[i] == '_')
+ return true;
+ return false;
+}
+
+static bool hasSideEffects(const QString &exp)
+{
+ // FIXME: complete?
+ return exp.contains("-=")
+ || exp.contains("+=")
+ || exp.contains("/=")
+ || exp.contains("*=")
+ || exp.contains("&=")
+ || exp.contains("|=")
+ || exp.contains("^=")
+ || exp.contains("--")
+ || exp.contains("++");
+}
+
+static bool isKeyWord(const QString &exp)
+{
+ // FIXME: incomplete
+ return exp == QLatin1String("class")
+ || exp == QLatin1String("const")
+ || exp == QLatin1String("do")
+ || exp == QLatin1String("if")
+ || exp == QLatin1String("return")
+ || exp == QLatin1String("struct")
+ || exp == QLatin1String("template")
+ || exp == QLatin1String("void")
+ || exp == QLatin1String("volatile")
+ || exp == QLatin1String("while");
+}
+
+void GdbEngine::setToolTipExpression(const QPoint &pos, const QString &exp0)
+{
+ //qDebug() << "SET TOOLTIP EXP" << pos << exp0;
+ if (q->status() != DebuggerInferiorStopped) {
+ //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED";
+ return;
+ }
+
+ if (qq->debugDumpersAction()->isChecked()) {
+ // minimize interference
+ return;
+ }
+
+ m_toolTipPos = pos;
+ m_toolTipExpression = exp0;
+ QString exp = exp0;
+/*
+ if (m_toolTip.isTypePending()) {
+ qDebug() << "suppressing duplicated tooltip creation";
+ return;
+ }
+*/
+ if (m_toolTipCache.contains(exp)) {
+ const WatchData & data = m_toolTipCache[exp];
+ // FIXME: qq->watchHandler()->collapseChildren(data.iname);
+ insertData(data);
+ return;
+ }
+
+ QToolTip::hideText();
+ if (exp.isEmpty() || exp.startsWith("#")) {
+ QToolTip::hideText();
+ return;
+ }
+
+ if (!hasLetterOrNumber(exp)) {
+ QToolTip::showText(m_toolTipPos,
+ "'" + exp + "' contains no identifier");
+ return;
+ }
+
+ if (isKeyWord(exp))
+ return;
+
+ if (exp.startsWith('"') && exp.endsWith('"')) {
+ QToolTip::showText(m_toolTipPos, "String literal " + exp);
+ return;
+ }
+
+ if (exp.startsWith("++") || exp.startsWith("--"))
+ exp = exp.mid(2);
+
+ if (exp.endsWith("++") || exp.endsWith("--"))
+ exp = exp.mid(2);
+
+ if (exp.startsWith("<") || exp.startsWith("["))
+ return;
+
+ if (hasSideEffects(exp)) {
+ QToolTip::showText(m_toolTipPos,
+ "Cowardly refusing to evaluate expression '" + exp
+ + "' with potential side effects");
+ return;
+ }
+
+ // Gdb crashes when creating a variable object with the name
+ // of the type of 'this'
+/*
+ for (int i = 0; i != m_currentLocals.childCount(); ++i) {
+ if (m_currentLocals.childAt(i).exp == "this") {
+ qDebug() << "THIS IN ROW " << i;
+ if (m_currentLocals.childAt(i).type.startsWith(exp)) {
+ QToolTip::showText(m_toolTipPos,
+ exp + ": type of current 'this'");
+ qDebug() << " TOOLTIP CRASH SUPPRESSED";
+ return;
+ }
+ break;
+ }
+ }
+*/
+
+ //if (m_manager->status() != DebuggerInferiorStopped)
+ // return;
+
+ // FIXME: 'exp' can contain illegal characters
+ m_toolTip = WatchData();
+ //m_toolTip.level = 0;
+ // m_toolTip.row = 0;
+ // m_toolTip.parentIndex = 2;
+ m_toolTip.exp = exp;
+ m_toolTip.name = exp;
+ m_toolTip.iname = tooltipIName;
+ insertData(m_toolTip);
+ updateWatchModel2();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Watch specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static const QString strNotInScope = QLatin1String("<not in scope>");
+
+static bool isPointerType(const QString &type)
+{
+ return type.endsWith("*") || type.endsWith("* const");
+}
+
+static bool isAccessSpecifier(const QString &str)
+{
+ static const QStringList items =
+ QStringList() << "private" << "protected" << "public";
+ return items.contains(str);
+}
+
+static bool startsWithDigit(const QString &str)
+{
+ return !str.isEmpty() && str[0] >= '0' && str[0] <= '9';
+}
+
+QString stripPointerType(QString type)
+{
+ if (type.endsWith("*"))
+ type.chop(1);
+ if (type.endsWith("* const"))
+ type.chop(7);
+ if (type.endsWith(' '))
+ type.chop(1);
+ return type;
+}
+
+static QString gdbQuoteTypes(const QString &type)
+{
+ // gdb does not understand sizeof(Core::IFile*).
+ // "sizeof('Core::IFile*')" is also not acceptable,
+ // it needs to be "sizeof('Core::IFile'*)"
+ //
+ // We never will have a perfect solution here (even if we had a full blown
+ // C++ parser as we do not have information on what is a type and what is
+ // a vriable name. So "a<b>::c" could either be two comparisons of values
+ // 'a', 'b' and '::c', or a nested type 'c' in a template 'a<b>'. We
+ // assume here it is the latter.
+ //return type;
+
+ // (*('myns::QPointer<myns::QObject>*'*)0x684060)" is not acceptable
+ // (*('myns::QPointer<myns::QObject>'**)0x684060)" is acceptable
+ if (isPointerType(type))
+ return gdbQuoteTypes(stripPointerType(type)) + "*";
+
+ QString accu;
+ QString result;
+ int templateLevel = 0;
+ for (int i = 0; i != type.size(); ++i) {
+ QChar c = type.at(i);
+ if (c.isLetterOrNumber() || c == '_' || c == ':' || c == ' ') {
+ accu += c;
+ } else if (c == '<') {
+ ++templateLevel;
+ accu += c;
+ } else if (c == '<') {
+ --templateLevel;
+ accu += c;
+ } else if (templateLevel > 0) {
+ accu += c;
+ } else {
+ if (accu.contains(':') || accu.contains('<'))
+ result += '\'' + accu + '\'';
+ else
+ result += accu;
+ accu.clear();
+ result += c;
+ }
+ }
+ if (accu.contains(':') || accu.contains('<'))
+ result += '\'' + accu + '\'';
+ else
+ result += accu;
+ //qDebug() << "GDB_QUOTING" << type << " TO " << result;
+
+ return result;
+}
+
+static void setWatchDataValue(WatchData &data, const GdbMi &mi,
+ int encoding = 0)
+{
+ if (mi.isValid()) {
+ QByteArray ba;
+ switch (encoding) {
+ case 0: // unencoded 8 bit data
+ ba = mi.data();
+ break;
+ case 1: // base64 encoded 8 bit data
+ ba = QByteArray::fromBase64(mi.data());
+ break;
+ case 2: // base64 encoded 16 bit data
+ ba = QByteArray::fromBase64(mi.data());
+ ba = QString::fromUtf16((ushort *)ba.data(), ba.size() / 2).toUtf8();
+ break;
+ case 3: // base64 encoded 32 bit data
+ ba = QByteArray::fromBase64(mi.data());
+ ba = QString::fromUcs4((uint *)ba.data(), ba.size() / 4).toUtf8();
+ break;
+ }
+ data.setValue(ba);
+ } else {
+ data.setValueNeeded();
+ }
+}
+
+static void setWatchDataEditValue(WatchData &data, const GdbMi &mi)
+{
+ if (mi.isValid())
+ data.editvalue = mi.data();
+}
+
+static void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi)
+{
+ if (mi.isValid())
+ data.setValueToolTip(mi.data());
+}
+
+static void setWatchDataChildCount(WatchData &data, const GdbMi &mi)
+{
+ if (mi.isValid()) {
+ data.childCount = mi.data().toInt();
+ data.setChildCountUnneeded();
+ if (data.childCount == 0)
+ data.setChildrenUnneeded();
+ } else {
+ data.childCount = -1;
+ }
+}
+
+static void setWatchDataValueDisabled(WatchData &data, const GdbMi &mi)
+{
+ if (mi.data() == "true")
+ data.valuedisabled = true;
+ else if (mi.data() == "false")
+ data.valuedisabled = false;
+}
+
+static void setWatchDataExpression(WatchData &data, const GdbMi &mi)
+{
+ if (mi.isValid())
+ data.exp = "(" + mi.data() + ")";
+}
+
+static void setWatchDataAddress(WatchData &data, const GdbMi &mi)
+{
+ if (mi.isValid()) {
+ data.addr = mi.data();
+ if (data.exp.isEmpty())
+ data.exp = "(*(" + gdbQuoteTypes(data.type) + "*)" + data.addr + ")";
+ }
+}
+
+static bool extractTemplate(const QString &type, QString *tmplate, QString *inner)
+{
+ // Input "Template<Inner1,Inner2,...>::Foo" will return "Template::Foo" in
+ // 'tmplate' and "Inner1@Inner2@..." etc in 'inner'. Result indicates
+ // whether parsing was successful
+ int level = 0;
+ for (int i = 0; i != type.size(); ++i) {
+ QChar c = type[i];
+ if (c == '<') {
+ *(level == 0 ? tmplate : inner) += c;
+ ++level;
+ } else if (c == '>') {
+ --level;
+ *(level == 0 ? tmplate : inner) += c;
+ } else if (c == ',') {
+ *inner += (level == 1) ? '@' : ',';
+ } else {
+ *(level == 0 ? tmplate : inner) += c;
+ }
+ }
+ *tmplate = tmplate->trimmed();
+ *tmplate = tmplate->remove("<>");
+ *inner = inner->trimmed();
+ //qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner;
+ return !inner->isEmpty();
+}
+
+static QString extractTypeFromPTypeOutput(const QString &str)
+{
+ int pos0 = str.indexOf('=');
+ int pos1 = str.indexOf('{');
+ int pos2 = str.lastIndexOf('}');
+ QString res = str;
+ if (pos0 != -1 && pos1 != -1 && pos2 != -1)
+ res = str.mid(pos0 + 2, pos1 - 1 - pos0)
+ + " ... " + str.right(str.size() - pos2);
+ return res.simplified();
+}
+
+static bool isIntOrFloatType(const QString &type)
+{
+ static const QStringList types = QStringList()
+ << "char" << "int" << "short" << "float" << "double" << "long"
+ << "bool" << "signed char" << "unsigned" << "unsigned char"
+ << "unsigned int" << "unsigned long" << "long long"
+ << "unsigned long long";
+ return types.contains(type);
+}
+
+static QString sizeofTypeExpression(const QString &type)
+{
+ if (type.endsWith('*'))
+ return "sizeof(void*)";
+ if (type.endsWith('>'))
+ return "sizeof(" + type + ")";
+ return "sizeof(" + gdbQuoteTypes(type) + ")";
+}
+
+void GdbEngine::setCustomDumpersWanted(bool on)
+{
+ Q_UNUSED(on);
+ // FIXME: a bit too harsh, but otherwise the treeview
+ // sometimes look funny
+ //m_expandedINames.clear();
+ updateLocals();
+}
+
+bool GdbEngine::isCustomValueDumperAvailable(const QString &type) const
+{
+ if (!qq->useCustomDumpers())
+ return false;
+ if (qq->debugDumpersAction()->isChecked()
+ && qq->stackHandler()->isDebuggingDumpers())
+ return false;
+ if (m_dataDumperState != DataDumperAvailable)
+ return false;
+ if (m_availableSimpleDumpers.contains(type))
+ return true;
+
+ QString tmplate;
+ QString inner;
+ if (extractTemplate(type, &tmplate, &inner)) {
+ if (type.startsWith(m_namespace)) {
+ tmplate = tmplate.mid(m_namespace.size());
+ if (tmplate == "QList")
+ return true;
+ if (tmplate == "QVector")
+ return true;
+ if (tmplate == "QHash")
+ return true;
+ if (tmplate == "QHashNode")
+ return true;
+ if (tmplate == "QMap")
+ return true;
+ if (tmplate == "QMapNode")
+ return true;
+ if (tmplate == "QSet")
+ return true;
+ }
+ if (tmplate == "std::vector" && inner != "bool")
+ return true;
+ if (tmplate == "std::basic_string") {
+ if (inner.startsWith("char@") || inner.startsWith("wchar_t@"))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void GdbEngine::runCustomDumper(const WatchData & data0, bool dumpChildren)
+{
+ WatchData data = data0;
+ QWB_ASSERT(!data.exp.isEmpty(), return);
+ QString tmplate;
+ QString inner;
+ bool isTemplate = extractTemplate(data.type, &tmplate, &inner);
+ QStringList inners = inner.split('@');
+ if (inners.at(0).isEmpty())
+ inners.clear();
+
+ QString outertype = isTemplate ? tmplate : data.type;
+
+ if (outertype == "QWidget")
+ outertype = "QObject";
+
+ QString extraArgs[4];
+ extraArgs[0] = "0";
+ extraArgs[1] = "0";
+ extraArgs[2] = "0";
+ extraArgs[3] = "0";
+ int extraArgCount = 0;
+
+ // "generic" template dumpers: passing sizeof(argument)
+ // gives already most information the dumpers need
+ foreach (const QString &arg, inners)
+ extraArgs[extraArgCount++] = sizeofTypeExpression(arg);
+
+ // in rare cases we need more or less:
+ if (outertype == m_namespace + "QObject") {
+ extraArgs[extraArgCount++] = "(char*)&((('"
+ + m_namespace + "QObjectPrivate'*)&"
+ + data.exp + ")->children)-(char*)&" + data.exp;
+ } else if (outertype == m_namespace + "QVector") {
+ extraArgs[extraArgCount++] = "(char*)&(("
+ + data.exp + ").d->array)-(char*)" + data.exp + ".d";
+ } else if (outertype == m_namespace + "QObjectSlot"
+ || outertype == m_namespace + "QObjectSignal") {
+ // we need the number out of something like
+ // iname="local.ob.slots.[2]deleteLater()"
+ int lastOpened = data.iname.lastIndexOf('[');
+ int lastClosed = data.iname.lastIndexOf(']');
+ QString slotNumber = "-1";
+ if (lastOpened != -1 && lastClosed != -1)
+ slotNumber = data.iname.mid(lastOpened + 1, lastClosed - lastOpened - 1);
+ extraArgs[extraArgCount++] = slotNumber;
+ } else if (outertype == m_namespace + "QMap") {
+ QString nodetype = m_namespace + "QMapNode";
+ nodetype += data.type.mid(m_namespace.size() + 4);
+ //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype;
+ extraArgs[extraArgCount++] = sizeofTypeExpression(nodetype);
+ extraArgs[extraArgCount++] = "(size_t)&(('" + nodetype + "'*)0)->value";
+ } else if (outertype == m_namespace + "QMapNode") {
+ extraArgs[extraArgCount++] = sizeofTypeExpression(data.type);
+ extraArgs[extraArgCount++] = "(size_t)&(('" + data.type + "'*)0)->value";
+ } else if (outertype == "std::vector") {
+ //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
+ if (inners.at(0) == "bool") {
+ outertype = "std::vector::bool";
+ } else {
+ //extraArgs[extraArgCount++] = sizeofTypeExpression(data.type);
+ //extraArgs[extraArgCount++] = "(size_t)&(('" + data.type + "'*)0)->value";
+ }
+ } else if (outertype == "std::basic_string") {
+ //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
+ if (inners.at(0) == "char") {
+ outertype = "std::string";
+ } else if (inners.at(0) == "wchar_t") {
+ outertype = "std::wstring";
+ }
+ extraArgs[0] = "0";
+ extraArgs[1] = "0";
+ extraArgs[2] = "0";
+ extraArgs[3] = "0";
+ }
+
+ //int protocol = (data.iname.startsWith("watch") && data.type == "QImage") ? 3 : 2;
+ //int protocol = data.iname.startsWith("watch") ? 3 : 2;
+ int protocol = 2;
+ //int protocol = isDisplayedIName(data.iname) ? 3 : 2;
+
+ QString addr;
+ if (data.addr.startsWith("0x"))
+ addr = "(void*)" + data.addr;
+ else
+ addr = "&(" + data.exp + ")";
+
+ QByteArray params;
+ params.append(outertype);
+ params.append('\0');
+ params.append(data.iname);
+ params.append('\0');
+ params.append(data.exp);
+ params.append('\0');
+ params.append(inner);
+ params.append('\0');
+ params.append(data.iname);
+ params.append('\0');
+
+ sendWatchParameters(params);
+
+ QString cmd ="call "
+ + QString("qDumpObjectData440(")
+ + QString::number(protocol)
+ + ',' + "%1+1" // placeholder for token
+ + ',' + addr
+ + ',' + (dumpChildren ? "1" : "0")
+ + ',' + extraArgs[0]
+ + ',' + extraArgs[1]
+ + ',' + extraArgs[2]
+ + ',' + extraArgs[3] + ')';
+
+ sendSynchronizedCommand(cmd, WatchDumpCustomValue1, QVariant::fromValue(data));
+
+ q->showStatusMessage(
+ tr("Retrieving data for watch view (%1 requests pending)...")
+ .arg(m_pendingRequests + 1), -1);
+ // create response slot for socket data
+ QVariant var;
+ var.setValue(data);
+ sendSynchronizedCommand(QString(), WatchDumpCustomValue2, var);
+
+ // this increases the probability that gdb spits out output it
+ // has collected so far
+ //sendCommand("p qDumpInBuffer");
+}
+
+void GdbEngine::createGdbVariable(const WatchData &data)
+{
+ sendSynchronizedCommand("-var-delete \"" + data.iname + '"');
+ QString exp = data.exp;
+ if (exp.isEmpty() && data.addr.startsWith("0x"))
+ exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.addr;
+ QVariant val = QVariant::fromValue<WatchData>(data);
+ sendSynchronizedCommand("-var-create \"" + data.iname + '"' + " * "
+ + '"' + exp + '"', WatchVarCreate, val);
+}
+
+void GdbEngine::updateSubItem(const WatchData &data0)
+{
+ WatchData data = data0;
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: " << data.toString();
+ #endif
+ QWB_ASSERT(data.isValid(), return);
+
+ // in any case we need the type first
+ if (data.isTypeNeeded()) {
+ // This should only happen if we don't have a variable yet.
+ // Let's play safe, though.
+ if (!data.variable.isEmpty()) {
+ // Update: It does so for out-of-scope watchers.
+ #if 1
+ qDebug() << "FIXME: GdbEngine::updateSubItem: "
+ << data.toString() << "should not happen";
+ #else
+ data.setType("<out of scope>");
+ data.setValue("<out of scope>");
+ data.setChildCount(0);
+ insertData(data);
+ return;
+ #endif
+ }
+ // The WatchVarCreate handler will receive type information
+ // and re-insert a WatchData item with correct type, so
+ // we will not re-enter this bit.
+ // FIXME: Concurrency issues?
+ createGdbVariable(data);
+ return;
+ }
+
+ // we should have a type now. this is relied upon further below
+ QWB_ASSERT(!data.type.isEmpty(), return);
+
+ // a common case that can be easily solved
+ if (data.isChildrenNeeded() && isPointerType(data.type)
+ && !isCustomValueDumperAvailable(data.type)) {
+ // We sometimes know what kind of children pointers have
+ #if DEBUG_SUBITEM
+ qDebug() << "IT'S A POINTER";
+ #endif
+#if 1
+ WatchData data1;
+ data1.iname = data.iname + ".*";
+ data1.name = "*" + data.name;
+ data1.exp = "(*(" + data.exp + "))";
+ data1.type = stripPointerType(data.type);
+ data1.setValueNeeded();
+ insertData(data1);
+ data.setChildrenUnneeded();
+ insertData(data);
+#else
+ // Try automatic dereferentiation
+ data.exp = "*(" + data.exp + ")";
+ data.type = data.type + "."; // FIXME: fragile HACK to avoid recursion
+ insertData(data);
+#endif
+ return;
+ }
+
+ if (data.isValueNeeded() && isCustomValueDumperAvailable(data.type)) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: CUSTOMVALUE";
+ #endif
+ runCustomDumper(data, qq->watchHandler()->isExpandedIName(data.iname));
+ return;
+ }
+
+/*
+ if (data.isValueNeeded() && data.exp.isEmpty()) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: NO EXPRESSION?";
+ #endif
+ data.setError("<no expression given>");
+ insertData(data);
+ return;
+ }
+*/
+
+ if (data.isValueNeeded() && data.variable.isEmpty()) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR VALUE";
+ #endif
+ createGdbVariable(data);
+ // the WatchVarCreate handler will re-insert a WatchData
+ // item, with valueNeeded() set.
+ return;
+ }
+
+ if (data.isValueNeeded()) {
+ QWB_ASSERT(!data.variable.isEmpty(), return); // tested above
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: VALUE";
+ #endif
+ QString cmd = "-var-evaluate-expression \"" + data.iname + "\"";
+ sendSynchronizedCommand(cmd, WatchEvaluateExpression,
+ QVariant::fromValue(data));
+ return;
+ }
+
+ if (data.isChildrenNeeded() && isCustomValueDumperAvailable(data.type)) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: CUSTOMVALUE WITH CHILDREN";
+ #endif
+ runCustomDumper(data, true);
+ return;
+ }
+
+ if (data.isChildrenNeeded() && data.variable.isEmpty()) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDREN";
+ #endif
+ createGdbVariable(data);
+ // the WatchVarCreate handler will re-insert a WatchData
+ // item, with childrenNeeded() set.
+ return;
+ }
+
+ if (data.isChildrenNeeded()) {
+ QWB_ASSERT(!data.variable.isEmpty(), return); // tested above
+ QString cmd = "-var-list-children --all-values \"" + data.variable + "\"";
+ sendSynchronizedCommand(cmd, WatchVarListChildren, QVariant::fromValue(data));
+ return;
+ }
+
+ if (data.isChildCountNeeded() && isCustomValueDumperAvailable(data.type)) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: CUSTOMVALUE WITH CHILDREN";
+ #endif
+ runCustomDumper(data, qq->watchHandler()->isExpandedIName(data.iname));
+ return;
+ }
+
+ if (data.isChildCountNeeded() && data.variable.isEmpty()) {
+ #if DEBUG_SUBITEM
+ qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT";
+ #endif
+ createGdbVariable(data);
+ // the WatchVarCreate handler will re-insert a WatchData
+ // item, with childrenNeeded() set.
+ return;
+ }
+
+ if (data.isChildCountNeeded()) {
+ QWB_ASSERT(!data.variable.isEmpty(), return); // tested above
+ QString cmd = "-var-list-children --all-values \"" + data.variable + "\"";
+ sendCommand(cmd, WatchVarListChildren, QVariant::fromValue(data));
+ return;
+ }
+
+ qDebug() << "FIXME: UPDATE SUBITEM: " << data.toString();
+ QWB_ASSERT(false, return);
+}
+
+void GdbEngine::updateWatchModel()
+{
+ m_pendingRequests = 0;
+ PENDING_DEBUG("EXTERNAL TRIGGERING UPDATE WATCH MODEL");
+ updateWatchModel2();
+}
+
+void GdbEngine::updateWatchModel2()
+{
+ PENDING_DEBUG("UPDATE WATCH MODEL");
+ QList<WatchData> incomplete = qq->watchHandler()->takeCurrentIncompletes();
+ //QWB_ASSERT(incomplete.isEmpty(), /**/);
+ if (!incomplete.isEmpty()) {
+ #if DEBUG_PENDING
+ qDebug() << "##############################################";
+ qDebug() << "UPDATE MODEL, FOUND INCOMPLETES:";
+ foreach (const WatchData &data, incomplete)
+ qDebug() << data.toString();
+ #endif
+
+ // Bump requests to avoid model rebuilding during the nested
+ // updateWatchModel runs.
+ ++m_pendingRequests;
+ foreach (const WatchData &data, incomplete)
+ updateSubItem(data);
+ PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
+ updateWatchModel2();
+ --m_pendingRequests;
+
+ return;
+ }
+
+ if (m_pendingRequests > 0) {
+ PENDING_DEBUG("UPDATE MODEL, PENDING: " << m_pendingRequests);
+ return;
+ }
+
+ PENDING_DEBUG("REBUILDING MODEL")
+ emit gdbInputAvailable(QString(),
+ "[" + currentTime() + "] <Rebuild Watchmodel>");
+ q->showStatusMessage(tr("Finished retrieving data."), -1);
+ qq->watchHandler()->rebuildModel();
+
+ if (!m_toolTipExpression.isEmpty()) {
+ WatchData *data = qq->watchHandler()->findData(tooltipIName);
+ if (data) {
+ //m_toolTipCache[data->exp] = *data;
+ QToolTip::showText(m_toolTipPos,
+ "(" + data->type + ") " + data->exp + " = " + data->value);
+ } else {
+ QToolTip::showText(m_toolTipPos,
+ "Cannot evaluate expression: " + m_toolTipExpression);
+ }
+ }
+
+ //qDebug() << "INSERT DATA" << data0.toString();
+ //q->showStatusMessage(tr("Stopped."), 5000);
+}
+
+void GdbEngine::handleQueryDataDumper1(const GdbResultRecord &record)
+{
+ Q_UNUSED(record);
+}
+
+void GdbEngine::handleQueryDataDumper2(const GdbResultRecord &record)
+{
+ // is this the official gdb response. However, it won't contain
+ // interesting data other than the information that 'real' data
+ // either already arrived or is still in the pipe. So we do
+ // _not_ register this result for counting purposes, this will
+ // be done by the 'real' result (with resultClass == GdbResultCustomDone)
+ //qDebug() << "DATA DUMPER TRIAL:" << record.toString();
+ GdbMi output = record.data.findChild("customvaluecontents");
+ GdbMi contents(output.data());
+ GdbMi simple = contents.findChild("simpledumpers");
+ m_namespace = contents.findChild("namespace").data();
+ //qDebug() << "OUTPUT: " << output.toString();
+ //qDebug() << "CONTENTS: " << contents.toString();
+ //qDebug() << "SIMPLE DUMPERS: " << simple.toString();
+ m_availableSimpleDumpers.clear();
+ foreach (const GdbMi &item, simple.children())
+ m_availableSimpleDumpers.append(item.data());
+ if (m_availableSimpleDumpers.isEmpty()) {
+ m_dataDumperState = DataDumperUnavailable;
+ QMessageBox::warning(q->mainWindow(),
+ tr("Cannot find special data dumpers"),
+ tr("The debugged binary does not contain information needed for "
+ "nice display of Qt data types.\n\n"
+ "Try might want to try include the file\n\n"
+ ".../ide/main/bin/gdbmacros/gdbmacros.cpp'\n\n"
+ "into your project directly.")
+ );
+ } else {
+ m_dataDumperState = DataDumperAvailable;
+ }
+ //qDebug() << "DATA DUMPERS AVAILABLE" << m_availableSimpleDumpers;
+}
+
+void GdbEngine::sendWatchParameters(const QByteArray &params0)
+{
+ QByteArray params = params0;
+ params.append('\0');
+ char buf[50];
+ sprintf(buf, "set {char[%d]} qDumpInBuffer = {", params.size());
+ QByteArray encoded;
+ encoded.append(buf);
+ for (int i = 0; i != params.size(); ++i) {
+ sprintf(buf, "%d,", int(params[i]));
+ encoded.append(buf);
+ }
+ encoded[encoded.size() - 1] = '}';
+
+ sendCommand(encoded);
+}
+
+void GdbEngine::handleVarAssign()
+{
+ // everything might have changed, force re-evaluation
+ // FIXME: Speed this up by re-using variables and only
+ // marking values as 'unknown'
+ updateLocals();
+}
+
+void GdbEngine::setWatchDataType(WatchData &data, const GdbMi &mi)
+{
+ if (mi.isValid()) {
+ if (!data.framekey.isEmpty())
+ m_varToType[data.framekey] = mi.data();
+ data.setType(mi.data());
+ } else if (data.type.isEmpty()) {
+ data.setTypeNeeded();
+ }
+}
+
+void GdbEngine::handleVarCreate(const GdbResultRecord &record,
+ const WatchData &data0)
+{
+ WatchData data = data0;
+ // happens e.g. when we already issued a var-evaluate command
+ if (!data.isValid())
+ return;
+ //qDebug() << "HANDLE VARIABLE CREATION: " << data.toString();
+ if (record.resultClass == GdbResultDone) {
+ data.variable = data.iname;
+ setWatchDataType(data, record.data.findChild("type"));
+ if (isCustomValueDumperAvailable(data.type)) {
+ // we do not trust gdb if we have a custom dumper
+ if (record.data.findChild("children").isValid())
+ data.setChildrenUnneeded();
+ else if (qq->watchHandler()->isExpandedIName(data.iname))
+ data.setChildrenNeeded();
+ insertData(data);
+ } else {
+ if (record.data.findChild("children").isValid())
+ data.setChildrenUnneeded();
+ else if (qq->watchHandler()->isExpandedIName(data.iname))
+ data.setChildrenNeeded();
+ setWatchDataChildCount(data, record.data.findChild("numchild"));
+ //if (data.isValueNeeded() && data.childCount > 0)
+ // data.setValue(QByteArray());
+ insertData(data);
+ }
+ } else if (record.resultClass == GdbResultError) {
+ data.setError(record.data.findChild("msg").data());
+ if (data.isWatcher()) {
+ data.value = strNotInScope;
+ data.type = " ";
+ data.setAllUnneeded();
+ data.setChildCount(0);
+ data.valuedisabled = true;
+ insertData(data);
+ }
+ }
+}
+
+void GdbEngine::handleEvaluateExpression(const GdbResultRecord &record,
+ const WatchData &data0)
+{
+ WatchData data = data0;
+ QWB_ASSERT(data.isValid(), qDebug() << "HUH?");
+ if (record.resultClass == GdbResultDone) {
+ //if (col == 0)
+ // data.name = record.data.findChild("value").data();
+ //else
+ setWatchDataValue(data, record.data.findChild("value"));
+ } else if (record.resultClass == GdbResultError) {
+ data.setError(record.data.findChild("msg").data());
+ }
+ //qDebug() << "HANDLE EVALUATE EXPRESSION: " << data.toString();
+ insertData(data);
+ //updateWatchModel2();
+}
+
+void GdbEngine::handleDumpCustomSetup(const GdbResultRecord &record)
+{
+ qDebug() << "CUSTOM SETUP RESULT: " << record.toString();
+ if (record.resultClass == GdbResultDone) {
+ } else if (record.resultClass == GdbResultError) {
+ QString msg = record.data.findChild("msg").data();
+ qDebug() << "CUSTOM DUMPER SETUP ERROR MESSAGE: " << msg;
+ }
+}
+
+void GdbEngine::handleDumpCustomValue1(const GdbResultRecord &record,
+ const WatchData &data0)
+{
+ WatchData data = data0;
+ QWB_ASSERT(data.isValid(), return);
+ if (record.resultClass == GdbResultDone) {
+ // ignore this case, data will follow
+ } else if (record.resultClass == GdbResultError) {
+ // Record an extra result, as the socket result will be lost
+ // in transmission
+ --m_pendingRequests;
+ QString msg = record.data.findChild("msg").data();
+ //qDebug() << "CUSTOM DUMPER ERROR MESSAGE: " << msg;
+#ifdef QT_DEBUG
+ // Make debugging of dumers easier
+ if (qq->debugDumpersAction()->isChecked()
+ && msg.startsWith("The program being debugged stopped while")
+ && msg.contains("qDumpObjectData440")) {
+ // Fake full stop
+ sendCommand("-file-list-exec-source-files", GdbQuerySources);
+ sendCommand("-break-list", BreakList);
+ sendCommand("p 0", GdbAsyncOutput2); // dummy
+ return;
+ }
+#endif
+ if (msg.startsWith("The program being debugged was sig"))
+ msg = strNotInScope;
+ if (msg.startsWith("The program being debugged stopped while"))
+ msg = strNotInScope;
+ data.setError(msg);
+ insertData(data);
+ }
+}
+
+void GdbEngine::handleDumpCustomValue2(const GdbResultRecord &record,
+ const WatchData &data0)
+{
+ WatchData data = data0;
+ QWB_ASSERT(data.isValid(), return);
+ //qDebug() << "CUSTOM VALUE RESULT: " << record.toString();
+ //qDebug() << "FOR DATA: " << data.toString() << record.resultClass;
+ if (record.resultClass == GdbResultDone) {
+ GdbMi output = record.data.findChild("customvaluecontents");
+ //qDebug() << "HANDLE VALUE CONTENTS: " << output.toString(true);
+ if (!output.isValid()) {
+ //qDebug() << "INVALID";
+ // custom dumper produced no output
+ if (data.isValueNeeded())
+ data.setValue("<unknown>");
+ if (data.isTypeNeeded())
+ data.setType("<unknown>");
+ if (data.isChildrenNeeded())
+ data.setChildCount(0);
+ if (data.isChildCountNeeded())
+ data.setChildCount(0);
+ data.setValueToolTip("<custom dumper produced no output>");
+ insertData(data);
+ } else {
+ GdbMi contents;
+ //qDebug() << "OUTPUT" << output.toString(true);
+ contents.fromString(output.data());
+ //qDebug() << "CONTENTS" << contents.toString(true);
+ setWatchDataType(data, contents.findChild("type"));
+ setWatchDataValue(data, contents.findChild("value"),
+ contents.findChild("valueencoded").data().toInt());
+ setWatchDataAddress(data, contents.findChild("addr"));
+ setWatchDataChildCount(data, contents.findChild("numchild"));
+ setWatchDataValueToolTip(data, contents.findChild("valuetooltip"));
+ setWatchDataValueDisabled(data, contents.findChild("valuedisabled"));
+ setWatchDataEditValue(data, contents.findChild("editvalue"));
+ if (qq->watchHandler()->isDisplayedIName(data.iname)) {
+ GdbMi editvalue = contents.findChild("editvalue");
+ if (editvalue.isValid()) {
+ setWatchDataEditValue(data, editvalue);
+ qq->watchHandler()->showEditValue(data);
+ }
+ }
+ if (!qq->watchHandler()->isExpandedIName(data.iname))
+ data.setChildrenUnneeded();
+ GdbMi children = contents.findChild("children");
+ if (children.isValid() || !qq->watchHandler()->isExpandedIName(data.iname))
+ data.setChildrenUnneeded();
+ data.setValueUnneeded();
+
+ // try not to repeat data too often
+ WatchData childtemplate;
+ setWatchDataType(childtemplate, contents.findChild("childtype"));
+ setWatchDataChildCount(childtemplate, contents.findChild("childnumchild"));
+ //qDebug() << "DATA: " << data.toString();
+ insertData(data);
+ foreach (GdbMi item, children.children()) {
+ WatchData data1 = childtemplate;
+ data1.name = item.findChild("name").data();
+ data1.iname = data.iname + "." + data1.name;
+ //qDebug() << "NAMEENCODED: " << item.findChild("nameencoded").data()
+ // << item.findChild("nameencoded").data()[1];
+ if (item.findChild("nameencoded").data()[0] == '1')
+ data1.name = QByteArray::fromBase64(data1.name.toUtf8());
+ if (item.findChild("nameisindex").data()[0] == '1')
+ data1.name = '[' + data1.name + ']';
+ setWatchDataType(data1, item.findChild("type"));
+ setWatchDataExpression(data1, item.findChild("exp"));
+ setWatchDataChildCount(data1, item.findChild("numchild"));
+ setWatchDataValue(data1, item.findChild("value"),
+ item.findChild("valueencoded").data().toInt());
+ setWatchDataAddress(data1, item.findChild("addr"));
+ setWatchDataValueToolTip(data1, item.findChild("valuetooltip"));
+ setWatchDataValueDisabled(data1, item.findChild("valuedisabled"));
+ if (!qq->watchHandler()->isExpandedIName(data1.iname))
+ data1.setChildrenUnneeded();
+ //qDebug() << "HANDLE CUSTOM SUBCONTENTS:" << data1.toString();
+ insertData(data1);
+ }
+ }
+ //qDebug() << "HANDLE CUSTOM VALUE CONTENTS: " << data.toString();
+ } else if (record.resultClass == GdbResultError) {
+ // FIXME: Should not happen here, i.e. could be removed
+ QString msg = record.data.findChild("msg").data();
+ //qDebug() << "CUSTOM DUMPER ERROR MESSAGE: " << msg;
+ if (msg.startsWith("The program being debugged was sig"))
+ msg = strNotInScope;
+ if (msg.startsWith("The program being debugged stopped while"))
+ msg = strNotInScope;
+ data.setError(msg);
+ insertData(data);
+ } else {
+ qDebug() << "STRANGE CUSTOM DUMPER RESULT DATA: " << data.toString();
+ }
+}
+
+void GdbEngine::updateLocals()
+{
+ setTokenBarrier();
+
+ m_pendingRequests = 0;
+ PENDING_DEBUG("\nRESET PENDING");
+ m_toolTipCache.clear();
+ m_toolTipExpression.clear();
+ qq->watchHandler()->reinitializeWatchers();
+
+ int level = currentFrame();
+ // '2' is 'list with type and value'
+ QString cmd = QString("-stack-list-arguments 2 %1 %2").arg(level).arg(level);
+ sendSynchronizedCommand(cmd, StackListArguments); // stage 1/2
+ // '2' is 'list with type and value'
+ sendSynchronizedCommand("-stack-list-locals 2", StackListLocals); // stage 2/2
+}
+
+void GdbEngine::handleStackListArguments(const GdbResultRecord &record)
+{
+ // stage 1/2
+
+ // Linux:
+ // 12^done,stack-args=
+ // [frame={level="0",args=[
+ // {name="argc",type="int",value="1"},
+ // {name="argv",type="char **",value="(char **) 0x7..."}]}]
+ // Mac:
+ // 78^done,stack-args=
+ // {frame={level="0",args={
+ // varobj=
+ // {exp="this",value="0x38a2fab0",name="var21",numchild="3",
+ // type="CurrentDocumentFind * const",typecode="PTR",
+ // dynamic_type="",in_scope="true",block_start_addr="0x3938e946",
+ // block_end_addr="0x3938eb2d"},
+ // varobj=
+ // {exp="before",value="@0xbfffb9f8: {d = 0x3a7f2a70}",
+ // name="var22",numchild="1",type="const QString ...} }}}
+ //
+ // In both cases, iterating over the children of stack-args/frame/args
+ // is ok.
+ m_currentFunctionArgs.clear();
+ if (record.resultClass == GdbResultDone) {
+ const GdbMi list = record.data.findChild("stack-args");
+ const GdbMi frame = list.findChild("frame");
+ const GdbMi args = frame.findChild("args");
+ m_currentFunctionArgs = args.children();
+ } else if (record.resultClass == GdbResultError) {
+ qDebug() << "FIXME: GdbEngine::handleStackListArguments: should not happen";
+ }
+}
+
+void GdbEngine::handleStackListLocals(const GdbResultRecord &record)
+{
+ // stage 2/2
+
+ // There could be shadowed variables
+ QHash<QString, int> seen;
+ QList<GdbMi> locals = record.data.findChild("locals").children();
+ locals += m_currentFunctionArgs;
+
+ //qDebug() << m_varToType;
+
+ foreach (const GdbMi &item, locals) {
+ #ifdef Q_OS_MAC
+ QString name = item.findChild("exp").data();
+ #else
+ QString name = item.findChild("name").data();
+ #endif
+ int n = seen.value(name);
+ if (n) {
+ seen[name] = n + 1;
+ WatchData data;
+ data.iname = "local." + name + QString::number(n + 1);
+ data.name = name + QString(" <shadowed %1>").arg(n);
+ //data.setValue("<shadowed>");
+ setWatchDataValue(data, item.findChild("value"));
+ data.setType("<shadowed>");
+ data.setChildCount(0);
+ insertData(data);
+ } else {
+ seen[name] = 1;
+ WatchData data;
+ data.iname = "local." + name;
+ data.name = name;
+ data.exp = name;
+ data.framekey = m_currentFrame + data.name;
+ setWatchDataType(data, item.findChild("type"));
+ // set value only directly if it is simple enough, otherwise
+ // pass through the insertData() machinery
+ if (isIntOrFloatType(data.type) || isPointerType(data.type))
+ setWatchDataValue(data, item.findChild("value"));
+ if (!qq->watchHandler()->isExpandedIName(data.iname))
+ data.setChildrenUnneeded();
+ if (isPointerType(data.type) || data.name == "this")
+ data.setChildCount(1);
+ if (0 && m_varToType.contains(data.framekey)) {
+ qDebug() << "RE-USING " << m_varToType.value(data.framekey);
+ data.setType(m_varToType.value(data.framekey));
+ }
+ insertData(data);
+ }
+ }
+}
+
+void GdbEngine::insertData(const WatchData &data0)
+{
+ //qDebug() << "INSERT DATA" << data0.toString();
+ WatchData data = data0;
+ if (data.value.startsWith("mi_cmd_var_create:")) {
+ qDebug() << "BOGUS VALUE: " << data.toString();
+ return;
+ }
+ qq->watchHandler()->insertData(data);
+}
+
+void GdbEngine::handleTypeContents(const QString &output)
+{
+ // output.startsWith("type = ") == true
+ // "type = int"
+ // "type = class QString {"
+ // "type = class QStringList : public QList<QString> {"
+ QString tip;
+ QString className;
+ if (output.startsWith("type = class")) {
+ int posBrace = output.indexOf('{');
+ QString head = output.mid(13, posBrace - 13 - 1);
+ int posColon = head.indexOf(": public");
+ if (posColon == -1)
+ posColon = head.indexOf(": protected");
+ if (posColon == -1)
+ posColon = head.indexOf(": private");
+ if (posColon == -1) {
+ className = head;
+ tip = "class " + className + " { ... }";
+ } else {
+ className = head.left(posColon - 1);
+ tip = "class " + head + " { ... }";
+ }
+ //qDebug() << "posColon: " << posColon;
+ //qDebug() << "posBrace: " << posBrace;
+ //qDebug() << "head: " << head;
+ } else {
+ className = output.mid(7);
+ tip = className;
+ }
+ //qDebug() << "output: " << output.left(100) + "...";
+ //qDebug() << "className: " << className;
+ //qDebug() << "tip: " << tip;
+ //m_toolTip.type = className;
+ m_toolTip.type.clear();
+ m_toolTip.value = tip;
+}
+
+void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
+ const WatchData &parent)
+{
+ //qDebug() << "VAR_LIST_CHILDREN: PARENT 2" << parent.toString();
+ //qDebug() << "VAR_LIST_CHILDREN: APPENDEE " << data.toString();
+ QByteArray exp = item.findChild("exp").data();
+ QByteArray name = item.findChild("name").data();
+ if (isAccessSpecifier(exp)) {
+ // suppress 'private'/'protected'/'public' level
+ WatchData data;
+ data.variable = name;
+ data.iname = parent.iname;
+ //data.iname = data.variable;
+ data.exp = parent.exp;
+ data.setTypeUnneeded();
+ data.setValueUnneeded();
+ data.setChildCountUnneeded();
+ data.setChildrenUnneeded();
+ //qDebug() << "DATA" << data.toString();
+ QString cmd = "-var-list-children --all-values \"" + data.variable + "\"";
+ //iname += '.' + exp;
+ sendSynchronizedCommand(cmd, WatchVarListChildren, QVariant::fromValue(data));
+ } else if (item.findChild("numchild").data() == "0") {
+ // happens for structs without data, e.g. interfaces.
+ WatchData data;
+ data.iname = parent.iname + '.' + exp;
+ data.name = exp;
+ data.variable = name;
+ setWatchDataType(data, item.findChild("type"));
+ setWatchDataValue(data, item.findChild("value"));
+ setWatchDataAddress(data, item.findChild("addr"));
+ data.setChildCount(0);
+ insertData(data);
+ } else if (parent.iname.endsWith('.')) {
+ // Happens with anonymous unions
+ WatchData data;
+ data.iname = name;
+ QString cmd = "-var-list-children --all-values \"" + data.variable + "\"";
+ sendSynchronizedCommand(cmd, WatchVarListChildren, QVariant::fromValue(data));
+ } else if (exp == "staticMetaObject") {
+ // && item.findChild("type").data() == "const QMetaObject")
+ // FIXME: Namespaces?
+ // { do nothing } FIXME: make coinfigurable?
+ // special "clever" hack to avoid clutter in the GUI.
+ // I am not sure this is a good idea...
+ } else {
+ WatchData data;
+ data.iname = parent.iname + '.' + exp;
+ data.variable = name;
+ setWatchDataType(data, item.findChild("type"));
+ setWatchDataValue(data, item.findChild("value"));
+ setWatchDataAddress(data, item.findChild("addr"));
+ setWatchDataChildCount(data, item.findChild("numchild"));
+ if (!qq->watchHandler()->isExpandedIName(data.iname))
+ data.setChildrenUnneeded();
+
+ data.name = exp;
+ if (isPointerType(parent.type) && data.type == exp) {
+ data.exp = "*(" + parent.exp + ")";
+ data.name = "*" + parent.name;
+ } else if (data.type == exp) {
+ // A type we derive from? gdb crashes when creating variables here
+ data.exp = parent.exp;
+ } else if (exp.startsWith("*")) {
+ // A pointer
+ data.exp = "*(" + parent.exp + ")";
+ } else if (startsWithDigit(exp)) {
+ // An array. No variables needed?
+ data.name = "[" + data.name + "]";
+ data.exp = parent.exp + "[" + exp + "]";
+ } else if (0 && parent.name.endsWith('.')) {
+ // Happens with anonymous unions
+ data.exp = parent.exp + exp;
+ //data.name = "<anonymous union>";
+ } else if (exp.isEmpty()) {
+ // Happens with anonymous unions
+ data.exp = parent.exp;
+ data.name = "<n/a>";
+ data.iname = parent.iname + ".@";
+ data.type = "<anonymous union>";
+ } else {
+ // A structure. Hope there's nothing else...
+ data.exp = parent.exp + '.' + exp;
+ }
+
+ if (isCustomValueDumperAvailable(data.type)) {
+ // we do not trust gdb if we have a custom dumper
+ data.setValueNeeded();
+ data.setChildCountNeeded();
+ }
+
+ //qDebug() << "VAR_LIST_CHILDREN: PARENT 3" << parent.toString();
+ //qDebug() << "VAR_LIST_CHILDREN: APPENDEE " << data.toString();
+ insertData(data);
+ }
+}
+
+void GdbEngine::handleVarListChildren(const GdbResultRecord &record,
+ const WatchData &data0)
+{
+ //WatchResultCounter dummy(this, WatchVarListChildren);
+ WatchData data = data0;
+ if (!data.isValid())
+ return;
+ if (record.resultClass == GdbResultDone) {
+ //qDebug() << "VAR_LIST_CHILDREN: PARENT " << data.toString();
+ GdbMi children = record.data.findChild("children");
+
+ foreach (const GdbMi &child, children.children())
+ handleVarListChildrenHelper(child, data);
+
+ if (!isAccessSpecifier(data.variable.split('.').takeLast())) {
+ data.setChildrenUnneeded();
+ insertData(data);
+ }
+ } else if (record.resultClass == GdbResultError) {
+ data.setError(record.data.findChild("msg").data());
+ } else {
+ data.setError("Unknown error: " + record.toString());
+ }
+}
+
+void GdbEngine::handleToolTip(const GdbResultRecord &record,
+ const QString &what)
+{
+ //qDebug() << "HANDLE TOOLTIP: " << what << m_toolTip.toString();
+ // << "record: " << record.toString();
+ if (record.resultClass == GdbResultError) {
+ QString msg = record.data.findChild("msg").data();
+ if (what == "create") {
+ sendCommand("ptype " + m_toolTip.exp, WatchToolTip, "ptype");
+ return;
+ }
+ if (what == "evaluate") {
+ if (msg.startsWith("Cannot look up value of a typedef")) {
+ m_toolTip.value = m_toolTip.exp + " is a typedef.";
+ //return;
+ }
+ }
+ } else if (record.resultClass == GdbResultDone) {
+ if (what == "create") {
+ setWatchDataType(m_toolTip, record.data.findChild("type"));
+ setWatchDataChildCount(m_toolTip, record.data.findChild("numchild"));
+ if (isCustomValueDumperAvailable(m_toolTip.type))
+ runCustomDumper(m_toolTip, false);
+ else
+ q->showStatusMessage(tr("Retrieving data for tooltip..."), -1);
+ sendCommand("-data-evaluate-expression " + m_toolTip.exp,
+ WatchToolTip, "evaluate");
+ //sendToolTipCommand("-var-evaluate-expression tooltip")
+ return;
+ }
+ if (what == "evaluate") {
+ m_toolTip.value = m_toolTip.type + ' ' + m_toolTip.exp
+ + " = " + record.data.findChild("value").data();
+ //return;
+ }
+ if (what == "ptype") {
+ GdbMi mi = record.data.findChild("consolestreamoutput");
+ m_toolTip.value = extractTypeFromPTypeOutput(mi.data());
+ //return;
+ }
+ }
+
+ m_toolTip.iname = tooltipIName;
+ m_toolTip.setChildrenUnneeded();
+ m_toolTip.setChildCountUnneeded();
+ insertData(m_toolTip);
+ qDebug() << "DATA INSERTED";
+ QTimer::singleShot(0, this, SLOT(updateWatchModel2()));
+ qDebug() << "HANDLE TOOLTIP END";
+}
+
+#if 0
+void GdbEngine::handleChangedItem(QStandardItem *item)
+{
+ // HACK: Just store the item for the slot
+ // handleChangedItem(QWidget *widget) below.
+ QModelIndex index = item->index().sibling(item->index().row(), 0);
+ //WatchData data = m_currentSet.takeData(iname);
+ //m_editedData = inameFromItem(m_model.itemFromIndex(index)).exp;
+ //qDebug() << "HANDLE CHANGED EXPRESSION: " << m_editedData;
+}
+#endif
+
+void GdbEngine::assignValueInDebugger(const QString &expression, const QString &value)
+{
+ sendCommand("-var-delete assign");
+ sendCommand("-var-create assign * " + expression);
+ sendCommand("-var-assign assign " + value, WatchVarAssign);
+}
+
+
+void GdbEngine::tryLoadCustomDumpers()
+{
+ if (m_dataDumperState != DataDumperUninitialized)
+ return;
+
+ PENDING_DEBUG("TRY LOAD CUSTOM DUMPERS");
+ m_dataDumperState = DataDumperLoadTried;
+
+#if defined(Q_OS_LINUX)
+ QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.so";
+ if (QFileInfo(lib).isExecutable()) {
+ //sendCommand("p dlopen");
+ if (qq->useFastStart())
+ sendCommand("set stop-on-solib-events 0");
+ QString flag = QString::number(RTLD_NOW);
+ sendCommand("call dlopen(\"" + lib + "\", " + flag + ")");
+ sendCommand("sharedlibrary " + dotEscape(lib));
+ if (qq->useFastStart())
+ sendCommand("set stop-on-solib-events 1");
+ }
+#endif
+#if defined(Q_OS_MAC)
+ QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.dylib";
+ if (QFileInfo(lib).isExecutable()) {
+ //sendCommand("p dlopen"); // FIXME: remove me
+ if (qq->useFastStart())
+ sendCommand("set stop-on-solib-events 0");
+ QString flag = QString::number(RTLD_NOW);
+ sendCommand("call dlopen(\"" + lib + "\", " + flag + ")");
+ sendCommand("sharedlibrary " + dotEscape(lib));
+ if (qq->useFastStart())
+ sendCommand("set stop-on-solib-events 1");
+ }
+#endif
+#if defined(Q_OS_WIN)
+ QString lib = q->m_buildDir + "/qtc-gdbmacros/debug/gdbmacros.dll";
+ if (QFileInfo(lib).exists()) {
+ if (qq->useFastStart())
+ sendCommand("set stop-on-solib-events 0");
+ //sendCommand("handle SIGSEGV pass stop print");
+ //sendCommand("set unwindonsignal off");
+ sendCommand("call LoadLibraryA(\"" + lib + "\")");
+ sendCommand("sharedlibrary " + dotEscape(lib));
+ if (qq->useFastStart())
+ sendCommand("set stop-on-solib-events 1");
+ }
+#endif
+
+ // retreive list of dumpable classes
+ sendCommand("call qDumpObjectData440(1,%1+1,0,0,0,0,0,0)",
+ GdbQueryDataDumper1);
+ // create response slot for socket data
+ sendCommand(QString(), GdbQueryDataDumper2);
+}
+
+
+IDebuggerEngine *createGdbEngine(DebuggerManager *parent)
+{
+ return new GdbEngine(parent);
+}
+
diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h
new file mode 100644
index 0000000000..bdd59cbca6
--- /dev/null
+++ b/src/plugins/debugger/gdbengine.h
@@ -0,0 +1,351 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_GDBENGINE_H
+#define DEBUGGER_GDBENGINE_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QPoint>
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QAbstractItemModel;
+class QWidget;
+QT_END_NAMESPACE
+
+#include "idebuggerengine.h"
+#include "gdbmi.h"
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerManager;
+class IDebuggerManagerAccessForEngines;
+class GdbResultRecord;
+class GdbMi;
+
+class WatchData;
+class BreakpointData;
+
+struct GdbCookie
+{
+ GdbCookie() : type(0), synchronized(false) {}
+
+ QString command;
+ int type;
+ bool synchronized;
+ QVariant cookie;
+};
+
+enum DataDumperState
+{
+ DataDumperUninitialized,
+ DataDumperLoadTried,
+ DataDumperAvailable,
+ DataDumperUnavailable,
+};
+
+// FIXME: Move to extra file?
+class GdbSettings
+{
+public:
+ GdbSettings() { m_autoRun = m_autoQuit = false; }
+
+public:
+ QString m_gdbCmd;
+ QString m_gdbEnv;
+ bool m_autoRun;
+ bool m_autoQuit;
+
+ QString m_scriptFile;
+ QMap<QString, QVariant> m_typeMacros;
+};
+
+GdbSettings &theGdbSettings();
+
+class GdbEngine : public IDebuggerEngine
+{
+ Q_OBJECT
+
+public:
+ GdbEngine(DebuggerManager *parent);
+ ~GdbEngine();
+
+signals:
+ void gdbResponseAvailable();
+ void gdbInputAvailable(const QString &prefix, const QString &msg);
+ void gdbOutputAvailable(const QString &prefix, const QString &msg);
+ void applicationOutputAvailable(const QString &prefix, const QString &msg);
+
+private:
+ //
+ // IDebuggerEngine implementation
+ //
+ void stepExec();
+ void stepOutExec();
+ void nextExec();
+ void stepIExec();
+ void nextIExec();
+
+ void shutdown();
+ void setToolTipExpression(const QPoint &pos, const QString &exp);
+ bool startDebugger();
+ void exitDebugger();
+
+ void continueInferior();
+ void runInferior();
+ void interruptInferior();
+
+ void runToLineExec(const QString &fileName, int lineNumber);
+ void runToFunctionExec(const QString &functionName);
+ void jumpToLineExec(const QString &fileName, int lineNumber);
+
+ void activateFrame(int index);
+ void selectThread(int index);
+
+ Q_SLOT void attemptBreakpointSynchronization();
+
+ void loadSessionData() {}
+ void saveSessionData() {}
+
+ void assignValueInDebugger(const QString &expr, const QString &value);
+ void executeDebuggerCommand(const QString & command);
+
+ void loadSymbols(const QString &moduleName);
+ void loadAllSymbols();
+
+ //
+ // Own stuff
+ //
+ int currentFrame() const;
+ QString currentWorkingDirectory() const { return m_pwd; }
+
+ bool supportsThreads() const;
+
+ void init(); // called by destructor
+ void queryFullName(const QString &fileName, QString *fullName);
+ QString fullName(const QString &fileName);
+ QString shortName(const QString &fullName);
+ // get one usable name out of these, try full names first
+ QString fullName(const QStringList &candidates);
+
+ void handleResult(const GdbResultRecord &, int type, const QVariant &);
+
+ // type and cookie are sender-internal data, opaque for the "event
+ // queue". resultNeeded == true increments m_pendingResults on
+ // send and decrements on receipt, effectively preventing
+ // watch model updates before everything is finished.
+ void sendCommand(const QString & command,
+ int type = 0, const QVariant &cookie = QVariant(),
+ bool needStop = false, bool synchronized = false);
+ void sendSynchronizedCommand(const QString & command,
+ int type = 0, const QVariant &cookie = QVariant(),
+ bool needStop = false);
+
+ void setTokenBarrier();
+
+ void updateLocals();
+
+private slots:
+ void setDebugDumpers(bool on);
+ void setCustomDumpersWanted(bool on);
+
+ void handleResponse();
+
+ void gdbProcError(QProcess::ProcessError error);
+ void readGdbStandardOutput();
+ void readGdbStandardError();
+
+private:
+ int terminationIndex(const QByteArray &buffer, int &length);
+ void handleStreamOutput(const QString &output, char code);
+ void handleAsyncOutput2(const GdbMi &data);
+ void handleAsyncOutput(const GdbMi &data);
+ void handleResultRecord(const GdbResultRecord &response);
+ void handleFileExecAndSymbols(const GdbResultRecord &response);
+ void handleExecRun(const GdbResultRecord &response);
+ void handleExecJumpToLine(const GdbResultRecord &response);
+ void handleExecRunToFunction(const GdbResultRecord &response);
+ void handleInfoShared(const GdbResultRecord &response);
+ void handleInfoProc(const GdbResultRecord &response);
+ void handleShowVersion(const GdbResultRecord &response);
+ void handleQueryPwd(const GdbResultRecord &response);
+ void handleQuerySources(const GdbResultRecord &response);
+ void handleQuerySources2(const GdbResultRecord &response,
+ const QVariant &);
+
+ QByteArray m_inbuffer;
+
+ QProcess m_gdbProc;
+
+ QHash<int, GdbCookie> m_cookieForToken;
+ QHash<int, QByteArray> m_customOutputForToken;
+
+ QByteArray m_pendingConsoleStreamOutput;
+ QByteArray m_pendingTargetStreamOutput;
+ QByteArray m_pendingLogStreamOutput;
+ //QByteArray m_pendingCustomValueContents;
+ QString m_pwd;
+
+ // contains the first token number for the current round
+ // of evaluation. Responses with older tokens are considers
+ // out of date and discarded.
+ int m_oldestAcceptableToken;
+
+ int m_gdbVersion; // 6.8.0 is 680
+ int m_shared;
+
+ // awful hack to keep track of used files
+ QHash<QString, QString> m_shortToFullName;
+ QHash<QString, QString> m_fullToShortName;
+
+ //
+ // Breakpoint specific stuff
+ //
+ void handleBreakList(const GdbResultRecord &record);
+ void handleBreakList(const GdbMi &table);
+ void handleBreakIgnore(const GdbResultRecord &record, int index);
+ void handleBreakInsert(const GdbResultRecord &record, int index);
+ void handleBreakInsert1(const GdbResultRecord &record, int index);
+ void handleBreakCondition(const GdbResultRecord &record, int index);
+ void handleBreakInfo(const GdbResultRecord &record, int index);
+ void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
+ void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
+ void sendInsertBreakpoint(int index);
+
+
+ //
+ // Disassembler specific stuff
+ //
+ void handleDisassemblerList(const GdbResultRecord &record,
+ const QString &cookie);
+ void reloadDisassembler();
+ QString m_address;
+
+
+ //
+ // Modules specific stuff
+ //
+ void reloadModules();
+ void handleModulesList(const GdbResultRecord &record);
+
+
+ //
+ // Register specific stuff
+ //
+ void reloadRegisters();
+ void handleRegisterListNames(const GdbResultRecord &record);
+ void handleRegisterListValues(const GdbResultRecord &record);
+
+
+ //
+ // Stack specific stuff
+ //
+ void handleStackListFrames(const GdbResultRecord &record);
+ void handleStackSelectThread(const GdbResultRecord &record, int cookie);
+ void handleStackListThreads(const GdbResultRecord &record, int cookie);
+
+
+ //
+ // Tooltip specific stuff
+ //
+ void sendToolTipCommand(const QString &command, const QString &cookie);
+
+
+ //
+ // Watch specific stuff
+ //
+ // FIXME: BaseClass. called to improve situation for a watch item
+ void updateSubItem(const WatchData &data);
+
+ void updateWatchModel();
+ Q_SLOT void updateWatchModel2();
+
+ void insertData(const WatchData &data);
+ void sendWatchParameters(const QByteArray &params0);
+ void createGdbVariable(const WatchData &data);
+
+ void handleTypeContents(const QString &output);
+ void maybeHandleInferiorPidChanged(const QString &pid);
+
+ void tryLoadCustomDumpers();
+ void runCustomDumper(const WatchData &data, bool dumpChildren);
+ bool isCustomValueDumperAvailable(const QString &type) const;
+
+ void handleVarListChildren(const GdbResultRecord &record,
+ const WatchData &cookie);
+ void handleVarCreate(const GdbResultRecord &record,
+ const WatchData &cookie);
+ void handleVarAssign();
+ void handleEvaluateExpression(const GdbResultRecord &record,
+ const WatchData &cookie);
+ void handleToolTip(const GdbResultRecord &record,
+ const QString &cookie);
+ void handleDumpCustomValue1(const GdbResultRecord &record,
+ const WatchData &cookie);
+ void handleQueryDataDumper1(const GdbResultRecord &record);
+ void handleQueryDataDumper2(const GdbResultRecord &record);
+ void handleDumpCustomValue2(const GdbResultRecord &record,
+ const WatchData &cookie);
+ void handleDumpCustomEditValue(const GdbResultRecord &record);
+ void handleDumpCustomSetup(const GdbResultRecord &record);
+ void handleStackListLocals(const GdbResultRecord &record);
+ void handleStackListArguments(const GdbResultRecord &record);
+ void handleVarListChildrenHelper(const GdbMi &child,
+ const WatchData &parent);
+ void setWatchDataType(WatchData &data, const GdbMi &mi);
+
+ QString m_editedData;
+ int m_pendingRequests;
+ int m_inferiorPid;
+
+ QStringList m_availableSimpleDumpers;
+ QString m_namespace; // namespace used in "namespaced Qt";
+
+ DataDumperState m_dataDumperState; // state of qt creator dumpers
+ QList<GdbMi> m_currentFunctionArgs;
+ QString m_currentFrame;
+ QMap<QString, QString> m_varToType;
+
+ DebuggerManager *q;
+ IDebuggerManagerAccessForEngines *qq;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_GDBENGINE_H
diff --git a/src/plugins/debugger/gdbmi.cpp b/src/plugins/debugger/gdbmi.cpp
new file mode 100644
index 0000000000..9091422ad4
--- /dev/null
+++ b/src/plugins/debugger/gdbmi.cpp
@@ -0,0 +1,473 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gdbmi.h"
+#include "assert.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+
+namespace Debugger {
+namespace Internal {
+
+QTextStream & operator<<(QTextStream & os, const GdbMi & mi)
+{
+ return os << mi.toString();
+}
+
+//static void skipSpaces(const GdbMi::Char *&from, const GdbMi::Char *to)
+//{
+// while (from != to && QChar(*from).isSpace())
+// ++from;
+//}
+
+
+void GdbMi::parseResultOrValue(const Char *&from, const Char *to)
+{
+ //skipSpaces(from, to);
+ while (from != to && QChar(*from).isSpace())
+ ++from;
+
+ //qDebug() << "parseResultOrValue: " << QByteArray::fromLatin1(from, to - from);
+ parseValue(from, to);
+ if (isValid()) {
+ //qDebug() << "no valid result in " << QByteArray::fromLatin1(from, to - from);
+ return;
+ }
+ if (from == to || *from == '(')
+ return;
+ const Char *ptr = from;
+ while (ptr < to && *ptr != '=') {
+ //qDebug() << "adding" << QChar(*ptr) << "to name";
+ ++ptr;
+ }
+ m_name = QByteArray(from, ptr - from);
+ from = ptr;
+ if (from < to && *from == '=') {
+ ++from;
+ parseValue(from, to);
+ }
+}
+
+QByteArray GdbMi::parseCString(const Char *&from, const Char *to)
+{
+ QByteArray result;
+ //qDebug() << "parseCString: " << QByteArray::fromUtf16(from, to - from);
+ if (*from != '"') {
+ qDebug() << "MI Parse Error, double quote expected";
+ return QByteArray();
+ }
+ const Char *ptr = from;
+ ++ptr;
+ while (ptr < to) {
+ if (*ptr == '"') {
+ ++ptr;
+ result = QByteArray(from + 1, ptr - from - 2);
+ break;
+ }
+ if (*ptr == '\\' && ptr < to - 1)
+ ++ptr;
+ ++ptr;
+ }
+
+ if (result.contains('\\')) {
+ if (result.contains("\\032\\032"))
+ result.clear();
+ else {
+ result = result.replace("\\n", "\n");
+ result = result.replace("\\t", "\t");
+ result = result.replace("\\\"", "\"");
+ }
+ }
+
+ from = ptr;
+ return result;
+}
+
+void GdbMi::parseValue(const Char *&from, const Char *to)
+{
+ //qDebug() << "parseValue: " << QByteArray::fromUtf16(from, to - from);
+ switch (*from) {
+ case '{':
+ parseTuple(from, to);
+ break;
+ case '[':
+ parseList(from, to);
+ break;
+ case '"':
+ m_type = Const;
+ m_data = parseCString(from, to);
+ break;
+ default:
+ break;
+ }
+}
+
+
+void GdbMi::parseTuple(const Char *&from, const Char *to)
+{
+ //qDebug() << "parseTuple: " << QByteArray::fromUtf16(from, to - from);
+ QWB_ASSERT(*from == '{', /**/);
+ ++from;
+ parseTuple_helper(from, to);
+}
+
+void GdbMi::parseTuple_helper(const Char *&from, const Char *to)
+{
+ //qDebug() << "parseTuple_helper: " << QByteArray::fromUtf16(from, to - from);
+ m_type = Tuple;
+ while (from < to) {
+ if (*from == '}') {
+ ++from;
+ break;
+ }
+ GdbMi child;
+ child.parseResultOrValue(from, to);
+ //qDebug() << "\n=======\n" << qPrintable(child.toString()) << "\n========\n";
+ if (!child.isValid())
+ return;
+ m_children += child;
+ if (*from == ',')
+ ++from;
+ }
+}
+
+void GdbMi::parseList(const Char *&from, const Char *to)
+{
+ //qDebug() << "parseList: " << QByteArray::fromUtf16(from, to - from);
+ QWB_ASSERT(*from == '[', /**/);
+ ++from;
+ m_type = List;
+ while (from < to) {
+ if (*from == ']') {
+ ++from;
+ break;
+ }
+ GdbMi child;
+ child.parseResultOrValue(from, to);
+ if (child.isValid())
+ m_children += child;
+ if (*from == ',')
+ ++from;
+ }
+}
+
+void GdbMi::setStreamOutput(const QByteArray &name, const QByteArray &content)
+{
+ if (content.isEmpty())
+ return;
+ GdbMi child;
+ child.m_type = Const;
+ child.m_name = name;
+ child.m_data = content;
+ m_children += child;
+ if (m_type == Invalid)
+ m_type = Tuple;
+}
+
+static QByteArray ind(int indent)
+{
+ return QByteArray(2 * indent, ' ');
+}
+
+void GdbMi::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);
+ }
+}
+
+QByteArray GdbMi::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 Const:
+ if (!m_name.isEmpty())
+ result += m_name + "=";
+ if (multiline) {
+ result += "\"" + m_data + "\"";
+ } else {
+ result += "\"" + m_data + "\"";
+ }
+ break;
+ case Tuple:
+ 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 List:
+ if (!m_name.isEmpty())
+ result += m_name + "=";
+ if (multiline) {
+ result += "[\n";
+ dumpChildren(&result, multiline, indent + 1);
+ result += "]";
+ } else {
+ result += "[";
+ dumpChildren(&result, multiline, indent + 1);
+ result += '\n' + ind(indent) + "]";
+ }
+ break;
+ }
+ return result;
+}
+
+void GdbMi::fromString(const QByteArray &ba)
+{
+ const Char *from = ba.constBegin();
+ const Char *to = ba.constEnd();
+ parseResultOrValue(from, to);
+}
+
+GdbMi GdbMi::findChild(const QByteArray &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 GdbMi();
+}
+
+
+GdbMi GdbMi::findChild(const QByteArray &name, const QByteArray &defaultData) const
+{
+ for (int i = 0; i < m_children.size(); ++i)
+ if (m_children.at(i).m_name == name)
+ return m_children.at(i);
+ GdbMi result;
+ result.m_data = defaultData;
+ return result;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+// GdbResultRecord
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+QByteArray stringFromResultClass(GdbResultClass resultClass)
+{
+ switch (resultClass) {
+ case GdbResultDone: return "done";
+ case GdbResultRunning: return "running";
+ case GdbResultConnected: return "connected";
+ case GdbResultError: return "error";
+ case GdbResultExit: return "exit";
+ default: return "unknown";
+ }
+};
+
+QByteArray GdbResultRecord::toString() const
+{
+ QByteArray result;
+ if (token != -1)
+ result = QByteArray::number(token);
+ result += '^';
+ result += stringFromResultClass(resultClass);
+ if (data.isValid())
+ result += ',' + data.toString();
+ result += '\n';
+ return result;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+// GdbStreamOutput
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+
+static const char test1[] =
+ "1^done,stack=[frame={level=\"0\",addr=\"0x00000000004061ca\","
+ "func=\"main\",file=\"test1.cpp\","
+ "fullname=\"/home/apoenitz/work/test1/test1.cpp\",line=\"209\"}]\n"
+ "(gdb)\n";
+
+static const char test2[] =
+ "2^done,stack=[frame={level=\"0\",addr=\"0x00002ac058675840\","
+ "func=\"QApplication\",file=\"/home/apoenitz/dev/qt/src/gui/kernel/qapplication.cpp\","
+ "fullname=\"/home/apoenitz/dev/qt/src/gui/kernel/qapplication.cpp\",line=\"592\"},"
+ "frame={level=\"1\",addr=\"0x00000000004061e0\",func=\"main\",file=\"test1.cpp\","
+ "fullname=\"/home/apoenitz/work/test1/test1.cpp\",line=\"209\"}]\n"
+ "(gdb)\n";
+
+static const char test3[] =
+ "3^done,stack=[frame={level=\"0\",addr=\"0x00000000004061ca\","
+ "func=\"main\",file=\"test1.cpp\","
+ "fullname=\"/home/apoenitz/work/test1/test1.cpp\",line=\"209\"}]\n"
+ "(gdb)\n";
+
+static const char test4[] =
+ "&\"source /home/apoenitz/dev/ide/main/bin/gdb/qt4macros\\n\"\n"
+ "4^done\n"
+ "(gdb)\n";
+
+
+static const char test5[] =
+ "1*stopped,reason=\"breakpoint-hit\",bkptno=\"1\",thread-id=\"1\","
+ "frame={addr=\"0x0000000000405738\",func=\"main\","
+ "args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0x7fff1ac78f28\"}],"
+ "file=\"test1.cpp\",fullname=\"/home/apoenitz/work/test1/test1.cpp\","
+ "line=\"209\"}\n"
+ "(gdb)\n";
+
+static const char test6[] =
+ "{u = {u = 2048, v = 16788279, w = -689265400}, a = 1, b = -689265424, c = 11063, s = {static null = {<No data fields>}, static shared_null = {ref = {value = 2}, alloc = 0, size = 0, data = 0x6098da, clean = 0, simpletext = 0, righttoleft = 0, asciiCache = 0, capacity = 0, reserved = 0, array = {0}}, static shared_empty = {ref = {value = 1}, alloc = 0, size = 0, data = 0x2b37d84f8fba, clean = 0, simpletext = 0, righttoleft = 0, asciiCache = 0, capacity = 0, reserved = 0, array = {0}}, d = 0x6098c0, static codecForCStrings = 0x0}}";
+
+static const char test8[] =
+ "8^done,data={locals={{name=\"a\"},{name=\"w\"}}}\n"
+ "(gdb)\n";
+
+static const char test9[] =
+ "9^done,data={locals=[name=\"baz\",name=\"urgs\",name=\"purgs\"]}\n"
+ "(gdb)\n";
+
+
+static const char test10[] =
+ "16^done,name=\"urgs\",numchild=\"1\",type=\"Urgs\"\n"
+ "(gdb)\n"
+ "17^done,name=\"purgs\",numchild=\"1\",type=\"Urgs *\"\n"
+ "(gdb)\n"
+ "18^done,name=\"bar\",numchild=\"0\",type=\"int\"\n"
+ "(gdb)\n"
+ "19^done,name=\"z\",numchild=\"0\",type=\"int\"\n"
+ "(gdb)\n";
+
+static const char test11[] =
+ "[{name=\"size\",value=\"1\",type=\"size_t\",readonly=\"true\"},"
+ "{name=\"0\",value=\"one\",type=\"QByteArray\"}]";
+
+static const char test12[] =
+ "{iname=\"local.hallo\",value=\"\\\"\\\"\",type=\"QByteArray\",numchild=\"0\"}";
+
+static struct Tester {
+
+ Tester() {
+ //test(test10);
+ test2(test12);
+ //test(test4);
+ //apple();
+ exit(0);
+ }
+
+ void test(const char* input)
+ {
+ //qDebug("\n<<<<\n%s\n====\n%s\n>>>>\n", input,
+ //qPrintable(GdbResponse(input).toString()));
+ }
+
+ void test2(const char* input)
+ {
+ GdbMi mi(input);
+ qDebug("\n<<<<\n%s\n====\n%s\n>>>>\n", input,
+ qPrintable(mi.toString()));
+ }
+
+ void apple()
+ {
+ QByteArray input(test9);
+/*
+ qDebug() << "input: " << input;
+ input = input.replace("{{","[");
+ input = input.replace("},{",",");
+ input = input.replace("}}","]");
+ qDebug() << "input: " << input;
+ GdbResponse response(input);
+ qDebug() << "read: " << response.toString();
+ GdbMi list = response.results[0].data.findChild("data").findChild("locals");
+ QByteArrayList locals;
+ foreach (const GdbMi &item, list.children())
+ locals.append(item.string());
+ qDebug() << "Locals (new): " << locals;
+*/
+ }
+ void parse(const QByteArray &str)
+ {
+ QByteArray result;
+ result += "\n ";
+ int indent = 0;
+ int from = 0;
+ int to = str.size();
+ if (str.size() && str[0] == '{' /*'}'*/) {
+ ++from;
+ --to;
+ }
+ for (int i = from; i < to; ++i) {
+ if (str[i] == '{')
+ result += "{\n" + QByteArray(2*++indent + 1, QChar(' '));
+ else if (str[i] == '}') {
+ if (!result.isEmpty() && result[result.size() - 1] != '\n')
+ result += "\n";
+ result += QByteArray(2*--indent + 1, QChar(' ')) + "}\n";
+ }
+ else if (str[i] == ',') {
+ if (true || !result.isEmpty() && result[result.size() - 1] != '\n')
+ result += "\n";
+ result += QByteArray(2*indent, QChar(' '));
+ }
+ else
+ result += str[i];
+ }
+ qDebug() << "result:\n" << result;
+ }
+
+} dummy;
+
+#endif
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/gdbmi.h b/src/plugins/debugger/gdbmi.h
new file mode 100644
index 0000000000..381b5ba86b
--- /dev/null
+++ b/src/plugins/debugger/gdbmi.h
@@ -0,0 +1,183 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef DEBUGGER_GDBMI_H
+#define DEBUGGER_GDBMI_H
+
+#include <qglobal.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+
+namespace Debugger {
+namespace Internal {
+
+/*
+
+output ==>
+ ( out-of-band-record )* [ result-record ] "(gdb)" nl
+result-record ==>
+ [ token ] "^" result-class ( "," result )* nl
+out-of-band-record ==>
+ async-record | stream-record
+async-record ==>
+ exec-async-output | status-async-output | notify-async-output
+exec-async-output ==>
+ [ token ] "*" async-output
+status-async-output ==>
+ [ token ] "+" async-output
+notify-async-output ==>
+ [ token ] "=" async-output
+async-output ==>
+ async-class ( "," result )* nl
+result-class ==>
+ "done" | "running" | "connected" | "error" | "exit"
+async-class ==>
+ "stopped" | others (where others will be added depending on the needs--this is still in development).
+result ==>
+ variable "=" value
+variable ==>
+ string
+value ==>
+ const | tuple | list
+const ==>
+ c-string
+tuple ==>
+ "{}" | "{" result ( "," result )* "}"
+list ==>
+ "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+stream-record ==>
+ console-stream-output | target-stream-output | log-stream-output
+console-stream-output ==>
+ "~" c-string
+target-stream-output ==>
+ "@" c-string
+log-stream-output ==>
+ "&" c-string
+nl ==>
+ CR | CR-LF
+token ==>
+ any sequence of digits.
+
+ */
+
+// FIXME: rename into GdbMiValue
+class GdbMi
+{
+public:
+ GdbMi() : m_type(Invalid) {}
+ explicit GdbMi(const QByteArray &str) { fromString(str); }
+
+ QByteArray m_name;
+ QByteArray m_data;
+ QList<GdbMi> m_children;
+
+ enum Type {
+ Invalid,
+ Const,
+ Tuple,
+ List,
+ };
+
+ 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 isConst() const { return m_type == Const; }
+ inline bool isTuple() const { return m_type == Tuple; }
+ inline bool isList() const { return m_type == List; }
+
+
+ inline QByteArray data() const { return m_data; }
+ inline const QList<GdbMi> &children() const { return m_children; }
+ inline int childCount() const { return m_children.size(); }
+
+ const GdbMi & childAt(int index) const { return m_children[index]; }
+ GdbMi & childAt(int index) { return m_children[index]; }
+ GdbMi findChild(const QByteArray &name) const;
+ GdbMi findChild(const QByteArray &name, const QByteArray &defaultString) const;
+
+ QByteArray toString(bool multiline = false, int indent = 0) const;
+ void fromString(const QByteArray &str);
+ void setStreamOutput(const QByteArray &name, const QByteArray &content);
+
+private:
+ friend class GdbResultRecord;
+ friend class GdbEngine;
+
+ //typedef ushort Char;
+ typedef char Char;
+ static QByteArray parseCString(const Char *&from, const Char *to);
+ void parseResultOrValue(const Char *&from, const Char *to);
+ void parseValue(const Char *&from, const Char *to);
+ void parseTuple(const Char *&from, const Char *to);
+ void parseTuple_helper(const Char *&from, const Char *to);
+ void parseList(const Char *&from, const Char *to);
+
+ void dumpChildren(QByteArray *str, bool multiline, int indent) const;
+};
+
+enum GdbResultClass
+{
+ // "done" | "running" | "connected" | "error" | "exit"
+ GdbResultUnknown,
+ GdbResultDone,
+ GdbResultCustomDone,
+ GdbResultRunning,
+ GdbResultConnected,
+ GdbResultError,
+ GdbResultExit,
+};
+
+class GdbResultRecord
+{
+public:
+ GdbResultRecord() : token(-1), resultClass(GdbResultUnknown) {}
+ QByteArray toString() const;
+
+ int token;
+ GdbResultClass resultClass;
+ GdbMi data;
+private:
+ friend class GdbMi;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+//Q_DECLARE_METATYPE(GdbDebugger::Internal::GdbMi);
+
+#endif // DEBUGGER_GDBMI_H
diff --git a/src/plugins/debugger/gdboptionpage.cpp b/src/plugins/debugger/gdboptionpage.cpp
new file mode 100644
index 0000000000..bee68d1833
--- /dev/null
+++ b/src/plugins/debugger/gdboptionpage.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gdboptionpage.h"
+
+#include "gdbengine.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+
+#include <QtCore/QSettings>
+#include <QtGui/QLineEdit>
+#include <QtGui/QFileDialog>
+
+using namespace Debugger::Internal;
+
+GdbOptionPage::GdbOptionPage(GdbSettings *settings)
+{
+ m_pm = ExtensionSystem::PluginManager::instance();
+ m_settings = settings;
+
+ Core::ICore *coreIFace = m_pm->getObject<Core::ICore>();
+ if (!coreIFace || !coreIFace->settings())
+ return;
+ QSettings *s = coreIFace->settings();
+ s->beginGroup("GdbOptions");
+ QString defaultCommand("gdb");
+#if defined(Q_OS_WIN32)
+ defaultCommand.append(".exe");
+#endif
+ m_settings->m_gdbCmd = s->value("Location", defaultCommand).toString();
+ m_settings->m_gdbEnv = s->value("Environment", "").toString();
+ m_settings->m_autoRun = s->value("AutoRun", true).toBool();
+ m_settings->m_autoQuit = s->value("AutoQuit", true).toBool();
+ s->endGroup();
+}
+
+QString GdbOptionPage::name() const
+{
+ return tr("Gdb");
+}
+
+QString GdbOptionPage::category() const
+{
+ return "Debugger|Gdb";
+}
+
+QString GdbOptionPage::trCategory() const
+{
+ return tr("Debugger|Gdb");
+}
+
+QWidget *GdbOptionPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+ m_ui.gdbEdit->setText(m_settings->m_gdbCmd);
+ m_ui.envEdit->setText(m_settings->m_gdbEnv);
+ m_ui.autoStartBox->setChecked(m_settings->m_autoRun);
+ m_ui.autoQuitBox->setChecked(m_settings->m_autoQuit);
+ connect(m_ui.pushButtonBrowse, SIGNAL(clicked()),
+ this, SLOT(browse()));
+
+ return w;
+}
+
+void GdbOptionPage::browse()
+{
+ QString fileName = QFileDialog::getOpenFileName(m_ui.pushButtonBrowse,
+ "Browse for gdb executable");
+ if (fileName.isEmpty())
+ return;
+ m_settings->m_gdbCmd = fileName;
+ m_ui.gdbEdit->setText(fileName);
+}
+
+void GdbOptionPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_settings->m_gdbCmd = m_ui.gdbEdit->text();
+ m_settings->m_gdbEnv = m_ui.envEdit->text();
+ m_settings->m_autoRun = m_ui.autoStartBox->isChecked();
+ m_settings->m_autoQuit = m_ui.autoQuitBox->isChecked();
+
+ Core::ICore *coreIFace = m_pm->getObject<Core::ICore>();
+ if (!coreIFace || !coreIFace->settings())
+ return;
+
+ QSettings *s = coreIFace->settings();
+
+ s->beginGroup("GdbOptions");
+ s->setValue("Location", m_settings->m_gdbCmd);
+ s->setValue("Environment", m_settings->m_gdbEnv);
+ s->setValue("AutoRun", m_settings->m_autoRun);
+ s->setValue("AutoQuit", m_settings->m_autoQuit);
+ s->endGroup();
+}
diff --git a/src/plugins/debugger/gdboptionpage.h b/src/plugins/debugger/gdboptionpage.h
new file mode 100644
index 0000000000..0a83533742
--- /dev/null
+++ b/src/plugins/debugger/gdboptionpage.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GDBOPTIONPAGE_H
+#define GDBOPTIONPAGE_H
+
+#include "ui_gdboptionpage.h"
+#include "ui_gdbtypemacros.h"
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtGui/QWidget>
+
+namespace ExtensionSystem { class PluginManager; }
+
+namespace Debugger {
+namespace Internal {
+
+class GdbSettings;
+
+class GdbOptionPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ GdbOptionPage(GdbSettings *settings);
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+public slots:
+ void browse();
+
+private:
+ ExtensionSystem::PluginManager *m_pm;
+ Ui::GdbOptionPage m_ui;
+
+ GdbSettings *m_settings;
+};
+
+class TypeMacroPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ TypeMacroPage(GdbSettings *settings);
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+private slots:
+ void onScriptButton();
+ void onAddButton();
+ void onDelButton();
+ void currentItemChanged(QTreeWidgetItem *item);
+ void updateButtonState();
+
+private:
+ ExtensionSystem::PluginManager *m_pm;
+ Ui::TypeMacroPage m_ui;
+
+ GdbSettings *m_settings;
+ QWidget *m_widget;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // GDBOPTIONPAGE_H
diff --git a/src/plugins/debugger/gdboptionpage.ui b/src/plugins/debugger/gdboptionpage.ui
new file mode 100644
index 0000000000..4b58d5d714
--- /dev/null
+++ b/src/plugins/debugger/gdboptionpage.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GdbOptionPage</class>
+ <widget class="QWidget" name="GdbOptionPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>433</width>
+ <height>216</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Gdb Debug Options</string>
+ </property>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="gdbEdit"/>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLineEdit" name="envEdit"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Gdb Location:</string>
+ </property>
+ <property name="buddy">
+ <cstring>gdbEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Environment:</string>
+ </property>
+ <property name="buddy">
+ <cstring>envEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="pushButtonBrowse">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../coreplugin/core.qrc">
+ <normaloff>:/qworkbench/images/fileopen.png</normaloff>:/qworkbench/images/fileopen.png</iconset>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="autoStartBox">
+ <property name="text">
+ <string>Auto run executable on debugger startup</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="autoQuitBox">
+ <property name="text">
+ <string>Quit debugger when the executable exits</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>415</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../coreplugin/core.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/gdbtypemacros.cpp b/src/plugins/debugger/gdbtypemacros.cpp
new file mode 100644
index 0000000000..8a35720097
--- /dev/null
+++ b/src/plugins/debugger/gdbtypemacros.cpp
@@ -0,0 +1,214 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gdboptionpage.h"
+#include "gdbengine.h"
+#include "imports.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+
+#include <QtCore/QSettings>
+#include <QtCore/QByteArray>
+#include <QtGui/QFileDialog>
+
+using namespace Debugger::Internal;
+
+TypeMacroPage::TypeMacroPage(GdbSettings *settings)
+{
+ m_pm = ExtensionSystem::PluginManager::instance();
+ m_settings = settings;
+
+ Core::ICore *coreIFace = m_pm->getObject<Core::ICore>();
+ if (!coreIFace || !coreIFace->settings())
+ return;
+
+ QSettings *s = coreIFace->settings();
+ s->beginGroup("GdbOptions");
+ if (!s->contains("ScriptFile") && !s->contains("TypeMacros")) {
+ //insert qt4 defaults
+ m_settings->m_scriptFile = coreIFace->resourcePath() +
+ QLatin1String("/gdb/qt4macros");
+ for (int i=0; i<3; ++i) {
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ switch(i) {
+ case 0:
+ stream << QString("printqstring") << (int)1;
+ m_settings->m_typeMacros.insert(QLatin1String("QString"), data);
+ break;
+ case 1:
+ stream << QString("printqcolor") << (int)0;
+ m_settings->m_typeMacros.insert(QLatin1String("QColor"), data);
+ break;
+ case 2:
+ stream << QString("printqfont") << (int)1;
+ m_settings->m_typeMacros.insert(QLatin1String("QFont"), data);
+ break;
+ }
+ }
+
+ s->setValue("ScriptFile", m_settings->m_scriptFile);
+ s->setValue("TypeMacros", m_settings->m_typeMacros);
+ } else {
+ m_settings->m_scriptFile = s->value("ScriptFile", QString()).toString();
+ m_settings->m_typeMacros = s->value("TypeMacros", QMap<QString,QVariant>()).toMap();
+ }
+ s->endGroup();
+}
+
+QString TypeMacroPage::name() const
+{
+ return tr("Type Macros");
+}
+
+QString TypeMacroPage::category() const
+{
+ return "Debugger|Gdb";
+}
+
+QString TypeMacroPage::trCategory() const
+{
+ return tr("Debugger|Gdb");
+}
+
+QWidget *TypeMacroPage::createPage(QWidget *parent)
+{
+ QString macro;
+ int index;
+
+ m_widget = new QWidget(parent);
+ m_ui.setupUi(m_widget);
+
+ connect(m_ui.addButton, SIGNAL(clicked()),
+ this, SLOT(onAddButton()));
+
+ connect(m_ui.delButton, SIGNAL(clicked()),
+ this, SLOT(onDelButton()));
+
+ connect(m_ui.scriptButton, SIGNAL(clicked()),
+ this, SLOT(onScriptButton()));
+
+ connect(m_ui.treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(currentItemChanged(QTreeWidgetItem *)));
+
+ connect(m_ui.typeEdit, SIGNAL(textChanged(const QString &)),
+ this, SLOT(updateButtonState()));
+
+ connect(m_ui.macroEdit, SIGNAL(textChanged(const QString &)),
+ this, SLOT(updateButtonState()));
+
+ QMap<QString, QVariant>::const_iterator i = m_settings->m_typeMacros.constBegin();
+ while (i != m_settings->m_typeMacros.constEnd()) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.treeWidget);
+ QDataStream stream(i.value().toByteArray());
+ stream >> macro >> index;
+ item->setText(0, i.key());
+ item->setText(1, macro);
+ item->setData(0, Qt::UserRole, index);
+ ++i;
+ }
+
+ m_ui.scriptEdit->setText(m_settings->m_scriptFile);
+
+ updateButtonState();
+
+ return m_widget;
+}
+
+void TypeMacroPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_settings->m_typeMacros.clear();
+ m_settings->m_scriptFile = m_ui.scriptEdit->text();
+
+ for (int i=0; i<m_ui.treeWidget->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = m_ui.treeWidget->topLevelItem(i);
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ stream << item->text(1) << item->data(0, Qt::UserRole).toInt();
+ m_settings->m_typeMacros.insert(item->text(0), data);
+ }
+
+ Core::ICore *coreIFace = m_pm->getObject<Core::ICore>();
+ if (coreIFace && coreIFace->settings()) {
+ QSettings *s = coreIFace->settings();
+ s->beginGroup("GdbOptions");
+ s->setValue("ScriptFile", m_settings->m_scriptFile);
+ s->setValue("TypeMacros", m_settings->m_typeMacros);
+ s->endGroup();
+ }
+}
+
+void TypeMacroPage::onScriptButton()
+{
+ QString fileName = QFileDialog::getOpenFileName(m_widget, tr("Select Gdb Script"));
+ m_ui.scriptEdit->setText(fileName);
+ updateButtonState();
+}
+
+void TypeMacroPage::onAddButton()
+{
+ if (m_ui.typeEdit->text().isEmpty() || m_ui.macroEdit->text().isEmpty())
+ return;
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.treeWidget);
+ item->setText(0, m_ui.typeEdit->text());
+ item->setText(1, m_ui.macroEdit->text());
+ item->setData(0, Qt::UserRole, m_ui.parseAsBox->currentIndex());
+
+ updateButtonState();
+}
+
+void TypeMacroPage::onDelButton()
+{
+ if (QTreeWidgetItem *item = m_ui.treeWidget->currentItem())
+ delete item;
+ updateButtonState();
+}
+
+void TypeMacroPage::currentItemChanged(QTreeWidgetItem *item)
+{
+ m_ui.typeEdit->setText(item ? item->text(0) : QString());
+ m_ui.macroEdit->setText(item ? item->text(1) : QString());
+ m_ui.parseAsBox->setCurrentIndex(item ? item->data(0, Qt::UserRole).toInt() : 0);
+ updateButtonState();
+}
+
+void TypeMacroPage::updateButtonState()
+{
+ m_ui.delButton->setEnabled(m_ui.treeWidget->currentItem() != 0);
+ m_ui.addButton->setDisabled(m_ui.typeEdit->text().isEmpty()
+ || m_ui.macroEdit->text().isEmpty());
+}
diff --git a/src/plugins/debugger/gdbtypemacros.ui b/src/plugins/debugger/gdbtypemacros.ui
new file mode 100644
index 0000000000..aa7215577b
--- /dev/null
+++ b/src/plugins/debugger/gdbtypemacros.ui
@@ -0,0 +1,186 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>TypeMacroPage</class>
+ <widget class="QWidget" name="TypeMacroPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>519</width>
+ <height>238</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Script File</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="scriptEdit" />
+ </item>
+ <item>
+ <widget class="QToolButton" name="scriptButton" >
+ <property name="minimumSize" >
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" colspan="2" >
+ <widget class="QTreeWidget" name="treeWidget" >
+ <property name="rootIsDecorated" >
+ <bool>false</bool>
+ </property>
+ <column>
+ <property name="text" >
+ <string>Type</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>Macro</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QToolButton" name="addButton" >
+ <property name="minimumSize" >
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>+</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="gdbdebugger.qrc" >:/gdbdebugger/images/newitem.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Macro Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Parse as:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="macroEdit" />
+ </item>
+ <item row="0" column="2" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="delButton" >
+ <property name="minimumSize" >
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>-</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="gdbdebugger.qrc" >:/gdbdebugger/images/delete.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="typeEdit" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QComboBox" name="parseAsBox" >
+ <item>
+ <property name="text" >
+ <string>ASCII (char *)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Unicode (short)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <resources>
+ <include location="gdbdebugger.qrc" />
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
new file mode 100644
index 0000000000..84edcb6ca5
--- /dev/null
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_IDEBUGGERENGINE_H
+#define DEBUGGER_IDEBUGGERENGINE_H
+
+#include <QtCore/QObject>
+
+namespace Debugger {
+namespace Internal {
+
+class IDebuggerEngine : public QObject
+{
+public:
+ IDebuggerEngine(QObject *parent = 0) : QObject(parent) {}
+
+ virtual void shutdown() = 0;
+ virtual void setToolTipExpression(const QPoint &pos, const QString &exp) = 0;
+ virtual bool startDebugger() = 0;
+ virtual void exitDebugger() = 0;
+ virtual void updateWatchModel() = 0;
+
+ virtual void stepExec() = 0;
+ virtual void stepOutExec() = 0;
+ virtual void nextExec() = 0;
+ virtual void stepIExec() = 0;
+ virtual void nextIExec() = 0;
+
+ virtual void continueInferior() = 0;
+ virtual void runInferior() = 0;
+ virtual void interruptInferior() = 0;
+
+ virtual void runToLineExec(const QString &fileName, int lineNumber) = 0;
+ virtual void runToFunctionExec(const QString &functionName) = 0;
+ virtual void jumpToLineExec(const QString &fileName, int lineNumber) = 0;
+ virtual void assignValueInDebugger(const QString &expr, const QString &value) = 0;
+ virtual void executeDebuggerCommand(const QString &command) = 0;
+
+ virtual void activateFrame(int index) = 0;
+ virtual void selectThread(int index) = 0;
+
+ virtual void attemptBreakpointSynchronization() = 0;
+
+ virtual void loadSessionData() = 0;
+ virtual void saveSessionData() = 0;
+
+ virtual void reloadDisassembler() = 0;
+
+ virtual void reloadModules() = 0;
+ virtual void loadSymbols(const QString &moduleName) = 0;
+ virtual void loadAllSymbols() = 0;
+
+ virtual void reloadRegisters() = 0;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_IDEBUGGERENGINE_H
diff --git a/src/plugins/debugger/images/breakpoint.svg b/src/plugins/debugger/images/breakpoint.svg
new file mode 100644
index 0000000000..e8d63cc903
--- /dev/null
+++ b/src/plugins/debugger/images/breakpoint.svg
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="14"
+ height="14"
+ id="svg2270"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="D:\depot\research\main\editor\images"
+ sodipodi:docname="breakpoint.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2272">
+ <linearGradient
+ id="linearGradient7029">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop7031" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop7033" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17794">
+ <stop
+ style="stop-color:#f18383;stop-opacity:1;"
+ offset="0"
+ id="stop17798" />
+ <stop
+ id="stop8006"
+ offset="0.3807947"
+ style="stop-color:#ed6767;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e62323;stop-opacity:1;"
+ offset="1"
+ id="stop17796" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17794"
+ id="linearGradient24732"
+ gradientUnits="userSpaceOnUse"
+ x1="472.42236"
+ y1="436.79602"
+ x2="461.39169"
+ y2="424.95065" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17794"
+ id="linearGradient2438"
+ gradientUnits="userSpaceOnUse"
+ x1="472.42236"
+ y1="436.79602"
+ x2="461.39169"
+ y2="424.95065" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17794"
+ id="radialGradient6052"
+ cx="466.73566"
+ cy="431.19708"
+ fx="466.73566"
+ fy="431.19708"
+ r="9.3095722"
+ gradientTransform="matrix(1,0,0,1.0057859,0,-2.4948735)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7029"
+ id="linearGradient7035"
+ x1="6.75"
+ y1="0.5"
+ x2="6.75"
+ y2="12.5"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="32"
+ inkscape:cx="8.6877264"
+ inkscape:cy="6.3888789"
+ inkscape:document-units="px"
+ inkscape:current-layer="g25843"
+ width="14px"
+ height="14px"
+ inkscape:window-width="1280"
+ inkscape:window-height="998"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ gridspacingx="0.5px"
+ gridspacingy="0.5px"
+ gridempspacing="2"
+ inkscape:grid-points="true" />
+ <metadata
+ id="metadata2275">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g25843"
+ transform="matrix(0.7931251,0,0,0.7931251,-372.13374,-408.22195)">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#radialGradient6052);fill-opacity:1.0;stroke:#c80000;stroke-width:1.43637741;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path22737"
+ sodipodi:cx="466.73566"
+ sodipodi:cy="431.19708"
+ sodipodi:rx="8.5913839"
+ sodipodi:ry="8.6452484"
+ d="M 475.32704 431.19708 A 8.5913839 8.6452484 0 1 1 458.14427,431.19708 A 8.5913839 8.6452484 0 1 1 475.32704 431.19708 z"
+ transform="matrix(0.8805346,0,0,0.8750503,66.41784,145.57686)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:url(#linearGradient7035);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path6058"
+ sodipodi:cx="6.75"
+ sodipodi:cy="6.5"
+ sodipodi:rx="5.75"
+ sodipodi:ry="6"
+ d="M 12.5 6.5 A 5.75 6 0 1 1 1,6.5 A 5.75 6 0 1 1 12.5 6.5 z"
+ transform="matrix(0.9867408,0,0,0.6304178,470.73423,515.01579)" />
+ </g>
+ </g>
+</svg>
diff --git a/src/plugins/debugger/images/breakpoint_pending.svg b/src/plugins/debugger/images/breakpoint_pending.svg
new file mode 100644
index 0000000000..e7094068b5
--- /dev/null
+++ b/src/plugins/debugger/images/breakpoint_pending.svg
@@ -0,0 +1,534 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="14"
+ height="14"
+ id="svg2270"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="c:\depot\research\main\editor\images"
+ sodipodi:docname="pendingbreakpoint.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2272">
+ <linearGradient
+ id="linearGradient7029">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop7031" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop7033" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient17794">
+ <stop
+ style="stop-color:#f18383;stop-opacity:1;"
+ offset="0"
+ id="stop17798" />
+ <stop
+ id="stop8006"
+ offset="0.3807947"
+ style="stop-color:#ed6767;stop-opacity:1;" />
+ <stop
+ style="stop-color:#e62323;stop-opacity:1;"
+ offset="1"
+ id="stop17796" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17794"
+ id="linearGradient24732"
+ gradientUnits="userSpaceOnUse"
+ x1="472.42236"
+ y1="436.79602"
+ x2="461.39169"
+ y2="424.95065" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17794"
+ id="linearGradient2438"
+ gradientUnits="userSpaceOnUse"
+ x1="472.42236"
+ y1="436.79602"
+ x2="461.39169"
+ y2="424.95065" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient17794"
+ id="radialGradient6052"
+ cx="466.73566"
+ cy="431.19708"
+ fx="466.73566"
+ fy="431.19708"
+ r="9.3095722"
+ gradientTransform="matrix(1,0,0,1.0057859,0,-2.4948735)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7029"
+ id="linearGradient7035"
+ x1="6.75"
+ y1="0.5"
+ x2="6.75"
+ y2="12.5"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="12.5"
+ x2="6.75"
+ y1="0.5"
+ x1="6.75"
+ id="linearGradient2228"
+ xlink:href="#linearGradient7029"
+ inkscape:collect="always" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0057859,0,-2.4948735)"
+ r="9.3095722"
+ fy="431.19708"
+ fx="466.73566"
+ cy="431.19708"
+ cx="466.73566"
+ id="radialGradient2226"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2224"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2222"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2214">
+ <stop
+ id="stop2216"
+ offset="0"
+ style="stop-color:#f18383;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ed6767;stop-opacity:1;"
+ offset="0.3807947"
+ id="stop2218" />
+ <stop
+ id="stop2220"
+ offset="1"
+ style="stop-color:#e62323;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2208">
+ <stop
+ id="stop2210"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop2212"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ gradientTransform="matrix(1.2661544,0,0,1.2608351,469.23729,510.59508)"
+ y2="10.60876"
+ x2="10.981011"
+ y1="9.9135647"
+ x1="10.946278"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4173"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(1.2608351,0,0,1.2608351,475.7834,516.59183)"
+ y2="9.578125"
+ x2="5.859375"
+ y1="6.609375"
+ x1="5.953125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4159"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="11"
+ x2="11"
+ y1="10"
+ x1="11"
+ id="linearGradient4156"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="521.00476"
+ x2="472.35138"
+ y1="519.11353"
+ x1="472.35138"
+ gradientTransform="matrix(1,0,0,1.0000093,10.421461,10.71221)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4138"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(1,0,0,0.9687523,10.283691,16.9106)"
+ gradientUnits="userSpaceOnUse"
+ y2="521.00476"
+ x2="472.35138"
+ y1="519.11353"
+ x1="472.35138"
+ id="linearGradient4134"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2293"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2291"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2285">
+ <stop
+ id="stop2287"
+ offset="0"
+ style="stop-color:#c80000;stop-opacity:1;" />
+ <stop
+ id="stop2289"
+ offset="1"
+ style="stop-color:#ffa0a0;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient25826"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient4128">
+ <stop
+ id="stop4130"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:0.78431374;" />
+ <stop
+ id="stop4132"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0.23529412;" />
+ </linearGradient>
+ <linearGradient
+ gradientTransform="matrix(1.2661544,0,0,1.2608351,469.23729,510.59508)"
+ y2="10.60876"
+ x2="10.981011"
+ y1="9.9135647"
+ x1="10.946278"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2378"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="11.147234"
+ x2="11.02502"
+ y1="9.6892195"
+ x1="10.968282"
+ id="linearGradient2376"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(1.2608351,0,0,1.2608351,475.7834,516.59183)"
+ y2="9.578125"
+ x2="5.859375"
+ y1="6.609375"
+ x1="5.953125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2374"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="11"
+ x2="11"
+ y1="10"
+ x1="11"
+ id="linearGradient2372"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="521.00476"
+ x2="472.35138"
+ y1="519.11353"
+ x1="472.35138"
+ gradientTransform="matrix(1,0,0,0.6666648,10.303108,184.09099)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2370"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="521.00476"
+ x2="472.35138"
+ y1="519.11353"
+ x1="472.35138"
+ gradientTransform="matrix(1,0,0,0.6666648,10.342666,173.98441)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2368"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="521.00476"
+ x2="472.35138"
+ y1="519.11353"
+ x1="472.35138"
+ gradientTransform="matrix(1,0,0,1.0000093,10.421461,10.71221)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2366"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(1,0,0,0.9687523,10.283691,16.9106)"
+ gradientUnits="userSpaceOnUse"
+ y2="521.00476"
+ x2="472.35138"
+ y1="519.11353"
+ x1="472.35138"
+ id="linearGradient2364"
+ xlink:href="#linearGradient4128"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2362"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2360"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2354">
+ <stop
+ id="stop2356"
+ offset="0"
+ style="stop-color:#c80000;stop-opacity:1;" />
+ <stop
+ id="stop2358"
+ offset="1"
+ style="stop-color:#ffa0a0;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ y2="424.95065"
+ x2="461.39169"
+ y1="436.79602"
+ x1="472.42236"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2352"
+ xlink:href="#linearGradient17794"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient2346">
+ <stop
+ id="stop2348"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:0.78431374;" />
+ <stop
+ id="stop2350"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0.23529412;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4128"
+ id="linearGradient2392"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.6666648,10.342666,173.98441)"
+ x1="472.35138"
+ y1="519.11353"
+ x2="472.35138"
+ y2="521.00476" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4128"
+ id="linearGradient2394"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.6666648,10.303108,184.09099)"
+ x1="472.35138"
+ y1="519.11353"
+ x2="472.35138"
+ y2="521.00476" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4128"
+ id="linearGradient2396"
+ gradientUnits="userSpaceOnUse"
+ x1="10.968282"
+ y1="9.6892195"
+ x2="11.02502"
+ y2="11.147234" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="45.254834"
+ inkscape:cx="13.678175"
+ inkscape:cy="6.8291478"
+ inkscape:document-units="px"
+ inkscape:current-layer="g25843"
+ width="14px"
+ height="14px"
+ inkscape:window-width="1280"
+ inkscape:window-height="998"
+ inkscape:window-x="44"
+ inkscape:window-y="58"
+ showgrid="true"
+ gridspacingx="0.5px"
+ gridspacingy="0.5px"
+ gridempspacing="2"
+ inkscape:grid-points="true" />
+ <metadata
+ id="metadata2275">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g25843"
+ transform="matrix(0.7931251,0,0,0.7931251,-372.13374,-408.22195)">
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#radialGradient6052);fill-opacity:1.0;stroke:#c80000;stroke-width:1.43637741;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path22737"
+ sodipodi:cx="466.73566"
+ sodipodi:cy="431.19708"
+ sodipodi:rx="8.5913839"
+ sodipodi:ry="8.6452484"
+ d="M 475.32704 431.19708 A 8.5913839 8.6452484 0 1 1 458.14427,431.19708 A 8.5913839 8.6452484 0 1 1 475.32704 431.19708 z"
+ transform="matrix(0.8805346,0,0,0.8750503,66.41784,145.57686)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:url(#linearGradient7035);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path6058"
+ sodipodi:cx="6.75"
+ sodipodi:cy="6.5"
+ sodipodi:rx="5.75"
+ sodipodi:ry="6"
+ d="M 12.5 6.5 A 5.75 6 0 1 1 1,6.5 A 5.75 6 0 1 1 12.5 6.5 z"
+ transform="matrix(0.9867408,0,0,0.6304178,470.73423,515.01579)" />
+ <g
+ id="g2380"
+ inkscape:label="Layer 1"
+ transform="matrix(1.2608365,0,0,1.2633098,469.19929,514.69071)">
+ <g
+ transform="matrix(0.7931251,0,0,0.7931251,-372.13374,-408.22195)"
+ id="g2382">
+ <path
+ style="fill:#7f7f8c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 481.17723,524.15684 C 481.17723,524.15684 482.11277,524.68766 483.0584,524.68766 C 484.00403,524.68766 484.95974,524.15684 484.95974,524.15684 L 483.4493,526.03249 L 483.4493,527.83201 L 484.8944,528.56151 L 484.95974,531.09144 L 481.17723,531.09144 L 481.16963,528.69627 L 482.71594,527.80266 L 482.72456,526.04216 L 481.17723,524.15684 z "
+ id="path2442"
+ sodipodi:nodetypes="czcccccccccc" />
+ <path
+ style="opacity:0.2;fill:#7f7f7f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 481.17723,521.00476 L 481.17723,523.52643 L 482.43807,526.0481 L 481.17723,528.56977 L 481.17723,531.72186 L 484.95974,531.72186 L 484.95974,528.56977 L 483.6989,526.0481 L 484.95974,523.52643 L 484.95974,521.00476 L 481.17723,521.00476 z "
+ id="path2444"
+ sodipodi:nodetypes="ccccccccccc" />
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccc"
+ id="path2174"
+ d="M 480.54682,520.37434 L 480.54681,523.52643 L 481.80765,526.0481 L 480.54681,528.56977 L 480.54682,531.72185 L 485.59016,531.72185 L 485.59015,528.56977 L 484.32932,526.0481 L 485.59015,523.52643 L 485.59016,520.37434 L 480.54682,520.37434 z M 481.80766,521.63517 L 484.32932,521.63517 L 484.32932,523.52643 L 483.46249,526.0481 L 484.32932,528.56977 L 484.32932,530.46102 L 481.80766,530.46102 L 481.80765,528.56977 L 482.72372,526.0481 L 481.80765,523.52643 L 481.80766,521.63517 z "
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <rect
+ ry="1.2608351"
+ y="519.7439"
+ x="479.28598"
+ height="2.5216701"
+ width="7.565001"
+ id="rect2172"
+ style="opacity:1;fill:#7f2aff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ ry="1.2608351"
+ y="529.83063"
+ x="479.28598"
+ height="2.5216701"
+ width="7.565001"
+ id="rect2170"
+ style="opacity:1;fill:#6600ff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ ry="0.63040882"
+ y="520.0589"
+ x="480.17267"
+ height="1.2608176"
+ width="5.6737618"
+ id="rect4140"
+ style="opacity:1;fill:url(#linearGradient2392);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ ry="0.63040882"
+ y="530.16577"
+ x="480.13324"
+ height="1.2608176"
+ width="5.6737618"
+ id="rect4144"
+ style="opacity:1;fill:url(#linearGradient2394);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cssz"
+ transform="matrix(1.2608351,0,0,1.2608351,469.1993,514.70058)"
+ id="path4161"
+ d="M 11.007811,9.9179701 C 10.386665,9.9257826 9.6414144,10.484263 9.5594939,10.992187 C 9.5017174,11.350414 12.494284,11.43273 12.441847,10.914063 C 12.40754,10.574731 11.628908,9.9101582 11.007811,9.9179701 z "
+ style="fill:url(#linearGradient2396);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/src/plugins/debugger/images/debugger_breakpoints.png b/src/plugins/debugger/images/debugger_breakpoints.png
new file mode 100644
index 0000000000..75bb5f15bf
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_breakpoints.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_continue_small.png b/src/plugins/debugger/images/debugger_continue_small.png
new file mode 100644
index 0000000000..4a3788c149
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_continue_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_interrupt_small.png b/src/plugins/debugger/images/debugger_interrupt_small.png
new file mode 100644
index 0000000000..815400cb58
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_interrupt_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_start.png b/src/plugins/debugger/images/debugger_start.png
new file mode 100644
index 0000000000..8eed81a899
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_start.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_start_small.png b/src/plugins/debugger/images/debugger_start_small.png
new file mode 100644
index 0000000000..4a3788c149
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_start_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_stepinto_small.png b/src/plugins/debugger/images/debugger_stepinto_small.png
new file mode 100644
index 0000000000..da36a5f670
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_stepinto_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_steponeproc_small.png b/src/plugins/debugger/images/debugger_steponeproc_small.png
new file mode 100644
index 0000000000..cf164c6604
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_steponeproc_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_stepout_small.png b/src/plugins/debugger/images/debugger_stepout_small.png
new file mode 100644
index 0000000000..e5eeeb32ad
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_stepout_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_stepover_small.png b/src/plugins/debugger/images/debugger_stepover_small.png
new file mode 100644
index 0000000000..e8a5d08046
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_stepover_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_stepoverproc_small.png b/src/plugins/debugger/images/debugger_stepoverproc_small.png
new file mode 100644
index 0000000000..34e712da06
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_stepoverproc_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/debugger_stop_small.png b/src/plugins/debugger/images/debugger_stop_small.png
new file mode 100644
index 0000000000..1063d08998
--- /dev/null
+++ b/src/plugins/debugger/images/debugger_stop_small.png
Binary files differ
diff --git a/src/plugins/debugger/images/delete.png b/src/plugins/debugger/images/delete.png
new file mode 100644
index 0000000000..e4139afc55
--- /dev/null
+++ b/src/plugins/debugger/images/delete.png
Binary files differ
diff --git a/src/plugins/debugger/images/done.png b/src/plugins/debugger/images/done.png
new file mode 100644
index 0000000000..b5238f7680
--- /dev/null
+++ b/src/plugins/debugger/images/done.png
Binary files differ
diff --git a/src/plugins/debugger/images/empty.svg b/src/plugins/debugger/images/empty.svg
new file mode 100644
index 0000000000..46209de391
--- /dev/null
+++ b/src/plugins/debugger/images/empty.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="14"
+ height="14"
+ id="svg2243"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="c:\depot\research\main\editor\images"
+ sodipodi:docname="location.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2245">
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="64"
+ inkscape:cx="8.3920091"
+ inkscape:cy="7.4257237"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="14px"
+ height="14px"
+ showborder="true"
+ inkscape:window-width="1600"
+ inkscape:window-height="1174"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ gridempspacing="2"
+ showgrid="true"
+ inkscape:grid-points="true"
+ gridspacingx="0.5px"
+ gridspacingy="0.5px" />
+ <metadata
+ id="metadata2248">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ </g>
+</svg>
diff --git a/src/plugins/debugger/images/error.png b/src/plugins/debugger/images/error.png
new file mode 100644
index 0000000000..700530438a
--- /dev/null
+++ b/src/plugins/debugger/images/error.png
Binary files differ
diff --git a/src/plugins/debugger/images/location.svg b/src/plugins/debugger/images/location.svg
new file mode 100644
index 0000000000..afb70052a1
--- /dev/null
+++ b/src/plugins/debugger/images/location.svg
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="14"
+ height="14"
+ id="svg2243"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="c:\depot\research\main\editor\images"
+ sodipodi:docname="location.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2245">
+ <linearGradient
+ id="linearGradient3134">
+ <stop
+ style="stop-color:#dcdc23;stop-opacity:1;"
+ offset="0"
+ id="stop3136" />
+ <stop
+ id="stop5080"
+ offset="0.64285713"
+ style="stop-color:#e5d044;stop-opacity:1;" />
+ <stop
+ style="stop-color:#b89354;stop-opacity:1;"
+ offset="1"
+ id="stop3138" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3137">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.86274511;"
+ offset="0"
+ id="stop3139" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3141" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3137"
+ id="linearGradient3143"
+ x1="6.5"
+ y1="3"
+ x2="6.515625"
+ y2="12.180227"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3134"
+ id="linearGradient3140"
+ x1="6.5"
+ y1="3.015625"
+ x2="6.484375"
+ y2="11.984375"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="64"
+ inkscape:cx="8.3920091"
+ inkscape:cy="7.4257237"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="14px"
+ height="14px"
+ showborder="true"
+ inkscape:window-width="1600"
+ inkscape:window-height="1174"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ gridempspacing="2"
+ showgrid="true"
+ inkscape:grid-points="true"
+ gridspacingx="0.5px"
+ gridspacingy="0.5px" />
+ <metadata
+ id="metadata2248">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:url(#linearGradient3140);fill-opacity:1.0;fill-rule:evenodd;stroke:#b18b1b;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 6.5,3 L 6.5,5.5 L 0.5,5.5 L 0.5,9.5 L 6.5,9.5 L 6.5,12 L 13.125,7.5 L 6.5,3 z "
+ id="path2216"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="fill:url(#linearGradient3143);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
+ d="M 6.5,3 L 6.5,5.5 L 0.5,5.5 L 0.5,7.5 C 7,6.5 7.5,9.5 13,7.5 L 6.5,3 z "
+ id="path5066"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+</svg>
diff --git a/src/plugins/debugger/images/newitem.png b/src/plugins/debugger/images/newitem.png
new file mode 100644
index 0000000000..7e26ea9b15
--- /dev/null
+++ b/src/plugins/debugger/images/newitem.png
Binary files differ
diff --git a/src/plugins/debugger/images/running.png b/src/plugins/debugger/images/running.png
new file mode 100644
index 0000000000..1cf8888ecb
--- /dev/null
+++ b/src/plugins/debugger/images/running.png
Binary files differ
diff --git a/src/plugins/debugger/imports.h b/src/plugins/debugger/imports.h
new file mode 100644
index 0000000000..8a2edd4c39
--- /dev/null
+++ b/src/plugins/debugger/imports.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_IMPORTS_H
+#define DEBUGGER_IMPORTS_H
+
+// FIXME: Plan is to remove this file. It's needed to get "harmless"
+// replacements for GH internals in the standalone version
+
+#ifndef GDBDEBUGGERLEAN
+
+#include <texteditor/basetextmark.h>
+
+#else
+
+#include "lean.h"
+
+#endif
+
+#endif // DEBUGGER_IMPORTS_H
diff --git a/src/plugins/debugger/mode.cpp b/src/plugins/debugger/mode.cpp
new file mode 100644
index 0000000000..2023cdd7ee
--- /dev/null
+++ b/src/plugins/debugger/mode.cpp
@@ -0,0 +1,233 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "mode.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/minisplitter.h>
+#include <coreplugin/findplaceholder.h>
+#include <coreplugin/outputpane.h>
+#include <coreplugin/navigationwidget.h>
+#include <coreplugin/rightpane.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtGui/QDockWidget>
+#include <QtGui/QLabel>
+#include <QtGui/QMainWindow>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QWidget>
+
+using namespace Core;
+using namespace ExtensionSystem;
+using namespace Debugger;
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+
+DebugMode::DebugMode(DebuggerManager *manager, QObject *parent)
+ : BaseMode(tr("Debug"), Constants::MODE_DEBUG,
+ QIcon(":/fancyactionbar/images/mode_Debug.png"),
+ Constants::P_MODE_DEBUG, 0, parent),
+ m_manager(manager)
+{
+ IDebuggerManagerAccessForDebugMode *managerAccess =
+ m_manager->debugModeInterface();
+ UniqueIDManager *uidm =
+ PluginManager::instance()->getObject<ICore>()->uniqueIDManager();
+ QList<int> context;
+ context.append(uidm->uniqueIdentifier(Core::Constants::C_EDITORMANAGER));
+ context.append(uidm->uniqueIdentifier(Constants::C_GDBDEBUGGER));
+ context.append(uidm->uniqueIdentifier(Core::Constants::C_NAVIGATION_PANE));
+ setContext(context);
+
+ QBoxLayout *editorHolderLayout = new QVBoxLayout;
+ editorHolderLayout->setMargin(0);
+ editorHolderLayout->setSpacing(0);
+ editorHolderLayout->addWidget(new EditorManagerPlaceHolder(this));
+ editorHolderLayout->addWidget(new FindToolBarPlaceHolder(this));
+
+ QWidget *editorAndFindWidget = new QWidget;
+ editorAndFindWidget->setLayout(editorHolderLayout);
+
+ MiniSplitter *rightPaneSplitter = new MiniSplitter;
+ rightPaneSplitter->addWidget(editorAndFindWidget);
+ rightPaneSplitter->addWidget(new RightPanePlaceHolder(this));
+ rightPaneSplitter->setStretchFactor(0, 1);
+ rightPaneSplitter->setStretchFactor(1, 0);
+
+ QWidget *centralWidget = new QWidget;
+ QBoxLayout *toolBarAddingLayout = new QVBoxLayout(centralWidget);
+ toolBarAddingLayout->setMargin(0);
+ toolBarAddingLayout->setSpacing(0);
+ toolBarAddingLayout->addWidget(rightPaneSplitter);
+
+ m_manager->mainWindow()->setCentralWidget(centralWidget);
+
+ MiniSplitter *splitter = new MiniSplitter;
+ splitter->addWidget(m_manager->mainWindow());
+ splitter->addWidget(new OutputPanePlaceHolder(this));
+ splitter->setStretchFactor(0, 10);
+ splitter->setStretchFactor(1, 0);
+ splitter->setOrientation(Qt::Vertical);
+
+ MiniSplitter *splitter2 = new MiniSplitter;
+ splitter2 = new MiniSplitter;
+ splitter2->addWidget(new NavigationWidgetPlaceHolder(this));
+ splitter2->addWidget(splitter);
+ splitter2->setStretchFactor(0, 0);
+ splitter2->setStretchFactor(1, 1);
+
+ setWidget(splitter2);
+
+ QToolBar *toolBar = createToolBar();
+ toolBarAddingLayout->addWidget(toolBar);
+
+ managerAccess->createDockWidgets();
+ m_manager->setSimpleDockWidgetArrangement();
+ readSettings();
+
+ connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)),
+ this, SLOT(focusCurrentEditor(Core::IMode*)));
+ widget()->setFocusProxy(EditorManager::instance());
+}
+
+DebugMode::~DebugMode()
+{
+ // Make sure the editor manager does not get deleted
+ EditorManager::instance()->setParent(0);
+}
+
+void DebugMode::shutdown()
+{
+ writeSettings();
+}
+
+QToolBar *DebugMode::createToolBar()
+{
+ IDebuggerManagerAccessForDebugMode *managerAccess =
+ m_manager->debugModeInterface();
+
+ Core::ActionManagerInterface *am =
+ ExtensionSystem::PluginManager::instance()
+ ->getObject<Core::ICore>()->actionManager();
+ QToolBar *debugToolBar = new QToolBar;
+ debugToolBar->addAction(am->command(ProjectExplorer::Constants::DEBUG)->action());
+ debugToolBar->addAction(am->command(Constants::INTERRUPT)->action());
+ debugToolBar->addAction(am->command(Constants::NEXT)->action());
+ debugToolBar->addAction(am->command(Constants::STEP)->action());
+ debugToolBar->addAction(am->command(Constants::STEPOUT)->action());
+ debugToolBar->addSeparator();
+ debugToolBar->addAction(am->command(Constants::STEPI)->action());
+ debugToolBar->addAction(am->command(Constants::NEXTI)->action());
+ debugToolBar->addSeparator();
+ debugToolBar->addWidget(new QLabel(tr("Threads:")));
+
+ QComboBox *threadBox = new QComboBox;
+ threadBox->setModel(m_manager->threadsModel());
+ connect(threadBox, SIGNAL(activated(int)),
+ managerAccess->threadsWindow(), SIGNAL(threadSelected(int)));
+ debugToolBar->addWidget(threadBox);
+
+ QWidget *stretch = new QWidget;
+ stretch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ debugToolBar->addWidget(stretch);
+
+ QMenu *viewMenu = new QMenu(debugToolBar);
+ m_toggleLockedAction = new QAction(tr("Locked"), viewMenu);
+ m_toggleLockedAction->setCheckable(true);
+ m_toggleLockedAction->setChecked(true);
+ connect(m_toggleLockedAction, SIGNAL(toggled(bool)),
+ m_manager, SLOT(setLocked(bool)));
+ foreach (QDockWidget *dockWidget, managerAccess->dockWidgets())
+ viewMenu->addAction(dockWidget->toggleViewAction());
+ viewMenu->addSeparator();
+ viewMenu->addAction(m_toggleLockedAction);
+ viewMenu->addSeparator();
+
+ QAction *resetToSimpleAction = viewMenu->addAction(tr("Reset to default layout"));
+ connect(resetToSimpleAction, SIGNAL(triggered()),
+ m_manager, SLOT(setSimpleDockWidgetArrangement()));
+ QToolButton *viewMenuButton = new QToolButton(debugToolBar);
+ viewMenuButton->setText(tr("View "));
+ viewMenuButton->setPopupMode(QToolButton::InstantPopup);
+ viewMenuButton->setMenu(viewMenu);
+ debugToolBar->addWidget(viewMenuButton);
+
+ return debugToolBar;
+}
+
+void DebugMode::focusCurrentEditor(IMode *mode)
+{
+ if (mode != this)
+ return;
+
+ EditorManager *editorManager = EditorManager::instance();
+
+ if (editorManager->currentEditor())
+ editorManager->currentEditor()->widget()->setFocus();
+}
+
+void DebugMode::writeSettings() const
+{
+ QSettings *s = settings();
+ QWB_ASSERT(m_manager, return);
+ QWB_ASSERT(m_manager->mainWindow(), return);
+ s->beginGroup(QLatin1String("DebugMode"));
+ s->setValue(QLatin1String("State"), m_manager->mainWindow()->saveState());
+ s->setValue(QLatin1String("Locked"), m_toggleLockedAction->isChecked());
+ s->endGroup();
+}
+
+void DebugMode::readSettings()
+{
+ QSettings *s = settings();
+ s->beginGroup(QLatin1String("DebugMode"));
+ m_manager->mainWindow()->restoreState(s->value(QLatin1String("State"), QByteArray()).toByteArray());
+ m_toggleLockedAction->setChecked(s->value(QLatin1String("Locked"), true).toBool());
+ s->endGroup();
+}
+
+QSettings *DebugMode::settings()
+{
+ return PluginManager::instance()->getObject<ICore>()->settings();
+}
diff --git a/src/plugins/debugger/mode.h b/src/plugins/debugger/mode.h
new file mode 100644
index 0000000000..15506d0cac
--- /dev/null
+++ b/src/plugins/debugger/mode.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_DEBUGMODE_H
+#define DEBUGGER_DEBUGMODE_H
+
+#include <coreplugin/basemode.h>
+
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QDockWidget;
+class QMainWindow;
+class QSettings;
+class QSplitter;
+class QToolBar;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerManager;
+
+class DebugMode : public Core::BaseMode
+{
+ Q_OBJECT
+
+public:
+ DebugMode(DebuggerManager *manager, QObject *parent = 0);
+ ~DebugMode();
+
+ // IMode
+ void activated();
+ void shutdown();
+ static QSettings *settings();
+
+private slots:
+ void focusCurrentEditor(Core::IMode *mode);
+
+private:
+ QToolBar *createToolBar();
+ void writeSettings() const;
+ void readSettings();
+
+ QPointer<DebuggerManager> m_manager;
+ QAction *m_toggleLockedAction;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_DEBUGMODE_H
diff --git a/src/plugins/debugger/mode.ui b/src/plugins/debugger/mode.ui
new file mode 100644
index 0000000000..da44cf38b4
--- /dev/null
+++ b/src/plugins/debugger/mode.ui
@@ -0,0 +1,76 @@
+<ui version="4.0" >
+ <class>DebugMode</class>
+ <widget class="QWidget" name="DebugMode" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>558</width>
+ <height>353</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QSplitter" name="vSplitter" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QWidget" native="1" name="editorHolder" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>10</horstretch>
+ <verstretch>10</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QWidget" name="layoutWidget" >
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="toolbarLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSplitter" name="hSplitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QTabWidget" name="bottomTabWidget" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="tabPosition" >
+ <enum>QTabWidget::South</enum>
+ </property>
+ <property name="tabShape" >
+ <enum>QTabWidget::Rounded</enum>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp
new file mode 100644
index 0000000000..458482b385
--- /dev/null
+++ b/src/plugins/debugger/moduleshandler.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "moduleshandler.h"
+
+#include "assert.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QList>
+#include <QtCore/QTextStream>
+
+#include <QtGui/QAction>
+#include <QtGui/QMainWindow>
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QSortFilterProxyModel>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+
+
+//////////////////////////////////////////////////////////////////
+//
+// ModulesModel
+//
+//////////////////////////////////////////////////////////////////
+
+class Debugger::Internal::ModulesModel : public QAbstractItemModel
+{
+public:
+ ModulesModel(ModulesHandler *parent)
+ : QAbstractItemModel(parent)
+ {}
+
+ // QAbstractItemModel
+ int columnCount(const QModelIndex &parent) const
+ { return parent.isValid() ? 0 : 4; }
+ int rowCount(const QModelIndex &parent) const
+ { return parent.isValid() ? 0 : m_modules.size(); }
+ QModelIndex parent(const QModelIndex &) const { return QModelIndex(); }
+ QModelIndex index(int row, int column, const QModelIndex &) const
+ { return createIndex(row, column); }
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role);
+
+ void clearModel() { if (!m_modules.isEmpty()) { m_modules.clear(); update(); } }
+ void update() { reset(); }
+
+public:
+ QList<Module> m_modules;
+};
+
+QVariant ModulesModel::headerData(int section,
+ Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ static QString headers[] = {
+ tr("Module name") + " ",
+ tr("Symbols read") + " ",
+ tr("Start address") + " ",
+ tr("End addAress") + " "
+ };
+ return headers[section];
+ }
+ return QVariant();
+}
+
+QVariant ModulesModel::data(const QModelIndex &index, int role) const
+{
+ //static const QIcon icon(":/gdbdebugger/images/breakpoint.svg");
+ //static const QIcon icon2(":/gdbdebugger/images/breakpoint_pending.svg");
+
+ int row = index.row();
+ if (row < 0 || row >= m_modules.size())
+ return QVariant();
+
+ const Module &module = m_modules.at(row);
+
+ switch (index.column()) {
+ case 0:
+ if (role == Qt::DisplayRole)
+ return module.moduleName;
+ // FIXME: add icons
+ //if (role == Qt::DecorationRole)
+ // return module.symbolsRead ? icon2 : icon;
+ break;
+ case 1:
+ if (role == Qt::DisplayRole)
+ return module.symbolsRead ? "yes" : "no";
+ break;
+ case 2:
+ if (role == Qt::DisplayRole)
+ return module.startAddress;
+ break;
+ case 3:
+ if (role == Qt::DisplayRole)
+ return module.endAddress;
+ break;
+ }
+ return QVariant();
+}
+
+bool ModulesModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ return QAbstractItemModel::setData(index, value, role);
+}
+
+
+//////////////////////////////////////////////////////////////////
+//
+// ModulesHandler
+//
+//////////////////////////////////////////////////////////////////
+
+ModulesHandler::ModulesHandler()
+{
+ m_model = new ModulesModel(this);
+ m_proxyModel = new QSortFilterProxyModel(this);
+ m_proxyModel->setSourceModel(m_model);
+}
+
+QAbstractItemModel *ModulesHandler::model() const
+{
+ return m_proxyModel;
+}
+
+void ModulesHandler::removeAll()
+{
+ m_model->clearModel();
+}
+
+
+void ModulesHandler::setModules(const QList<Module> &modules)
+{
+ m_model->m_modules = modules;
+ m_model->update();
+}
+
+QList<Module> ModulesHandler::modules() const
+{
+ return m_model->m_modules;
+}
diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h
new file mode 100644
index 0000000000..49efe16a72
--- /dev/null
+++ b/src/plugins/debugger/moduleshandler.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_MODULESHANDLER_H
+#define DEBUGGER_MODULESHANDLER_H
+
+#include <QtCore/QList>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+QT_END_NAMESPACE
+
+
+namespace Debugger {
+namespace Internal {
+
+class ModulesModel;
+
+enum ModulesModelRoles
+{
+ DisplaySourceRole = Qt::UserRole,
+ LoadSymbolsRole,
+ LoadAllSymbolsRole
+};
+
+
+//////////////////////////////////////////////////////////////////
+//
+// Module
+//
+//////////////////////////////////////////////////////////////////
+
+class Module
+{
+public:
+ Module() : symbolsRead(false) {}
+
+public:
+ QString moduleName;
+ bool symbolsRead;
+ QString startAddress;
+ QString endAddress;
+};
+
+
+//////////////////////////////////////////////////////////////////
+//
+// ModulesHandler
+//
+//////////////////////////////////////////////////////////////////
+
+class ModulesHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ ModulesHandler();
+
+ QAbstractItemModel *model() const;
+
+ void setModules(const QList<Module> &modules);
+ QList<Module> modules() const;
+ void removeAll();
+
+private:
+ ModulesModel *m_model;
+ QSortFilterProxyModel *m_proxyModel;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_MODULESHANDLER_H
diff --git a/src/plugins/debugger/moduleswindow.cpp b/src/plugins/debugger/moduleswindow.cpp
new file mode 100644
index 0000000000..f98db1ce1f
--- /dev/null
+++ b/src/plugins/debugger/moduleswindow.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "moduleswindow.h"
+#include "moduleshandler.h" // for model roles
+
+#include <QAction>
+#include <QDebug>
+#include <QHeaderView>
+#include <QMenu>
+#include <QResizeEvent>
+#include <QToolButton>
+
+
+using Debugger::Internal::ModulesWindow;
+
+ModulesWindow::ModulesWindow(QWidget *parent)
+ : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
+{
+ setWindowTitle(tr("Modules"));
+ setSortingEnabled(true);
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+ setIconSize(QSize(10, 10));
+}
+
+void ModulesWindow::resizeEvent(QResizeEvent *event)
+{
+ //QHeaderView *hv = header();
+ //int totalSize = event->size().width() - 110;
+ //hv->resizeSection(0, totalSize / 4);
+ //hv->resizeSection(1, totalSize / 4);
+ //hv->resizeSection(2, totalSize / 4);
+ //hv->resizeSection(3, totalSize / 4);
+ //hv->resizeSection(0, 60);
+ //hv->resizeSection(1, (totalSize * 50) / 100);
+ //hv->resizeSection(2, (totalSize * 50) / 100);
+ //hv->resizeSection(3, 50);
+ //setColumnHidden(3, true);
+ QTreeView::resizeEvent(event);
+}
+
+void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ QModelIndex index = indexAt(ev->pos());
+ index = index.sibling(index.row(), 0);
+ QString name = model()->data(index).toString();
+
+ QMenu menu;
+ QAction *act0 = new QAction("Update module list", &menu);
+ QAction *act1 = new QAction("Adjust column widths to contents", &menu);
+ QAction *act2 = new QAction("Always adjust column widths to contents", &menu);
+ act2->setCheckable(true);
+ act2->setChecked(m_alwaysResizeColumnsToContents);
+ QAction *act3 = new QAction("Show source files for module " + name, &menu);
+ QAction *act4 = new QAction("Load symbols for all modules", &menu);
+ QAction *act5 = new QAction("Load symbols for module " + name, &menu);
+ act5->setDisabled(name.isEmpty());
+
+ menu.addAction(act0);
+ menu.addAction(act4);
+ menu.addAction(act5);
+ menu.addSeparator();
+ menu.addAction(act1);
+ menu.addAction(act2);
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (act == act0)
+ emit reloadModulesRequested();
+ else if (act == act1)
+ resizeColumnsToContents();
+ else if (act == act2)
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+ else if (act == act3)
+ emit displaySourceRequested(name);
+ else if (act == act4)
+ emit loadAllSymbolsRequested();
+ else if (act == act5)
+ emit loadSymbolsRequested(name);
+}
+
+void ModulesWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+ resizeColumnToContents(2);
+}
+
+void ModulesWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ header()->setResizeMode(1, mode);
+ header()->setResizeMode(2, mode);
+ header()->setResizeMode(3, mode);
+ //setColumnHidden(3, true);
+}
+
+void ModulesWindow::setModel(QAbstractItemModel *model)
+{
+ QTreeView::setModel(model);
+ setAlwaysResizeColumnsToContents(true);
+}
+
diff --git a/src/plugins/debugger/moduleswindow.h b/src/plugins/debugger/moduleswindow.h
new file mode 100644
index 0000000000..a014ff8e6c
--- /dev/null
+++ b/src/plugins/debugger/moduleswindow.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_MODULESWINDOW_H
+#define DEBUGGER_MODULESWINDOW_H
+
+#include <QTreeView>
+
+namespace Debugger {
+namespace Internal {
+
+class ModulesWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ explicit ModulesWindow(QWidget *parent = 0);
+
+signals:
+ void reloadModulesRequested();
+ void displaySourceRequested(const QString &modulesName);
+ void loadSymbolsRequested(const QString &modulesName);
+ void loadAllSymbolsRequested();
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on);
+
+protected:
+ void resizeEvent(QResizeEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+ void setModel(QAbstractItemModel *model);
+
+private:
+ bool m_alwaysResizeColumnsToContents;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_MODULESWINDOW_H
+
diff --git a/src/plugins/debugger/procinterrupt.cpp b/src/plugins/debugger/procinterrupt.cpp
new file mode 100644
index 0000000000..29d4d5803d
--- /dev/null
+++ b/src/plugins/debugger/procinterrupt.cpp
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "procinterrupt.h"
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#include <Tlhelp32.h>
+
+using namespace Debugger::Internal;
+
+typedef HANDLE (WINAPI *PtrCreateRemoteThread)(
+ HANDLE hProcess,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ SIZE_T dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter,
+ DWORD dwCreationFlags,
+ LPDWORD lpThreadId);
+
+PtrCreateRemoteThread resolveCreateRemoteThread()
+{
+ HINSTANCE hLib = LoadLibraryA("Kernel32");
+ return (PtrCreateRemoteThread)GetProcAddress(hLib, "CreateRemoteThread");
+}
+
+DWORD findProcessId(DWORD parentId)
+{
+ HANDLE hProcList = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+ PROCESSENTRY32 procEntry;
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
+
+ DWORD procId = 0;
+
+ BOOL moreProc = Process32First(hProcList, &procEntry);
+ while (moreProc) {
+ if (procEntry.th32ParentProcessID == parentId) {
+ procId = procEntry.th32ProcessID;
+ break;
+ }
+ moreProc = Process32Next(hProcList, &procEntry);
+ }
+
+ CloseHandle(hProcList);
+ return procId;
+}
+#else
+
+#include <QtCore/QLatin1String>
+#include <QtCore/QString>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfoList>
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+
+#include <sys/types.h>
+#include <signal.h>
+
+#include <sys/sysctl.h>
+
+#define OPProcessValueUnknown UINT_MAX
+
+/* Mac OS X
+int OPParentIDForProcessID(int pid)
+ // Returns the parent process id for the given process id (pid)
+{
+ struct kinfo_proc info;
+ size_t length = sizeof(struct kinfo_proc);
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
+ if (sysctl(mib, 4, &info, &length, NULL, 0) < 0)
+ return OPProcessValueUnknown;
+ if (length == 0)
+ return OPProcessValueUnknown;
+ return info.kp_eproc.e_ppid;
+}
+*/
+
+int findParentProcess(int procId)
+{
+ QFile statFile(QLatin1String("/proc/") + QString::number(procId) +
+ QLatin1String("/stat"));
+ if (!statFile.open(QIODevice::ReadOnly))
+ return -1;
+
+ QByteArray line = statFile.readLine();
+ line = line.mid(line.indexOf(')') + 4);
+ //qDebug() << "1: " << line;
+ line = line.left(line.indexOf(' '));
+ //qDebug() << "2: " << line;
+
+ return QString(line).toInt();
+}
+
+int findChildProcess(int parentId)
+{
+ QDir proc(QLatin1String("/proc"));
+ QFileInfoList procList = proc.entryInfoList(QDir::Dirs);
+ foreach (const QFileInfo &info, procList) {
+ int procId = 0;
+ bool ok = false;
+ procId = info.baseName().toInt(&ok);
+ if (!ok || !procId)
+ continue;
+
+ if (findParentProcess(procId) == parentId)
+ return procId;
+ }
+
+ return -1;
+}
+
+#endif
+
+bool Debugger::Internal::interruptProcess(int pID)
+{
+#ifdef Q_OS_WIN
+ DWORD pid = pID;
+ if (!pid)
+ return false;
+
+ PtrCreateRemoteThread libFunc = resolveCreateRemoteThread();
+ if (libFunc) {
+ DWORD dwThreadId = 0;
+ HANDLE hproc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
+ HANDLE hthread = libFunc(hproc, NULL, 0, (LPTHREAD_START_ROUTINE)DebugBreak, 0, 0, &dwThreadId);
+ CloseHandle(hthread);
+ if (dwThreadId)
+ return true;
+ }
+#else
+ int procId = pID;
+ if (procId != -1) {
+ if (kill(procId, 2) == 0)
+ return true;
+ }
+
+#endif
+
+ return false;
+}
+
+bool Debugger::Internal::interruptChildProcess(Q_PID parentPID)
+{
+#ifdef WIN32
+ DWORD pid = findProcessId(parentPID->dwProcessId);
+ return interruptProcess(pid);
+#else
+ int procId = findChildProcess(parentPID);
+ //qDebug() << "INTERRUPTING PROCESS" << procId;
+ return interruptProcess(procId);
+#endif
+}
diff --git a/src/plugins/debugger/procinterrupt.h b/src/plugins/debugger/procinterrupt.h
new file mode 100644
index 0000000000..0fcf27b0f1
--- /dev/null
+++ b/src/plugins/debugger/procinterrupt.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_PROCINTERRUPT_H
+#define DEBUGGER_PROCINTERRUPT_H
+
+#include <QtCore/QProcess>
+
+namespace Debugger {
+namespace Internal {
+
+bool interruptProcess(int pID);
+bool interruptChildProcess(Q_PID parentPID);
+
+} // Internal
+} // GdbDebugger
+
+#endif // DEBUGGER_PROCINTERRUPT_H
diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp
new file mode 100644
index 0000000000..4c70e2339c
--- /dev/null
+++ b/src/plugins/debugger/registerhandler.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "registerhandler.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+
+#include <QtCore/QAbstractTableModel>
+#include <QtCore/QDebug>
+
+#include <QtGui/QColor>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// RegisterHandler
+//
+//////////////////////////////////////////////////////////////////
+
+RegisterHandler::RegisterHandler(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+ setProperty(PROPERTY_REGISTER_FORMAT, "x");
+}
+
+int RegisterHandler::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_registers.size();
+}
+
+int RegisterHandler::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 2;
+}
+
+QVariant RegisterHandler::data(const QModelIndex &index, int role) const
+{
+ static const QVariant red = QColor(200, 0, 0);
+ if (!index.isValid() || index.row() >= m_registers.size())
+ return QVariant();
+
+ const Register &reg = m_registers.at(index.row());
+
+ if (role == Qt::DisplayRole) {
+ switch (index.column()) {
+ case 0:
+ return reg.name;
+ case 1:
+ return reg.value;
+ }
+ }
+ if (role == Qt::TextColorRole && reg.changed && index.column() == 1)
+ return red;
+ return QVariant();
+}
+
+QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ static const char * const headers[] = {
+ QT_TR_NOOP("Name"),
+ QT_TR_NOOP("Value"),
+ };
+ if (section < 2)
+ return tr(headers[section]);
+ }
+ return QVariant();
+}
+
+void RegisterHandler::removeAll()
+{
+ m_registers.clear();
+ reset();
+}
+
+bool RegisterHandler::isEmpty() const
+{
+ return m_registers.isEmpty();
+}
+
+void RegisterHandler::setRegisters(const QList<Register> &registers)
+{
+ m_registers = registers;
+ reset();
+}
+
+QList<Register> RegisterHandler::registers() const
+{
+ return m_registers;
+}
diff --git a/src/plugins/debugger/registerhandler.h b/src/plugins/debugger/registerhandler.h
new file mode 100644
index 0000000000..933e45aad4
--- /dev/null
+++ b/src/plugins/debugger/registerhandler.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_REGISTERHANDLER_H
+#define DEBUGGER_REGISTERHANDLER_H
+
+#include <QtCore/QAbstractTableModel>
+
+namespace Debugger {
+namespace Internal {
+
+class Register
+{
+public:
+ Register() : changed(true) {}
+ Register(QString const &name_) : name(name_), changed(true) {}
+
+public:
+ QString name;
+ QString value;
+ bool changed;
+};
+
+class RegisterHandler : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ RegisterHandler(QObject *parent = 0);
+
+ void sessionClosed();
+ QAbstractItemModel *model() { return this; }
+
+ bool isEmpty() const; // nothing known so far?
+ void setRegisters(const QList<Register> &registers);
+ QList<Register> registers() const;
+ void removeAll();
+
+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;
+
+ QList<Register> m_registers;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_REGISTERHANDLER_H
diff --git a/src/plugins/debugger/registerwindow.cpp b/src/plugins/debugger/registerwindow.cpp
new file mode 100644
index 0000000000..5e53139285
--- /dev/null
+++ b/src/plugins/debugger/registerwindow.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "registerwindow.h"
+
+#include "debuggerconstants.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QDir>
+#include <QFileInfo>
+#include <QFileInfoList>
+#include <QHeaderView>
+#include <QMenu>
+#include <QResizeEvent>
+#include <QToolButton>
+
+
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+RegisterWindow::RegisterWindow()
+ : m_alwaysResizeColumnsToContents(true), m_alwaysReloadContents(false)
+{
+ setWindowTitle(tr("Registers"));
+ setSortingEnabled(true);
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+ //header()->hide();
+ //setIconSize(QSize(10, 10));
+ //setWindowIcon(QIcon(":/gdbdebugger/images/debugger_breakpoints.png"));
+ //QHeaderView *hv = header();
+ //hv->setDefaultAlignment(Qt::AlignLeft);
+ //hv->setClickable(true);
+ //hv->setSortIndicatorShown(true);
+}
+
+void RegisterWindow::resizeEvent(QResizeEvent *ev)
+{
+ //QHeaderView *hv = header();
+ //int totalSize = ev->size().width() - 110;
+ //hv->resizeSection(0, totalSize / 4);
+ //hv->resizeSection(1, totalSize / 4);
+ QTreeView::resizeEvent(ev);
+}
+
+void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ enum { Hex, Bin, Dec, Raw, Oct, Nat,
+ Adjust, AlwaysAdjust, Reload, AlwaysReload, Count };
+
+ QMenu menu;
+ QAction *actions[Count];
+ //QTreeWidgetItem *item = itemAt(ev->pos());
+ QString format = model()->property(PROPERTY_REGISTER_FORMAT).toString();
+ qDebug() << "FORMAT: " << format;
+
+ actions[Adjust] = menu.addAction("Adjust column widths to contents");
+
+ actions[AlwaysAdjust] = menu.addAction("Always adjust column widths to contents");
+ actions[AlwaysAdjust]->setCheckable(true);
+ actions[AlwaysAdjust]->setChecked(m_alwaysResizeColumnsToContents);
+
+ actions[Reload] = menu.addAction("Reload register listing");
+
+ actions[AlwaysReload] = menu.addAction("Always reload register listing");
+ actions[AlwaysReload]->setCheckable(true);
+ actions[AlwaysReload]->setChecked(m_alwaysReloadContents);
+
+ menu.addSeparator();
+
+ actions[Hex] = menu.addAction("Hexadecimal");
+ actions[Hex]->setCheckable(true);
+ actions[Hex]->setChecked(format == "h");
+
+ actions[Bin] = menu.addAction("Binary");
+ actions[Bin]->setCheckable(true);
+ actions[Bin]->setChecked(format == "t");
+
+ actions[Dec] = menu.addAction("Decimal");
+ actions[Dec]->setCheckable(true);
+ actions[Dec]->setChecked(format == "d");
+
+ actions[Raw] = menu.addAction("Raw");
+ actions[Raw]->setCheckable(true);
+ actions[Raw]->setChecked(format == "r");
+
+ actions[Nat] = menu.addAction("Natural");
+ actions[Nat]->setCheckable(true);
+ actions[Nat]->setChecked(format == "N");
+
+ actions[Oct] = menu.addAction("Octal");
+ actions[Oct]->setCheckable(true);
+ actions[Oct]->setChecked(format == "o");
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (act == actions[Adjust])
+ resizeColumnsToContents();
+ else if (act == actions[AlwaysAdjust])
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+ else if (act == actions[Reload])
+ reloadContents();
+ else if (act == actions[AlwaysReload])
+ setAlwaysReloadContents(!m_alwaysReloadContents);
+ else if (act == actions[Hex])
+ model()->setProperty(PROPERTY_REGISTER_FORMAT, "h");
+ else if (act == actions[Oct])
+ model()->setProperty(PROPERTY_REGISTER_FORMAT, "o");
+ else if (act == actions[Bin])
+ model()->setProperty(PROPERTY_REGISTER_FORMAT, "t");
+ else if (act == actions[Dec])
+ model()->setProperty(PROPERTY_REGISTER_FORMAT, "d");
+ else if (act == actions[Nat])
+ model()->setProperty(PROPERTY_REGISTER_FORMAT, "N");
+
+}
+
+void RegisterWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+}
+
+void RegisterWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ header()->setResizeMode(1, mode);
+}
+
+void RegisterWindow::setAlwaysReloadContents(bool on)
+{
+ m_alwaysReloadContents = on;
+ if (m_alwaysReloadContents)
+ reloadContents();
+}
+
+void RegisterWindow::reloadContents()
+{
+ emit reloadRegisterRequested();
+}
+
+
+void RegisterWindow::setModel(QAbstractItemModel *model)
+{
+ QTreeView::setModel(model);
+ setAlwaysResizeColumnsToContents(true);
+}
+
diff --git a/src/plugins/debugger/registerwindow.h b/src/plugins/debugger/registerwindow.h
new file mode 100644
index 0000000000..4c2cc7b7a6
--- /dev/null
+++ b/src/plugins/debugger/registerwindow.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_REGISTERWINDOW_H
+#define DEBUGGER_REGISTERWINDOW_H
+
+#include <QTreeView>
+
+namespace Debugger {
+namespace Internal {
+
+class RegisterWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ RegisterWindow();
+ void setModel(QAbstractItemModel *model);
+
+signals:
+ void reloadRegisterRequested();
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on);
+ void reloadContents();
+ void setAlwaysReloadContents(bool on);
+
+protected:
+ void resizeEvent(QResizeEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+
+private:
+ bool m_alwaysResizeColumnsToContents;
+ bool m_alwaysReloadContents;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_REGISTERWINDOW_H
+
diff --git a/src/plugins/debugger/scriptengine.cpp b/src/plugins/debugger/scriptengine.cpp
new file mode 100644
index 0000000000..c6c7dd65a5
--- /dev/null
+++ b/src/plugins/debugger/scriptengine.cpp
@@ -0,0 +1,677 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "scriptengine.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+
+#include "disassemblerhandler.h"
+#include "breakhandler.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+
+#include "startexternaldialog.h"
+#include "attachexternaldialog.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QToolTip>
+
+#include <QtScript/QScriptContext>
+#include <QtScript/QScriptClassPropertyIterator>
+#include <QtScript/QScriptContextInfo>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptEngineAgent>
+#include <QtScript/QScriptValue>
+#include <QtScript/QScriptValueIterator>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// ScriptEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+class Debugger::Internal::ScriptAgent : public QScriptEngineAgent
+{
+public:
+ ScriptAgent(ScriptEngine *debugger, QScriptEngine *script);
+ ~ScriptAgent() {}
+
+ void contextPop();
+ void contextPush();
+ void exceptionCatch(qint64 scriptId, const QScriptValue &exception);
+ void exceptionThrow(qint64 scriptId, const QScriptValue & exception,
+ bool hasHandler);
+ void functionEntry(qint64 scriptId);
+ void functionExit(qint64 scriptId, const QScriptValue &returnValue);
+ void positionChange(qint64 scriptId, int lineNumber, int columnNumber);
+ void scriptLoad(qint64 id, const QString &program, const QString &fileName,
+ int baseLineNumber);
+ void scriptUnload(qint64 id);
+
+private:
+ void maybeBreakNow(bool byFunction);
+
+ ScriptEngine *q;
+};
+
+ScriptAgent::ScriptAgent(ScriptEngine *debugger, QScriptEngine *script)
+ : QScriptEngineAgent(script), q(debugger)
+{}
+
+void ScriptAgent::contextPop()
+{
+ qDebug() << "ScriptAgent::contextPop: ";
+}
+
+void ScriptAgent::contextPush()
+{
+ qDebug() << "ScriptAgent::contextPush: ";
+}
+
+void ScriptAgent::exceptionCatch(qint64 scriptId, const QScriptValue & exception)
+{
+ qDebug() << "ScriptAgent::exceptionCatch: " << scriptId << &exception;
+}
+
+void ScriptAgent::exceptionThrow(qint64 scriptId, const QScriptValue &exception,
+ bool hasHandler)
+{
+ qDebug() << "ScriptAgent::exceptionThrow: " << scriptId << &exception
+ << hasHandler;
+}
+
+void ScriptAgent::functionEntry(qint64 scriptId)
+{
+ Q_UNUSED(scriptId);
+ q->maybeBreakNow(true);
+}
+
+void ScriptAgent::functionExit(qint64 scriptId, const QScriptValue &returnValue)
+{
+ qDebug() << "ScriptAgent::functionExit: " << scriptId << &returnValue;
+}
+
+void ScriptAgent::positionChange(qint64 scriptId, int lineNumber, int columnNumber)
+{
+ //qDebug() << "ScriptAgent::position: " << lineNumber;
+ Q_UNUSED(scriptId);
+ Q_UNUSED(lineNumber);
+ Q_UNUSED(columnNumber);
+ q->maybeBreakNow(false);
+}
+
+void ScriptAgent::scriptLoad(qint64 scriptId, const QString &program,
+ const QString &fileName, int baseLineNumber)
+{
+ Q_UNUSED(scriptId);
+ Q_UNUSED(program);
+ Q_UNUSED(fileName);
+ Q_UNUSED(baseLineNumber);
+ //qDebug() << "ScriptAgent::scriptLoad: " << program << fileName
+ // << baseLineNumber;
+}
+
+void ScriptAgent::scriptUnload(qint64 scriptId)
+{
+ Q_UNUSED(scriptId);
+ //qDebug() << "ScriptAgent::scriptUnload: " << scriptId;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// ScriptEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+ScriptEngine::ScriptEngine(DebuggerManager *parent)
+{
+ q = parent;
+ qq = parent->engineInterface();
+ m_scriptEngine = new QScriptEngine(this);
+ m_scriptAgent = new ScriptAgent(this, m_scriptEngine);
+ m_scriptEngine->setAgent(m_scriptAgent);
+ m_scriptEngine->setProcessEventsInterval(1 /*ms*/);
+}
+
+ScriptEngine::~ScriptEngine()
+{
+}
+
+void ScriptEngine::executeDebuggerCommand(const QString &command)
+{
+ Q_UNUSED(command);
+ qDebug() << "FIXME: ScriptEngine::executeDebuggerCommand()";
+}
+
+void ScriptEngine::shutdown()
+{
+ exitDebugger();
+}
+
+void ScriptEngine::exitDebugger()
+{
+ //qDebug() << " ScriptEngine::exitDebugger()";
+ m_stopped = false;
+ m_stopOnNextLine = false;
+ m_scriptEngine->abortEvaluation();
+ qq->notifyInferiorExited();
+}
+
+bool ScriptEngine::startDebugger()
+{
+ m_stopped = false;
+ m_stopOnNextLine = false;
+ m_scriptEngine->abortEvaluation();
+ QFileInfo fi(q->m_executable);
+ m_scriptFileName = fi.absoluteFilePath();
+ QFile scriptFile(m_scriptFileName);
+ if (!scriptFile.open(QIODevice::ReadOnly))
+ return false;
+ QTextStream stream(&scriptFile);
+ m_scriptContents = stream.readAll();
+ scriptFile.close();
+ attemptBreakpointSynchronization();
+ QTimer::singleShot(0, q, SLOT(notifyStartupFinished()));
+ return true;
+}
+
+void ScriptEngine::continueInferior()
+{
+ //qDebug() << "ScriptEngine::continueInferior()";
+ m_stopped = false;
+ m_stopOnNextLine = false;
+}
+
+void ScriptEngine::runInferior()
+{
+ //qDebug() << "ScriptEngine::runInferior()";
+ QScriptValue result = m_scriptEngine->evaluate(m_scriptContents, m_scriptFileName);
+}
+
+void ScriptEngine::interruptInferior()
+{
+ m_stopped = false;
+ m_stopOnNextLine = true;
+ qDebug() << "FIXME: ScriptEngine::interruptInferior()";
+}
+
+void ScriptEngine::stepExec()
+{
+ //qDebug() << "FIXME: ScriptEngine::stepExec()";
+ m_stopped = false;
+ m_stopOnNextLine = true;
+}
+
+void ScriptEngine::stepIExec()
+{
+ //qDebug() << "FIXME: ScriptEngine::stepIExec()";
+ m_stopped = false;
+ m_stopOnNextLine = true;
+}
+
+void ScriptEngine::stepOutExec()
+{
+ //qDebug() << "FIXME: ScriptEngine::stepOutExec()";
+ m_stopped = false;
+ m_stopOnNextLine = true;
+}
+
+void ScriptEngine::nextExec()
+{
+ //qDebug() << "FIXME: ScriptEngine::nextExec()";
+ m_stopped = false;
+ m_stopOnNextLine = true;
+}
+
+void ScriptEngine::nextIExec()
+{
+ //qDebug() << "FIXME: ScriptEngine::nextIExec()";
+ m_stopped = false;
+ m_stopOnNextLine = true;
+}
+
+void ScriptEngine::runToLineExec(const QString &fileName, int lineNumber)
+{
+ Q_UNUSED(fileName);
+ Q_UNUSED(lineNumber);
+ qDebug() << "FIXME: ScriptEngine::runToLineExec()";
+}
+
+void ScriptEngine::runToFunctionExec(const QString &functionName)
+{
+ Q_UNUSED(functionName);
+ qDebug() << "FIXME: ScriptEngine::runToFunctionExec()";
+}
+
+void ScriptEngine::jumpToLineExec(const QString &fileName, int lineNumber)
+{
+ Q_UNUSED(fileName);
+ Q_UNUSED(lineNumber);
+ qDebug() << "FIXME: ScriptEngine::jumpToLineExec()";
+}
+
+void ScriptEngine::activateFrame(int index)
+{
+ Q_UNUSED(index);
+}
+
+void ScriptEngine::selectThread(int index)
+{
+ Q_UNUSED(index);
+}
+
+void ScriptEngine::attemptBreakpointSynchronization()
+{
+ BreakHandler *handler = qq->breakHandler();
+ bool updateNeeded = false;
+ for (int index = 0; index != handler->size(); ++index) {
+ BreakpointData *data = handler->at(index);
+ if (data->pending) {
+ data->pending = false; // FIXME
+ updateNeeded = true;
+ }
+ if (data->bpNumber.isEmpty()) {
+ data->bpNumber = QString::number(index + 1);
+ updateNeeded = true;
+ }
+ if (!data->fileName.isEmpty() && data->markerFileName.isEmpty()) {
+ data->markerFileName = data->fileName;
+ data->markerLineNumber = data->lineNumber.toInt();
+ updateNeeded = true;
+ }
+ }
+ if (updateNeeded)
+ handler->updateMarkers();
+}
+
+void ScriptEngine::reloadDisassembler()
+{
+}
+
+void ScriptEngine::loadSymbols(const QString &moduleName)
+{
+ Q_UNUSED(moduleName);
+}
+
+void ScriptEngine::loadAllSymbols()
+{
+}
+
+void ScriptEngine::reloadModules()
+{
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Tooltip specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static WatchData m_toolTip;
+static QPoint m_toolTipPos;
+static QHash<QString, WatchData> m_toolTipCache;
+
+static bool hasLetterOrNumber(const QString &exp)
+{
+ for (int i = exp.size(); --i >= 0; )
+ if (exp[i].isLetterOrNumber())
+ return true;
+ return false;
+}
+
+static bool hasSideEffects(const QString &exp)
+{
+ // FIXME: complete?
+ return exp.contains("-=")
+ || exp.contains("+=")
+ || exp.contains("/=")
+ || exp.contains("*=")
+ || exp.contains("&=")
+ || exp.contains("|=")
+ || exp.contains("^=")
+ || exp.contains("--")
+ || exp.contains("++");
+}
+
+void ScriptEngine::setToolTipExpression(const QPoint &pos, const QString &exp0)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(exp0);
+
+ if (q->status() != DebuggerInferiorStopped) {
+ //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED";
+ return;
+ }
+
+ //m_toolTipPos = pos;
+ QString exp = exp0;
+
+/*
+ if (m_toolTipCache.contains(exp)) {
+ const WatchData & data = m_toolTipCache[exp];
+ q->watchHandler()->removeChildren(data.iname);
+ insertData(data);
+ return;
+ }
+*/
+
+ QToolTip::hideText();
+ if (exp.isEmpty() || exp.startsWith("#")) {
+ QToolTip::hideText();
+ return;
+ }
+
+ if (!hasLetterOrNumber(exp)) {
+ QToolTip::showText(m_toolTipPos,
+ "'" + exp + "' contains no identifier");
+ return;
+ }
+
+ if (exp.startsWith('"') && exp.endsWith('"')) {
+ QToolTip::showText(m_toolTipPos, "String literal " + exp);
+ return;
+ }
+
+ if (exp.startsWith("++") || exp.startsWith("--"))
+ exp = exp.mid(2);
+
+ if (exp.endsWith("++") || exp.endsWith("--"))
+ exp = exp.mid(2);
+
+ if (exp.startsWith("<") || exp.startsWith("["))
+ return;
+
+ if (hasSideEffects(exp)) {
+ QToolTip::showText(m_toolTipPos,
+ "Cowardly refusing to evaluate expression '" + exp
+ + "' with potential side effects");
+ return;
+ }
+
+#if 0
+ //if (m_manager->status() != DebuggerInferiorStopped)
+ // return;
+
+ // FIXME: 'exp' can contain illegal characters
+ m_toolTip = WatchData();
+ m_toolTip.exp = exp;
+ m_toolTip.name = exp;
+ m_toolTip.iname = tooltipIName;
+ insertData(m_toolTip);
+#endif
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Watch specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void ScriptEngine::assignValueInDebugger(const QString &expression,
+ const QString &value)
+{
+ Q_UNUSED(expression);
+ Q_UNUSED(value);
+}
+
+void ScriptEngine::maybeBreakNow(bool byFunction)
+{
+ QScriptContext *context = m_scriptEngine->currentContext();
+ QScriptContextInfo info(context);
+
+ //
+ // Update breakpoints
+ //
+ QString functionName = info.functionName();
+ QString fileName = info.fileName();
+ int lineNumber = info.lineNumber();
+ if (byFunction)
+ lineNumber = info.functionStartLineNumber();
+
+ BreakHandler *handler = qq->breakHandler();
+
+ if (m_stopOnNextLine) {
+ m_stopOnNextLine = false;
+ } else {
+ int index = 0;
+ for (; index != handler->size(); ++index) {
+ BreakpointData *data = handler->at(index);
+ if (byFunction) {
+ if (!functionName.isEmpty() && data->funcName == functionName)
+ break;
+ } else {
+ if (info.lineNumber() == data->lineNumber.toInt()
+ && fileName == data->fileName)
+ break;
+ }
+ }
+
+ if (index == handler->size())
+ return;
+
+ // we just run into a breakpoint
+ //qDebug() << "RESOLVING BREAKPOINT AT " << fileName << lineNumber;
+ BreakpointData *data = handler->at(index);
+ data->bpLineNumber = QString::number(lineNumber);
+ data->bpFileName = fileName;
+ data->bpFuncName = functionName;
+ data->markerLineNumber = lineNumber;
+ data->markerFileName = fileName;
+ data->pending = false;
+ data->updateMarker();
+ }
+
+ qq->notifyInferiorStopped();
+ q->gotoLocation(fileName, lineNumber, true);
+
+ qq->watchHandler()->reinitializeWatchers();
+ //qDebug() << "UPDATE LOCALS";
+
+ //
+ // Build stack
+ //
+ QList<StackFrame> stackFrames;
+ int i = 0;
+ for (QScriptContext *c = context; c; c = c->parentContext(), ++i) {
+ QScriptContextInfo info(c);
+ StackFrame frame;
+ frame.level = i;
+ frame.file = info.fileName();
+ frame.function = info.functionName();
+ frame.from = QString::number(info.functionStartLineNumber());
+ frame.to = QString::number(info.functionEndLineNumber());
+ frame.line = info.lineNumber();
+
+ if (frame.function.isEmpty())
+ frame.function = "<global scope>";
+ //frame.address = ...;
+ stackFrames.append(frame);
+ }
+ qq->stackHandler()->setFrames(stackFrames);
+
+ //
+ // Build locals
+ //
+ WatchData data;
+ data.iname = "local";
+ data.name = "local";
+ data.scriptValue = context->activationObject();
+ qq->watchHandler()->insertData(data);
+ updateWatchModel();
+
+ // FIXME: Use an extra thread. This here is evil
+ m_stopped = true;
+ while (m_stopped) {
+ //qDebug() << "LOOPING";
+ QApplication::processEvents();
+ }
+ //qDebug() << "RUNNING AGAIN";
+}
+
+void ScriptEngine::updateWatchModel()
+{
+ while (true) {
+ QList<WatchData> list = qq->watchHandler()->takeCurrentIncompletes();
+ if (list.isEmpty())
+ break;
+ foreach (const WatchData &data, list)
+ updateSubItem(data);
+ }
+ qq->watchHandler()->rebuildModel();
+ q->showStatusMessage(tr("Stopped."), 5000);
+}
+
+void ScriptEngine::updateSubItem(const WatchData &data0)
+{
+ WatchData data = data0;
+ //qDebug() << "\nUPDATE SUBITEM: " << data.toString();
+ QWB_ASSERT(data.isValid(), return);
+
+ if (data.isTypeNeeded() || data.isValueNeeded()) {
+ QScriptValue ob = data.scriptValue;
+ if (ob.isArray()) {
+ data.setType("Array");
+ data.setValue(" ");
+ } else if (ob.isBool()) {
+ data.setType("Bool");
+ data.setValue(ob.toBool() ? "true" : "false");
+ data.setChildCount(0);
+ } else if (ob.isDate()) {
+ data.setType("Date");
+ data.setValue(ob.toDateTime().toString().toUtf8());
+ data.setChildCount(0);
+ } else if (ob.isError()) {
+ data.setType("Error");
+ data.setValue(" ");
+ } else if (ob.isFunction()) {
+ data.setType("Function");
+ data.setValue(" ");
+ } else if (ob.isNull()) {
+ data.setType("<null>");
+ data.setValue("<null>");
+ } else if (ob.isNumber()) {
+ data.setType("Number");
+ data.setValue(QString::number(ob.toNumber()).toUtf8());
+ data.setChildCount(0);
+ } else if (ob.isObject()) {
+ data.setType("Object");
+ data.setValue(" ");
+ } else if (ob.isQMetaObject()) {
+ data.setType("QMetaObject");
+ data.setValue(" ");
+ } else if (ob.isQObject()) {
+ data.setType("QObject");
+ data.setValue(" ");
+ } else if (ob.isRegExp()) {
+ data.setType("RegExp");
+ data.setValue(ob.toRegExp().pattern().toUtf8());
+ } else if (ob.isString()) {
+ data.setType("String");
+ data.setValue(ob.toString().toUtf8());
+ } else if (ob.isVariant()) {
+ data.setType("Variant");
+ data.setValue(" ");
+ } else if (ob.isUndefined()) {
+ data.setType("<undefined>");
+ data.setValue("<unknown>");
+ } else {
+ data.setType("<unknown>");
+ data.setValue("<unknown>");
+ }
+ qq->watchHandler()->insertData(data);
+ return;
+ }
+
+ if (data.isChildrenNeeded()) {
+ int numChild = 0;
+ QScriptValueIterator it(data.scriptValue);
+ while (it.hasNext()) {
+ it.next();
+ WatchData data1;
+ data1.iname = data.iname + "." + it.name();
+ data1.name = it.name();
+ data1.scriptValue = it.value();
+ if (qq->watchHandler()->isExpandedIName(data1.iname))
+ data1.setChildrenNeeded();
+ else
+ data1.setChildrenUnneeded();
+ qq->watchHandler()->insertData(data1);
+ ++numChild;
+ }
+ //qDebug() << " ... CHILDREN: " << numChild;
+ data.setChildCount(numChild);
+ data.setChildrenUnneeded();
+ qq->watchHandler()->insertData(data);
+ return;
+ }
+
+ if (data.isChildCountNeeded()) {
+ int numChild = 0;
+ QScriptValueIterator it(data.scriptValue);
+ while (it.hasNext()) {
+ it.next();
+ ++numChild;
+ }
+ data.setChildCount(numChild);
+ //qDebug() << " ... CHILDCOUNT: " << numChild;
+ qq->watchHandler()->insertData(data);
+ return;
+ }
+
+ QWB_ASSERT(false, return);
+}
+
+IDebuggerEngine *createScriptEngine(DebuggerManager *parent)
+{
+ return new ScriptEngine(parent);
+}
+
diff --git a/src/plugins/debugger/scriptengine.h b/src/plugins/debugger/scriptengine.h
new file mode 100644
index 0000000000..69cb440570
--- /dev/null
+++ b/src/plugins/debugger/scriptengine.h
@@ -0,0 +1,134 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_SCRIPTENGINE_H
+#define DEBUGGER_SCRIPTENGINE_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QPoint>
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+
+#include <QtNetwork/QLocalSocket>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QAbstractItemModel;
+class QSplitter;
+class QToolBar;
+class QScriptEngine;
+class QScriptValue;
+QT_END_NAMESPACE
+
+#include "idebuggerengine.h"
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerManager;
+class IDebuggerManagerAccessForEngines;
+class ScriptAgent;
+class WatchData;
+
+class ScriptEngine : public IDebuggerEngine
+{
+ Q_OBJECT
+
+public:
+ ScriptEngine(DebuggerManager *parent);
+ ~ScriptEngine();
+
+private:
+ // IDebuggerEngine implementation
+ void stepExec();
+ void stepOutExec();
+ void nextExec();
+ void stepIExec();
+ void nextIExec();
+
+ void shutdown();
+ void setToolTipExpression(const QPoint &pos, const QString &exp);
+ bool startDebugger();
+ void exitDebugger();
+
+ void continueInferior();
+ void runInferior();
+ void interruptInferior();
+
+ void runToLineExec(const QString &fileName, int lineNumber);
+ void runToFunctionExec(const QString &functionName);
+ void jumpToLineExec(const QString &fileName, int lineNumber);
+
+ void activateFrame(int index);
+ void selectThread(int index);
+
+ void attemptBreakpointSynchronization();
+
+ void loadSessionData() {}
+ void saveSessionData() {}
+
+ void assignValueInDebugger(const QString &expr, const QString &value);
+ void executeDebuggerCommand(const QString & command);
+
+ void loadSymbols(const QString &moduleName);
+ void loadAllSymbols();
+ void reloadDisassembler();
+ void reloadModules();
+ void reloadRegisters() {}
+
+ bool supportsThreads() const { return true; }
+ void maybeBreakNow(bool byFunction);
+ void updateWatchModel();
+ void updateSubItem(const WatchData &data0);
+
+private:
+ friend class ScriptAgent;
+ DebuggerManager *q;
+ IDebuggerManagerAccessForEngines *qq;
+
+ QScriptEngine *m_scriptEngine;
+ QString m_scriptContents;
+ QString m_scriptFileName;
+ ScriptAgent *m_scriptAgent;
+
+ bool m_stopped;
+ bool m_stopOnNextLine;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_SCRIPTENGINE_H
diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp
new file mode 100644
index 0000000000..d05e259c09
--- /dev/null
+++ b/src/plugins/debugger/stackhandler.cpp
@@ -0,0 +1,271 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "stackhandler.h"
+
+#include "assert.h"
+
+#include <QtCore/QAbstractTableModel>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+
+using namespace Debugger::Internal;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// StackHandler
+//
+////////////////////////////////////////////////////////////////////////
+
+StackHandler::StackHandler(QObject *parent)
+ : QAbstractTableModel(parent), m_currentIndex(0)
+{
+ m_emptyIcon = QIcon(":/gdbdebugger/images/empty.svg");
+ m_positionIcon = QIcon(":/gdbdebugger/images/location.svg");
+}
+
+int StackHandler::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_stackFrames.size();
+}
+
+int StackHandler::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : 4;
+}
+
+QVariant StackHandler::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= m_stackFrames.size())
+ return QVariant();
+
+ const StackFrame &frame = m_stackFrames.at(index.row());
+
+ if (role == Qt::DisplayRole) {
+ switch (index.column()) {
+ case 0: // Stack frame level
+ return QString::number(frame.level);
+ case 1: // Function name
+ return frame.function;
+ case 2: // File name
+ return frame.file.isEmpty() ? frame.from : QFileInfo(frame.file).fileName();
+ case 3: // Line number
+ return frame.line;
+ case 4: // Address
+ return frame.address;
+ }
+ } else if (role == Qt::ToolTipRole) {
+ return "<table><tr><td>Address:</td><td>" + frame.address + "</td></tr>"
+ + "<tr><td>Function: </td><td>" + frame.function + "</td></tr>"
+ + "<tr><td>File: </td><td>" + frame.file + "</td></tr>"
+ + "<tr><td>Line: </td><td>" + QString::number(frame.line) + "</td></tr>"
+ + "<tr><td>From: </td><td>" + frame.from + "</td></tr></table>"
+ + "<tr><td>To: </td><td>" + frame.to + "</td></tr></table>";
+ } 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 StackHandler::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ static const char * const headers[] = {
+ QT_TR_NOOP("Level"),
+ QT_TR_NOOP("Function"),
+ QT_TR_NOOP("File"),
+ QT_TR_NOOP("Line"),
+ QT_TR_NOOP("Address")
+ };
+ if (section < 5)
+ return tr(headers[section]);
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags StackHandler::flags(const QModelIndex &index) const
+{
+ if (index.row() >= m_stackFrames.size())
+ return 0;
+ const StackFrame &frame = m_stackFrames.at(index.row());
+ const bool isValid = !frame.file.isEmpty() && !frame.function.isEmpty();
+ return isValid ? QAbstractTableModel::flags(index) : Qt::ItemFlags(0);
+}
+
+StackFrame StackHandler::currentFrame() const
+{
+ QWB_ASSERT(m_currentIndex >= 0, return StackFrame());
+ QWB_ASSERT(m_currentIndex < m_stackFrames.size(), return StackFrame());
+ return m_stackFrames.at(m_currentIndex);
+}
+
+void StackHandler::setCurrentIndex(int level)
+{
+ if (level == m_currentIndex)
+ return;
+
+ // Emit changed for previous frame
+ QModelIndex i = index(m_currentIndex, 0);
+ emit dataChanged(i, i);
+
+ m_currentIndex = level;
+
+ // Emit changed for new frame
+ i = index(m_currentIndex, 0);
+ emit dataChanged(i, i);
+}
+
+void StackHandler::removeAll()
+{
+ m_stackFrames.clear();
+ m_currentIndex = 0;
+ reset();
+}
+
+void StackHandler::setFrames(const QList<StackFrame> &frames)
+{
+ m_stackFrames = frames;
+ if (m_currentIndex >= m_stackFrames.size())
+ m_currentIndex = m_stackFrames.size() - 1;
+ reset();
+}
+
+QList<StackFrame> StackHandler::frames() const
+{
+ return m_stackFrames;
+}
+
+bool StackHandler::isDebuggingDumpers() const
+{
+ for (int i = m_stackFrames.size(); --i >= 0; )
+ if (m_stackFrames.at(i).function.startsWith("qDumpObjectData"))
+ return true;
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+////////////////////////////////////////////////////////////////////////
+
+ThreadsHandler::ThreadsHandler(QObject *parent)
+ : QAbstractTableModel(parent), m_currentIndex(0)
+{
+ m_emptyIcon = QIcon(":/gdbdebugger/images/empty.svg");
+ m_positionIcon = QIcon(":/gdbdebugger/images/location.svg");
+}
+
+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 : 1;
+}
+
+QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= m_threads.size())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ switch (index.column()) {
+ case 0: // Thread ID
+ return m_threads.at(index.row()).id;
+ case 1: // Function name
+ return "???";
+ }
+ } else if (role == Qt::ToolTipRole) {
+ return "Thread: " + QString::number(m_threads.at(index.row()).id);
+ } 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) {
+ static const char * const headers[] = {
+ QT_TR_NOOP("Thread ID"),
+ };
+ if (section < 1)
+ return tr(headers[section]);
+ }
+ 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();
+}
diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h
new file mode 100644
index 0000000000..81a4686f68
--- /dev/null
+++ b/src/plugins/debugger/stackhandler.h
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_STACKHANDLER_H
+#define DEBUGGER_STACKHANDLER_H
+
+#include <QtCore/QAbstractTableModel>
+#include <QtCore/QObject>
+
+#include <QtGui/QIcon>
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// StackModel
+//
+////////////////////////////////////////////////////////////////////////
+
+struct StackFrame
+{
+ int level;
+ QString function;
+ QString file; // we try to put an absolute file name in there
+ QString from;
+ QString to;
+ int line;
+ QString address;
+};
+
+/*! A model to represent the stack in a QTreeView. */
+class StackHandler : public QAbstractTableModel
+{
+public:
+ StackHandler(QObject *parent = 0);
+
+ void setFrames(const QList<StackFrame> &frames);
+ QList<StackFrame> frames() const;
+ void setCurrentIndex(int index);
+ int currentIndex() const { return m_currentIndex; }
+ StackFrame currentFrame() const;
+ int stackSize() const { return m_stackFrames.size(); }
+
+ // Called from StackHandler after a new stack list has been received
+ void removeAll();
+ QAbstractItemModel *stackModel() { return this; }
+ bool isDebuggingDumpers() const;
+
+private:
+ // QAbstractTableModel
+ 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;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ QList<StackFrame> m_stackFrames;
+ int m_currentIndex;
+ QIcon m_positionIcon;
+ QIcon m_emptyIcon;
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+////////////////////////////////////////////////////////////////////////
+
+struct ThreadData
+{
+ int id;
+};
+
+/*! A model to represent the running threads in a QTreeView or ComboBox */
+class ThreadsHandler : public QAbstractTableModel
+{
+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; }
+
+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:
+ friend class StackHandler;
+ QList<ThreadData> m_threads;
+ int m_currentIndex;
+ QIcon m_positionIcon;
+ QIcon m_emptyIcon;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_STACKHANDLER_H
diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp
new file mode 100644
index 0000000000..3dc1209a00
--- /dev/null
+++ b/src/plugins/debugger/stackwindow.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "stackwindow.h"
+
+#include "assert.h"
+#include "stackhandler.h"
+
+#include <QAction>
+#include <QComboBox>
+#include <QDebug>
+#include <QHeaderView>
+#include <QMenu>
+#include <QResizeEvent>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+using Debugger::Internal::StackWindow;
+
+StackWindow::StackWindow(QWidget *parent)
+ : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
+{
+ setWindowTitle(tr("Stack"));
+
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+ setIconSize(QSize(10, 10));
+
+ header()->setDefaultAlignment(Qt::AlignLeft);
+
+ connect(this, SIGNAL(activated(QModelIndex)),
+ this, SLOT(rowActivated(QModelIndex)));
+}
+
+void StackWindow::resizeEvent(QResizeEvent *event)
+{
+ QHeaderView *hv = header();
+ int totalSize = event->size().width() - 120;
+ if (totalSize > 10) {
+ hv->resizeSection(0, 45);
+ hv->resizeSection(1, totalSize / 2);
+ hv->resizeSection(2, totalSize / 2);
+ hv->resizeSection(3, 55);
+ }
+ QTreeView::resizeEvent(event);
+}
+
+void StackWindow::rowActivated(const QModelIndex &index)
+{
+ //qDebug() << "ACTIVATED: " << index.row() << index.column();
+ emit frameActivated(index.row());
+}
+
+void StackWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ QMenu menu;
+ QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
+ QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
+ act2->setCheckable(true);
+ act2->setChecked(m_alwaysResizeColumnsToContents);
+
+ menu.addAction(act1);
+ menu.addAction(act2);
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (act == act1)
+ resizeColumnsToContents();
+ else if (act == act2)
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+}
+
+void StackWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+ resizeColumnToContents(2);
+}
+
+void StackWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ header()->setResizeMode(1, mode);
+ header()->setResizeMode(2, mode);
+}
diff --git a/src/plugins/debugger/stackwindow.h b/src/plugins/debugger/stackwindow.h
new file mode 100644
index 0000000000..5edfeb3fb6
--- /dev/null
+++ b/src/plugins/debugger/stackwindow.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_STACKWINDOW_H
+#define DEBUGGER_STACKWINDOW_H
+
+#include <QtGui/QTreeView>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QComboBox;
+class QModelIndex;
+QT_END_NAMESPACE
+
+namespace Debugger {
+namespace Internal {
+
+class StackWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ StackWindow(QWidget *parent = 0);
+
+signals:
+ void frameActivated(int);
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on);
+
+private slots:
+ void rowActivated(const QModelIndex &index);
+
+private:
+ void resizeEvent(QResizeEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+
+ bool m_alwaysResizeColumnsToContents;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_STACKWINDOW_H
+
diff --git a/src/plugins/debugger/startexternaldialog.cpp b/src/plugins/debugger/startexternaldialog.cpp
new file mode 100644
index 0000000000..c87982ab1d
--- /dev/null
+++ b/src/plugins/debugger/startexternaldialog.cpp
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "startexternaldialog.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QPushButton>
+
+using namespace Debugger::Internal;
+
+StartExternalDialog::StartExternalDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+ //execLabel->setHidden(false);
+ //execEdit->setHidden(false);
+ //browseButton->setHidden(false);
+
+ execLabel->setText(tr("Executable:"));
+ argLabel->setText(tr("Arguments:"));
+
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ connect(browseButton, SIGNAL(clicked()),
+ this, SLOT(onBrowseButton()));
+}
+
+void StartExternalDialog::setExecutableFile(const QString &str)
+{
+ execEdit->setText(str);
+}
+
+void StartExternalDialog::setExecutableArguments(const QString &str)
+{
+ argsEdit->setText(str);
+}
+
+QString StartExternalDialog::executableFile() const
+{
+ return execEdit->text();
+}
+
+QString StartExternalDialog::executableArguments() const
+{
+ return argsEdit->text();
+ /*
+ bool inQuotes = false;
+ QString args = argsEdit->text();
+ QChar current;
+ QChar last;
+ QString arg;
+
+ QStringList result;
+ if (!args.isEmpty())
+ result << QLatin1String("--args");
+ result << execEdit->text();
+
+ for(int i=0; i<args.length(); ++i) {
+ current = args.at(i);
+
+ if (current == QLatin1Char('\"') && last != QLatin1Char('\\')) {
+ if (inQuotes && !arg.isEmpty()) {
+ result << arg;
+ arg.clear();
+ }
+ inQuotes = !inQuotes;
+ } else if (!inQuotes && current == QLatin1Char(' ')) {
+ arg = arg.trimmed();
+ if (!arg.isEmpty()) {
+ result << arg;
+ arg.clear();
+ }
+ } else {
+ arg += current;
+ }
+
+ last = current;
+ }
+
+ if (!arg.isEmpty())
+ result << arg;
+
+ return result;
+ */
+}
+
+void StartExternalDialog::onBrowseButton()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select Executable"),
+ execEdit->text());
+ execEdit->setText(fileName);
+}
diff --git a/src/plugins/debugger/startexternaldialog.h b/src/plugins/debugger/startexternaldialog.h
new file mode 100644
index 0000000000..10a43670db
--- /dev/null
+++ b/src/plugins/debugger/startexternaldialog.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_STARTEXTERNALDIALOG_H
+#define DEBUGGER_STARTEXTERNALDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_startexternaldialog.h"
+
+namespace Debugger {
+namespace Internal {
+
+class StartExternalDialog : public QDialog, Ui::StartExternalDialog
+{
+ Q_OBJECT
+
+public:
+ StartExternalDialog(QWidget *parent);
+
+ void setExecutableFile(const QString &executable);
+ void setExecutableArguments(const QString &args);
+
+ QString executableFile() const;
+ QString executableArguments() const;
+
+private slots:
+ void onBrowseButton();
+};
+
+} // namespace Debugger
+} // namespace Internal
+
+#endif // DEBUGGER_STARTEXTERNALDIALOG_H
diff --git a/src/plugins/debugger/startexternaldialog.ui b/src/plugins/debugger/startexternaldialog.ui
new file mode 100644
index 0000000000..7888db2a3e
--- /dev/null
+++ b/src/plugins/debugger/startexternaldialog.ui
@@ -0,0 +1,93 @@
+<ui version="4.0" >
+ <class>StartExternalDialog</class>
+ <widget class="QDialog" name="StartExternalDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>425</width>
+ <height>127</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="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="argsEdit" />
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="execEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="execLabel" >
+ <property name="text" >
+ <string>Executable:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QToolButton" name="browseButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="argLabel" >
+ <property name="text" >
+ <string>Arguments:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>407</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </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>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/threadswindow.cpp b/src/plugins/debugger/threadswindow.cpp
new file mode 100644
index 0000000000..beffda84cb
--- /dev/null
+++ b/src/plugins/debugger/threadswindow.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "threadswindow.h"
+
+#include "assert.h"
+#include "stackhandler.h"
+
+#include <QAction>
+#include <QComboBox>
+#include <QDebug>
+#include <QHeaderView>
+#include <QMenu>
+#include <QResizeEvent>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+using Debugger::Internal::ThreadsWindow;
+
+ThreadsWindow::ThreadsWindow(QWidget *parent)
+ : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
+{
+ setWindowTitle(tr("Thread"));
+
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+ setIconSize(QSize(10, 10));
+
+ header()->setDefaultAlignment(Qt::AlignLeft);
+
+ connect(this, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(rowActivated(const QModelIndex &)));
+}
+
+void ThreadsWindow::resizeEvent(QResizeEvent *event)
+{
+ //QHeaderView *hv = header();
+ //int totalSize = event->size().width() - 120;
+ //hv->resizeSection(0, 45);
+ //hv->resizeSection(1, totalSize);
+ //hv->resizeSection(2, 55);
+ QTreeView::resizeEvent(event);
+}
+
+void ThreadsWindow::rowActivated(const QModelIndex &index)
+{
+ //qDebug() << "ACTIVATED: " << index.row() << index.column();
+ emit threadSelected(index.row());
+}
+
+void ThreadsWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ QMenu menu;
+ QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
+ QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
+ act2->setCheckable(true);
+ act2->setChecked(m_alwaysResizeColumnsToContents);
+ menu.addAction(act1);
+ menu.addAction(act2);
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (act == act1)
+ resizeColumnsToContents();
+ else if (act == act2)
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+}
+
+void ThreadsWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ //resizeColumnToContents(1);
+}
+
+void ThreadsWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ //header()->setResizeMode(1, mode);
+}
+
diff --git a/src/plugins/debugger/threadswindow.h b/src/plugins/debugger/threadswindow.h
new file mode 100644
index 0000000000..05b94dc531
--- /dev/null
+++ b/src/plugins/debugger/threadswindow.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_THREADWINDOW_H
+#define DEBUGGER_THREADWINDOW_H
+
+#include <QtGui/QTreeView>
+
+namespace Debugger {
+namespace Internal {
+
+class ThreadsWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ ThreadsWindow(QWidget *parent = 0);
+
+signals:
+ void threadSelected(int);
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on);
+
+private slots:
+ void rowActivated(const QModelIndex &index);
+
+private:
+ void resizeEvent(QResizeEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+
+ bool m_alwaysResizeColumnsToContents;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_THREADWINDOW_H
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
new file mode 100644
index 0000000000..9147aa308e
--- /dev/null
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -0,0 +1,1137 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "watchhandler.h"
+
+#if USE_MODEL_TEST
+#include "modeltest.h"
+#endif
+
+#include "assert.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QEvent>
+
+#include <QtGui/QApplication>
+#include <QtGui/QLabel>
+#include <QtGui/QToolTip>
+#include <QtGui/QTextEdit>
+
+#include <ctype.h>
+
+// creates debug output regarding pending watch data results
+//#define DEBUG_PENDING 1
+// creates debug output for accesses to the itemmodel
+//#define DEBUG_MODEL 1
+
+#if DEBUG_MODEL
+# define MODEL_DEBUG(s) qDebug() << s
+#else
+# define MODEL_DEBUG(s)
+#endif
+#define MODEL_DEBUGX(s) qDebug() << s
+
+using namespace Debugger::Internal;
+
+static const QString strNotInScope = QLatin1String("<not in scope>");
+
+static bool isIntOrFloatType(const QString &type)
+{
+ static const QStringList types = QStringList()
+ << "char" << "int" << "short" << "float" << "double" << "long"
+ << "bool" << "signed char" << "unsigned" << "unsigned char"
+ << "unsigned int" << "unsigned long" << "long long";
+ return types.contains(type);
+}
+
+static bool isPointerType(const QString &type)
+{
+ return type.endsWith("*") || type.endsWith("* const");
+}
+
+static QString htmlQuote(const QString &str0)
+{
+ QString str = str0;
+ str.replace('&', "&amp;");
+ str.replace('<', "&lt;");
+ str.replace('>', "&gt;");
+ return str;
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// WatchData
+//
+////////////////////////////////////////////////////////////////////
+
+WatchData::WatchData()
+{
+ valuedisabled = false;
+ state = InitialState;
+ childCount = -1;
+ parentIndex = -1;
+ row = -1;
+ level = -1;
+ changed = false;
+}
+
+void WatchData::setError(const QString &msg)
+{
+ setAllUnneeded();
+ value = msg;
+ setChildCount(0);
+ valuedisabled = true;
+}
+
+static QByteArray quoteUnprintable(const QByteArray &ba)
+{
+ QByteArray res;
+ char buf[10];
+ for (int i = 0, n = ba.size(); i != n; ++i) {
+ char c = ba.at(i);
+ if (isprint(c)) {
+ res += c;
+ } else {
+ qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c));
+ res += buf;
+ }
+ }
+ return res;
+}
+
+void WatchData::setValue(const QByteArray &value0)
+{
+ value = quoteUnprintable(value0);
+ if (value == "{...}") {
+ value.clear();
+ childCount = 1; // at least one...
+ }
+
+ // avoid duplicated information
+ if (value.startsWith("(") && value.contains(") 0x"))
+ value = value.mid(value.lastIndexOf(") 0x") + 2);
+
+ // doubles are sometimes displayed as "@0x6141378: 1.2".
+ // I don't want that.
+ if (/*isIntOrFloatType(type) && */ value.startsWith("@0x")
+ && value.contains(':')) {
+ value = value.mid(value.indexOf(':') + 2);
+ setChildCount(0);
+ }
+
+ // "numchild" is sometimes lying
+ //MODEL_DEBUG("\n\n\nPOINTER: " << type << value);
+ if (isPointerType(type))
+ setChildCount(value != "0x0" && value != "<null>");
+
+ // pointer type information is available in the 'type'
+ // column. No need to duplicate it here.
+ if (value.startsWith("(" + type + ") 0x"))
+ value = value.section(" ", -1, -1);
+
+ setValueUnneeded();
+}
+
+void WatchData::setValueToolTip(const QString &tooltip)
+{
+ valuetooltip = tooltip;
+}
+
+void WatchData::setType(const QString &str)
+{
+ type = str.trimmed();
+ bool changed = true;
+ while (changed) {
+ if (type.endsWith("const"))
+ type.chop(5);
+ else if (type.endsWith(" "))
+ type.chop(1);
+ else if (type.endsWith("&"))
+ type.chop(1);
+ else if (type.startsWith("const "))
+ type = type.mid(6);
+ else if (type.startsWith("volatile "))
+ type = type.mid(9);
+ else if (type.startsWith("class "))
+ type = type.mid(6);
+ else if (type.startsWith("struct "))
+ type = type.mid(6);
+ else if (type.startsWith(" "))
+ type = type.mid(1);
+ else
+ changed = false;
+ }
+ setTypeUnneeded();
+ if (isIntOrFloatType(type))
+ setChildCount(0);
+}
+
+void WatchData::setAddress(const QString & str)
+{
+ addr = str;
+}
+
+QString WatchData::toString() const
+{
+ QString res = "{";
+
+ res += "level=\"" + QString::number(level) + "\",";
+ res += "parent=\"" + QString::number(parentIndex) + "\",";
+ res += "row=\"" + QString::number(row) + "\",";
+ res += "child=\"";
+ foreach (int index, childIndex)
+ res += QString::number(index) + ",";
+ if (res.endsWith(','))
+ res[res.size() - 1] = '"';
+ else
+ res += '"';
+ res += ",";
+
+
+ if (!iname.isEmpty())
+ res += "iname=\"" + iname + "\",";
+ if (!exp.isEmpty())
+ res += "exp=\"" + exp + "\",";
+
+ if (!variable.isEmpty())
+ res += "variable=\"" + variable + "\",";
+
+ if (isValueNeeded())
+ res += "value=<needed>,";
+ if (isValueKnown() && !value.isEmpty())
+ res += "value=\"" + value + "\",";
+
+ if (!editvalue.isEmpty())
+ res += "editvalue=\"" + editvalue + "\",";
+
+ if (isTypeNeeded())
+ res += "type=<needed>,";
+ if (isTypeKnown() && !type.isEmpty())
+ res += "type=\"" + type + "\",";
+
+ if (isChildCountNeeded())
+ res += "numchild=<needed>,";
+ if (isChildCountKnown() && childCount == -1)
+ res += "numchild=\"" + QString::number(childCount) + "\",";
+
+ if (isChildrenNeeded())
+ res += "children=<needed>,";
+
+ if (res.endsWith(','))
+ res[res.size() - 1] = '}';
+ else
+ res += '}';
+
+ return res;
+}
+
+
+static bool iNameSorter(const WatchData &d1, const WatchData &d2)
+{
+ if (d1.level != d2.level)
+ return d1.level < d2.level;
+
+ for (int level = 0; level != d1.level; ++level) {
+ QString name1 = d1.iname.section('.', level, level);
+ QString name2 = d2.iname.section('.', level, level);
+ //MODEL_DEBUG(" SORT: " << name1 << name2 << (name1 < name2));
+
+ if (name1 != name2) {
+ // This formerly used inames. in this case 'lastIndexOf' probably
+ // makes more sense.
+ if (name1.startsWith('[') && name2.startsWith('[')) {
+ return name1.mid(1, name1.indexOf(']') - 1).toInt()
+ < name2.mid(1, name2.indexOf(']') - 1).toInt();
+ // numbers should be sorted according to their numerical value
+ //int pos = d1.name.lastIndexOf('.');
+ //if (pos != -1 && pos + 1 != d1.name.size() && d1.name.at(pos + 1).isDigit())
+ // return d1.name.size() < d2.name.size();
+ // fall through
+ }
+ return name1 < name2;
+ }
+ }
+ return false;
+}
+
+static QString parentName(const QString &iname)
+{
+ int pos = iname.lastIndexOf(".");
+ if (pos == -1)
+ return QString();
+ return iname.left(pos);
+}
+
+
+static void insertDataHelper(QList<WatchData> &list, const WatchData &data)
+{
+ // FIXME: Quadratic algorithm
+ for (int i = list.size(); --i >= 0; ) {
+ if (list.at(i).iname == data.iname) {
+ list[i] = data;
+ return;
+ }
+ }
+ list.append(data);
+}
+
+static WatchData take(const QString &iname, QList<WatchData> *list)
+{
+ for (int i = list->size(); --i >= 0;) {
+ if (list->at(i).iname == iname) {
+ WatchData res = list->at(i);
+ (*list)[i] = list->back();
+ (void) list->takeLast();
+ return res;
+ //return list->takeAt(i);
+ }
+ }
+ return WatchData();
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// WatchHandler
+//
+///////////////////////////////////////////////////////////////////////
+
+WatchHandler::WatchHandler()
+{
+ m_expandPointers = true;
+ m_inFetchMore = false;
+ m_inChange = false;
+
+ cleanModel();
+ m_displaySet = m_completeSet;
+}
+
+bool WatchHandler::setData(const QModelIndex &idx,
+ const QVariant &value, int role)
+{
+/*
+ Q_UNUSED(idx);
+ Q_UNUSED(value);
+ Q_UNUSED(role);
+ if (role == VisualRole) {
+ QString iname = inameFromIndex(index);
+ setDisplayedIName(iname, value.toBool());
+ return true;
+ }
+ return true;
+*/
+ return QAbstractItemModel::setData(idx, value, role);
+}
+
+static QString niceType(QString type)
+{
+ if (type.contains("std::")) {
+ static QRegExp re("std::vector<(.*)\\s*,std::allocator<(.*)>\\s*>");
+ re.setMinimal(true);
+
+ type.replace("std::basic_string<char, std::char_traits<char>, "
+ "std::allocator<char> >", "std::string");
+ type.replace("std::basic_string<wchar_t, std::char_traits<wchar_t>, "
+ "std::allocator<wchar_t> >", "std::wstring");
+
+ for (int i = 0; i != 10; ++i) {
+ if (re.indexIn(type) == -1 || re.cap(1) != re.cap(2))
+ break;
+ type.replace(re.cap(0), "std::vector<" + re.cap(1) + ">");
+ }
+
+ type.replace(" >", ">");
+ }
+ return type;
+}
+
+QVariant WatchHandler::data(const QModelIndex &idx, int role) const
+{
+ int node = idx.internalId();
+ if (node < 0)
+ return QVariant();
+
+ const WatchData &data = m_displaySet.at(node);
+
+ switch (role) {
+ case Qt::DisplayRole: {
+ switch (idx.column()) {
+ case 0: return data.name;
+ case 1: return data.value;
+ case 2: return niceType(data.type);
+ default: break;
+ }
+ break;
+ }
+
+ case Qt::ToolTipRole: {
+ QString val = data.value;
+ if (val.size() > 1000)
+ val = val.left(1000) + " ... <cut off>";
+
+ QString tt = "<table>";
+ //tt += "<tr><td>internal name</td><td> : </td><td>";
+ //tt += htmlQuote(iname) + "</td></tr>";
+ tt += "<tr><td>expression</td><td> : </td><td>";
+ tt += htmlQuote(data.exp) + "</td></tr>";
+ tt += "<tr><td>type</td><td> : </td><td>";
+ tt += htmlQuote(data.type) + "</td></tr>";
+ //if (!valuetooltip.isEmpty())
+ // tt += valuetooltip;
+ //else
+ tt += "<tr><td>value</td><td> : </td><td>";
+ tt += htmlQuote(data.value) + "</td></tr>";
+ tt += "<tr><td>addr</td><td> : </td><td>";
+ tt += htmlQuote(data.addr) + "</td></tr>";
+ tt += "<tr><td>iname</td><td> : </td><td>";
+ tt += htmlQuote(data.iname) + "</td></tr>";
+ tt += "</table>";
+ tt.replace("@value@", htmlQuote(data.value));
+
+ if (tt.size() > 10000)
+ tt = tt.left(10000) + " ... <cut off>";
+ return tt;
+ }
+
+ case Qt::ForegroundRole: {
+ static const QVariant red(QColor(200, 0, 0));
+ static const QVariant black(QColor(0, 0, 0));
+ static const QVariant gray(QColor(140, 140, 140));
+ switch (idx.column()) {
+ case 0: return black;
+ case 1: return data.valuedisabled ? gray : data.changed ? red : black;
+ case 2: return black;
+ }
+ break;
+ }
+
+ case INameRole:
+ return data.iname;
+
+ case VisualRole:
+ return m_displayedINames.contains(data.iname);
+
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags WatchHandler::flags(const QModelIndex &idx) const
+{
+ using namespace Qt;
+
+ if (!idx.isValid())
+ return ItemFlags();
+
+ int node = idx.internalId();
+ if (node < 0)
+ return ItemFlags();
+
+ // enabled, editable, selectable, checkable, and can be used both as the
+ // source of a drag and drop operation and as a drop target.
+
+ static const ItemFlags DefaultNotEditable =
+ ItemIsSelectable
+ | ItemIsDragEnabled
+ | ItemIsDropEnabled
+ // | ItemIsUserCheckable
+ // | ItemIsTristate
+ | ItemIsEnabled;
+
+ static const ItemFlags DefaultEditable =
+ DefaultNotEditable | ItemIsEditable;
+
+ const WatchData &data = m_displaySet.at(node);
+ return idx.column() == 1 &&
+ data.isWatcher() ? DefaultEditable : DefaultNotEditable;
+}
+
+QVariant WatchHandler::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Vertical)
+ return QVariant();
+ if (role == Qt::DisplayRole) {
+ switch (section) {
+ case 0: return tr("Name") + " ";
+ case 1: return tr("Value") + " ";
+ case 2: return tr("Type") + " ";
+ }
+ }
+ return QVariant();
+}
+
+QString WatchHandler::toString() const
+{
+ QString res;
+ res += "\nIncomplete:\n";
+ for (int i = 0, n = m_incompleteSet.size(); i != n; ++i) {
+ res += QString("%1: ").arg(i);
+ res += m_incompleteSet.at(i).toString();
+ res += '\n';
+ }
+ res += "\nComplete:\n";
+ for (int i = 0, n = m_completeSet.size(); i != n; ++i) {
+ res += QString("%1: ").arg(i);
+ res += m_completeSet.at(i).toString();
+ res += '\n';
+ }
+ res += "\nDisplay:\n";
+ for (int i = 0, n = m_displaySet.size(); i != n; ++i) {
+ res += QString("%1: ").arg(i);
+ res += m_displaySet.at(i).toString();
+ res += '\n';
+ }
+#if 0
+ res += "\nOld:\n";
+ for (int i = 0, n = m_oldSet.size(); i != n; ++i) {
+ res += m_oldSet.at(i).toString();
+ res += '\n';
+ }
+#endif
+ return res;
+}
+
+WatchData *WatchHandler::findData(const QString &iname)
+{
+ for (int i = m_completeSet.size(); --i >= 0; )
+ if (m_completeSet.at(i).iname == iname)
+ return &m_completeSet[i];
+ return 0;
+}
+
+WatchData WatchHandler::takeData(const QString &iname)
+{
+ WatchData data = take(iname, &m_incompleteSet);
+ if (data.isValid())
+ return data;
+ return take(iname, &m_completeSet);
+}
+
+QList<WatchData> WatchHandler::takeCurrentIncompletes()
+{
+ QList<WatchData> res = m_incompleteSet;
+ //MODEL_DEBUG("TAKING INCOMPLETES" << toString());
+ m_incompleteSet.clear();
+ return res;
+}
+
+void WatchHandler::rebuildModel()
+{
+ if (m_inChange) {
+ MODEL_DEBUG("RECREATE MODEL IGNORED, CURRENT SET:\n" << toString());
+ return;
+ }
+
+ #ifdef DEBUG_PENDING
+ MODEL_DEBUG("RECREATE MODEL, CURRENT SET:\n" << toString());
+ #endif
+
+ QHash<QString, QString> oldValues;
+ for (int i = 0, n = m_oldSet.size(); i != n; ++i) {
+ WatchData &data = m_oldSet[i];
+ oldValues[data.iname] = data.value;
+ }
+ #ifdef DEBUG_PENDING
+ MODEL_DEBUG("OLD VALUES: " << oldValues);
+ #endif
+
+ for (int i = m_completeSet.size(); --i >= 0; ) {
+ WatchData &data = m_completeSet[i];
+ data.level = data.iname.isEmpty() ? 0 : data.iname.count('.') + 1;
+ data.childIndex.clear();
+ }
+
+ qSort(m_completeSet.begin(), m_completeSet.end(), &iNameSorter);
+
+ QHash<QString, int> iname2idx;
+
+ for (int i = m_completeSet.size(); --i > 0; ) {
+ WatchData &data = m_completeSet[i];
+ data.parentIndex = 0;
+ data.childIndex.clear();
+ iname2idx[data.iname] = i;
+ }
+
+ for (int i = 1; i < m_completeSet.size(); ++i) {
+ WatchData &data = m_completeSet[i];
+ QString parentIName = parentName(data.iname);
+ data.parentIndex = iname2idx.value(parentIName, 0);
+ WatchData &parent = m_completeSet[data.parentIndex];
+ data.row = parent.childIndex.size();
+ parent.childIndex.append(i);
+ }
+
+ m_oldSet = m_completeSet;
+ m_oldSet += m_incompleteSet;
+
+ for (int i = 0, n = m_completeSet.size(); i != n; ++i) {
+ WatchData &data = m_completeSet[i];
+ data.changed = !data.value.isEmpty()
+ && data.value != oldValues[data.iname]
+ && data.value != strNotInScope;
+ }
+
+ //emit layoutAboutToBeChanged();
+
+ m_displaySet = m_completeSet;
+
+ #ifdef DEBUG_PENDING
+ MODEL_DEBUG("SET " << toString());
+ #endif
+
+#if 1
+ // Append dummy item to get the [+] effect
+ for (int i = 0, n = m_displaySet.size(); i != n; ++i) {
+ WatchData &data = m_displaySet[i];
+ if (data.childCount > 0 && data.childIndex.size() == 0) {
+ WatchData dummy;
+ dummy.state = 0;
+ dummy.row = 0;
+ dummy.iname = data.iname + ".dummy";
+ //dummy.name = data.iname + ".dummy";
+ //dummy.name = "<loading>";
+ dummy.level = data.level + 1;
+ dummy.parentIndex = i;
+ dummy.childCount = 0;
+ data.childIndex.append(m_displaySet.size());
+ m_displaySet.append(dummy);
+ }
+ }
+#endif
+
+ // Possibly append dummy items to prevent empty views
+ bool ok = true;
+ QWB_ASSERT(m_displaySet.size() >= 2, ok = false);
+ QWB_ASSERT(m_displaySet.at(1).iname == "local", ok = false);
+ QWB_ASSERT(m_displaySet.at(2).iname == "tooltip", ok = false);
+ QWB_ASSERT(m_displaySet.at(3).iname == "watch", ok = false);
+ if (ok) {
+ for (int i = 1; i <= 3; ++i) {
+ WatchData &data = m_displaySet[i];
+ if (data.childIndex.size() == 0) {
+ WatchData dummy;
+ dummy.state = 0;
+ dummy.row = 0;
+ if (i == 1) {
+ dummy.iname = "local.dummy";
+ dummy.name = "<No Locals>";
+ } else if (i == 2) {
+ dummy.iname = "tooltip.dummy";
+ dummy.name = "<No Tooltip>";
+ } else {
+ dummy.iname = "watch.dummy";
+ dummy.name = "<No Watchers>";
+ }
+ dummy.level = 2;
+ dummy.parentIndex = i;
+ dummy.childCount = 0;
+ data.childIndex.append(m_displaySet.size());
+ m_displaySet.append(dummy);
+ }
+ }
+ }
+
+ m_inChange = true;
+ //qDebug() << "WATCHHANDLER: RESET ABOUT TO EMIT";
+ emit reset();
+ //qDebug() << "WATCHHANDLER: RESET EMITTED";
+ m_inChange = false;
+ //emit layoutChanged();
+ //QSet<QString> einames = m_expandedINames;
+ //einames.insert("local");
+ //einames.insert("watch");
+ //emit expandedItems(einames);
+
+ #if DEBUG_MODEL
+ #if USE_MODEL_TEST
+ //(void) new ModelTest(this, this);
+ #endif
+ #endif
+
+ #ifdef DEBUG_PENDING
+ MODEL_DEBUG("SORTED: " << toString());
+ MODEL_DEBUG("EXPANDED INAMES: " << m_expandedINames);
+ #endif
+}
+
+void WatchHandler::cleanup()
+{
+ m_oldSet.clear();
+ m_expandedINames.clear();
+ m_displayedINames.clear();
+ cleanModel();
+ m_displaySet = m_completeSet;
+#if 0
+ for (EditWindows::ConstIterator it = m_editWindows.begin();
+ it != m_editWindows.end(); ++it) {
+ if (!it.value().isNull())
+ delete it.value();
+ }
+ m_editWindows.clear();
+#endif
+ emit reset();
+}
+
+void WatchHandler::collapseChildren(const QModelIndex &idx)
+{
+ if (m_inChange || m_completeSet.isEmpty()) {
+ //qDebug() << "WATCHHANDLER: COLLAPSE IGNORED" << idx;
+ return;
+ }
+ QWB_ASSERT(checkIndex(idx.internalId()), return);
+#if 0
+ QString iname0 = m_displaySet.at(idx.internalId()).iname;
+ MODEL_DEBUG("COLLAPSE NODE" << iname0);
+ QString iname1 = iname0 + '.';
+ for (int i = m_completeSet.size(); --i >= 0; ) {
+ QString iname = m_completeSet.at(i).iname;
+ if (iname.startsWith(iname1)) {
+ // Better leave it in in case the user re-enters the branch?
+ (void) m_completeSet.takeAt(i);
+ MODEL_DEBUG(" REMOVING " << iname);
+ m_expandedINames.remove(iname);
+ }
+ }
+ m_expandedINames.remove(iname0);
+ //MODEL_DEBUG(toString());
+ //rebuildModel();
+#endif
+}
+
+void WatchHandler::expandChildren(const QModelIndex &idx)
+{
+ if (m_inChange || m_completeSet.isEmpty()) {
+ //qDebug() << "WATCHHANDLER: EXPAND IGNORED" << idx;
+ return;
+ }
+ int index = idx.internalId();
+ if (index == 0)
+ return;
+ QWB_ASSERT(index >= 0, qDebug() << toString() << index; return);
+ QWB_ASSERT(index < m_completeSet.size(), qDebug() << toString() << index; return);
+ const WatchData &display = m_displaySet.at(index);
+ QWB_ASSERT(index >= 0, qDebug() << toString() << index; return);
+ QWB_ASSERT(index < m_completeSet.size(), qDebug() << toString() << index; return);
+ const WatchData &complete = m_completeSet.at(index);
+ MODEL_DEBUG("\n\nEXPAND" << display.iname);
+ if (display.iname.isEmpty()) {
+ // This should not happen but the view seems to send spurious
+ // "expand()" signals folr the root item from time to time.
+ // Try to handle that gracfully.
+ //MODEL_DEBUG(toString());
+ qDebug() << "FIXME: expandChildren, no data " << display.iname << "found"
+ << idx;
+ //rebuildModel();
+ return;
+ }
+
+ //qDebug() << " ... NODE: " << display.toString()
+ // << complete.childIndex.size() << complete.childCount;
+
+ if (m_expandedINames.contains(display.iname))
+ return;
+
+ // This is a performance hack and not strictly necessary.
+ // Remove it if there are troubles when expanding nodes.
+ if (0 && complete.childCount > 0 && complete.childIndex.size() > 0) {
+ MODEL_DEBUG("SKIP FETCHING CHILDREN");
+ return;
+ }
+
+ WatchData data = takeData(display.iname); // remove previous data
+ m_expandedINames.insert(data.iname);
+ if (data.iname.contains('.')) // not for top-level items
+ data.setChildrenNeeded();
+ insertData(data);
+ emit watchModelUpdateRequested();
+}
+
+void WatchHandler::insertData(const WatchData &data)
+{
+ //MODEL_DEBUG("INSERTDATA: " << data.toString());
+ QWB_ASSERT(data.isValid(), return);
+ if (data.isSomethingNeeded())
+ insertDataHelper(m_incompleteSet, data);
+ else
+ insertDataHelper(m_completeSet, data);
+ //MODEL_DEBUG("INSERT RESULT" << toString());
+}
+
+void WatchHandler::watchExpression(const QString &exp)
+{
+ // FIXME: 'exp' can contain illegal characters
+ //MODEL_DEBUG("WATCH: " << exp);
+ WatchData data;
+ data.exp = exp;
+ data.name = exp;
+ data.iname = "watch." + exp;
+ insertData(data);
+}
+
+
+void WatchHandler::setDisplayedIName(const QString &iname, bool on)
+{
+ WatchData *d = findData(iname);
+ if (!on || !d) {
+ delete m_editWindows.take(iname);
+ m_displayedINames.remove(iname);
+ return;
+ }
+ if (d->exp.isEmpty()) {
+ //emit statusMessageRequested(tr("Sorry. Cannot visualize objects without known address."), 5000);
+ return;
+ }
+ d->setValueNeeded();
+ m_displayedINames.insert(iname);
+ insertData(*d);
+}
+
+void WatchHandler::showEditValue(const WatchData &data)
+{
+ // editvalue is always base64 encoded
+ QByteArray ba = QByteArray::fromBase64(data.editvalue);
+ //QByteArray ba = data.editvalue;
+ QWidget *w = m_editWindows.value(data.iname);
+ qDebug() << "SHOW_EDIT_VALUE " << data.toString() << data.type
+ << data.iname << w;
+ if (data.type == "QImage") {
+ if (!w) {
+ w = new QLabel;
+ m_editWindows[data.iname] = w;
+ }
+ QDataStream ds(&ba, QIODevice::ReadOnly);
+ QVariant v;
+ ds >> v;
+ QString type = QString::fromAscii(v.typeName());
+ QImage im = v.value<QImage>();
+ if (QLabel *l = qobject_cast<QLabel *>(w))
+ l->setPixmap(QPixmap::fromImage(im));
+ } else if (data.type == "QPixmap") {
+ if (!w) {
+ w = new QLabel;
+ m_editWindows[data.iname] = w;
+ }
+ QDataStream ds(&ba, QIODevice::ReadOnly);
+ QVariant v;
+ ds >> v;
+ QString type = QString::fromAscii(v.typeName());
+ QPixmap im = v.value<QPixmap>();
+ if (QLabel *l = qobject_cast<QLabel *>(w))
+ l->setPixmap(im);
+ } else if (data.type == "QString") {
+ if (!w) {
+ w = new QTextEdit;
+ m_editWindows[data.iname] = w;
+ }
+#if 0
+ QDataStream ds(&ba, QIODevice::ReadOnly);
+ QVariant v;
+ ds >> v;
+ QString type = QString::fromAscii(v.typeName());
+ QString str = v.value<QString>();
+#else
+ MODEL_DEBUG("DATA: " << ba);
+ QString str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
+#endif
+ if (QTextEdit *t = qobject_cast<QTextEdit *>(w))
+ t->setText(str);
+ }
+ if (w)
+ w->show();
+}
+
+void WatchHandler::removeWatchExpression(const QString &iname)
+{
+ MODEL_DEBUG("REMOVE WATCH: " << iname);
+ (void) takeData(iname);
+ emit watchModelUpdateRequested();
+}
+
+void WatchHandler::cleanModel()
+{
+ // This uses data stored in m_oldSet to re-create a new set
+ // one-by-one
+ m_completeSet.clear();
+ m_incompleteSet.clear();
+
+ WatchData root;
+ root.state = 0;
+ root.level = 0;
+ root.row = 0;
+ root.name = "Root";
+ root.parentIndex = -1;
+ root.childIndex.append(1);
+ root.childIndex.append(2);
+ root.childIndex.append(3);
+ m_completeSet.append(root);
+
+ WatchData local;
+ local.iname = "local";
+ local.name = "Locals";
+ local.state = 0;
+ local.level = 1;
+ local.row = 0;
+ local.parentIndex = 0;
+ m_completeSet.append(local);
+
+ WatchData tooltip;
+ tooltip.iname = "tooltip";
+ tooltip.name = "Tooltip";
+ tooltip.state = 0;
+ tooltip.level = 1;
+ tooltip.row = 1;
+ tooltip.parentIndex = 0;
+ m_completeSet.append(tooltip);
+
+ WatchData watch;
+ watch.iname = "watch";
+ watch.name = "Watchers";
+ watch.state = 0;
+ watch.level = 1;
+ watch.row = 2;
+ watch.parentIndex = 0;
+ m_completeSet.append(watch);
+}
+
+
+void WatchHandler::reinitializeWatchers()
+{
+ cleanModel();
+
+ // copy over all watchers and mark all watchers as incomplete
+ for (int i = 0, n = m_oldSet.size(); i < n; ++i) {
+ WatchData data = m_oldSet.at(i);
+ if (data.isWatcher()) {
+ data.level = -1;
+ data.row = -1;
+ data.parentIndex = -1;
+ data.variable.clear();
+ data.setAllNeeded();
+ data.valuedisabled = false;
+ insertData(data); // properly handles "neededChildren"
+ }
+ }
+}
+
+bool WatchHandler::canFetchMore(const QModelIndex &parent) const
+{
+ MODEL_DEBUG("CAN FETCH MORE: " << parent << "false");
+#if 1
+ Q_UNUSED(parent);
+ return false;
+#else
+ // FIXME: not robust enough. Problem is that fetchMore
+ // needs to be made synchronous to be useful. Busy loop is no good.
+ if (!parent.isValid())
+ return false;
+ QWB_ASSERT(checkIndex(parent.internalId()), return false);
+ const WatchData &data = m_displaySet.at(parent.internalId());
+ MODEL_DEBUG("CAN FETCH MORE: " << parent << " children: " << data.childCount
+ << data.iname);
+ return data.childCount > 0;
+#endif
+}
+
+void WatchHandler::fetchMore(const QModelIndex &parent)
+{
+ MODEL_DEBUG("FETCH MORE: " << parent);
+ return;
+
+ QWB_ASSERT(checkIndex(parent.internalId()), return);
+ QString iname = m_displaySet.at(parent.internalId()).iname;
+
+ if (m_inFetchMore) {
+ MODEL_DEBUG("LOOP IN FETCH MORE" << iname);
+ return;
+ }
+ m_inFetchMore = true;
+
+ WatchData data = takeData(iname);
+ MODEL_DEBUG("FETCH MORE: " << parent << ":" << iname << data.name);
+
+ if (!data.isValid()) {
+ MODEL_DEBUG("FIXME: FETCH MORE, no data " << iname << "found");
+ return;
+ }
+
+ m_expandedINames.insert(data.iname);
+ if (data.iname.contains('.')) // not for top-level items
+ data.setChildrenNeeded();
+
+ MODEL_DEBUG("FETCH MORE: data:" << data.toString());
+ insertData(data);
+ //emit watchUpdateRequested();
+
+ while (m_inFetchMore) {
+ QApplication::processEvents();
+ }
+ m_inFetchMore = false;
+ MODEL_DEBUG("BUSY LOOP FINISHED, data:" << data.toString());
+}
+
+QModelIndex WatchHandler::index(int row, int col, const QModelIndex &parent) const
+{
+ #ifdef DEBUG_MODEL
+ MODEL_DEBUG("INDEX " << row << col << parent);
+ #endif
+ //if (col != 0) {
+ // MODEL_DEBUG(" -> " << QModelIndex() << " (3) ");
+ // return QModelIndex();
+ //}
+ if (row < 0) {
+ MODEL_DEBUG(" -> " << QModelIndex() << " (4) ");
+ return QModelIndex();
+ }
+ if (!parent.isValid()) {
+ if (row == 0 && col >= 0 && col < 3 && parent.row() == -1) {
+ MODEL_DEBUG(" -> " << createIndex(0, 0, 0) << " (B) ");
+ return createIndex(0, col, 0);
+ }
+ MODEL_DEBUG(" -> " << QModelIndex() << " (1) ");
+ return QModelIndex();
+ }
+ int parentIndex = parent.internalId();
+ if (parentIndex < 0) {
+ //MODEL_DEBUG("INDEX " << row << col << parentIndex << "INVALID");
+ MODEL_DEBUG(" -> " << QModelIndex() << " (2) ");
+ return QModelIndex();
+ }
+ QWB_ASSERT(checkIndex(parentIndex), return QModelIndex());
+ const WatchData &data = m_displaySet.at(parentIndex);
+ QWB_ASSERT(row >= 0, qDebug() << "ROW: " << row << "PARENT: " << parent
+ << data.toString() << toString(); return QModelIndex());
+ QWB_ASSERT(row < data.childIndex.size(),
+ MODEL_DEBUG("ROW: " << row << data.toString() << toString());
+ return QModelIndex());
+ QModelIndex idx = createIndex(row, col, data.childIndex.at(row));
+ QWB_ASSERT(idx.row() == m_displaySet.at(idx.internalId()).row,
+ return QModelIndex());
+ MODEL_DEBUG(" -> " << idx << " (A) ");
+ return idx;
+}
+
+QModelIndex WatchHandler::parent(const QModelIndex &idx) const
+{
+ if (!idx.isValid()) {
+ MODEL_DEBUG(" -> " << QModelIndex() << " (1) ");
+ return QModelIndex();
+ }
+ MODEL_DEBUG("PARENT " << idx);
+ int currentIndex = idx.internalId();
+ QWB_ASSERT(checkIndex(currentIndex), return QModelIndex());
+ QWB_ASSERT(idx.row() == m_displaySet.at(currentIndex).row,
+ MODEL_DEBUG("IDX: " << idx << toString(); return QModelIndex()));
+ int parentIndex = m_displaySet.at(currentIndex).parentIndex;
+ if (parentIndex < 0) {
+ MODEL_DEBUG(" -> " << QModelIndex() << " (2) ");
+ return QModelIndex();
+ }
+ QWB_ASSERT(checkIndex(parentIndex), return QModelIndex());
+ QModelIndex parent =
+ createIndex(m_displaySet.at(parentIndex).row, 0, parentIndex);
+ MODEL_DEBUG(" -> " << parent);
+ return parent;
+}
+
+int WatchHandler::rowCount(const QModelIndex &idx) const
+{
+ MODEL_DEBUG("ROW COUNT " << idx);
+ if (idx.column() > 0) {
+ MODEL_DEBUG(" -> " << 0 << " (A) ");
+ return 0;
+ }
+ int thisIndex = idx.internalId();
+ QWB_ASSERT(checkIndex(thisIndex), return 0);
+ if (idx.row() == -1 && idx.column() == -1) {
+ MODEL_DEBUG(" -> " << 3 << " (B) ");
+ return 1;
+ }
+ if (thisIndex < 0) {
+ MODEL_DEBUG(" -> " << 0 << " (C) ");
+ return 0;
+ }
+ if (thisIndex == 0) {
+ MODEL_DEBUG(" -> " << 3 << " (D) ");
+ return 3;
+ }
+ const WatchData &data = m_displaySet.at(thisIndex);
+ int rows = data.childIndex.size();
+ MODEL_DEBUG(" -> " << rows << " (E) ");
+ return rows;
+ // Try lazy evaluation
+ //if (rows > 0)
+ // return rows;
+ //return data.childCount;
+}
+
+int WatchHandler::columnCount(const QModelIndex &idx) const
+{
+ MODEL_DEBUG("COLUMN COUNT " << idx);
+ if (idx == QModelIndex()) {
+ MODEL_DEBUG(" -> " << 3 << " (C) ");
+ return 3;
+ }
+ if (idx.column() != 0) {
+ MODEL_DEBUG(" -> " << 0 << " (A) ");
+ return 0;
+ }
+ MODEL_DEBUG(" -> " << 3 << " (B) ");
+ QWB_ASSERT(checkIndex(idx.internalId()), return 3);
+ return 3;
+}
+
+bool WatchHandler::hasChildren(const QModelIndex &idx) const
+{
+ // that's the base implementation:
+ bool base = rowCount(idx) > 0 && columnCount(idx) > 0;
+ MODEL_DEBUG("HAS CHILDREN: " << idx << base);
+ return base;
+ QWB_ASSERT(checkIndex(idx.internalId()), return false);
+ const WatchData &data = m_displaySet.at(idx.internalId());
+ MODEL_DEBUG("HAS CHILDREN: " << idx << data.toString());
+ return data.childCount > 0; // || data.childIndex.size() > 0;
+}
+
+bool WatchHandler::checkIndex(int id) const
+{
+ if (id < 0) {
+ MODEL_DEBUG("CHECK INDEX FAILED" << id);
+ return false;
+ }
+ if (id >= m_displaySet.size()) {
+ MODEL_DEBUG("CHECK INDEX FAILED" << id << toString());
+ return false;
+ }
+ return true;
+}
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
new file mode 100644
index 0000000000..b3db114be8
--- /dev/null
+++ b/src/plugins/debugger/watchhandler.h
@@ -0,0 +1,219 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_WATCHHANDLER_H
+#define DEBUGGER_WATCHHANDLER_H
+
+#include <QtCore/QPointer>
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QSet>
+#include <QtGui/QStandardItem>
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QTreeView>
+#include <QtScript/QScriptValue>
+
+namespace Debugger {
+namespace Internal {
+
+class WatchData
+{
+public:
+ WatchData();
+
+ enum State
+ {
+ Complete = 0,
+ ChildCountNeeded = 1,
+ ValueNeeded = 2,
+ TypeNeeded = 4,
+ ChildrenNeeded = 8,
+
+ NeededMask = ValueNeeded
+ | TypeNeeded
+ | ChildrenNeeded
+ | ChildCountNeeded,
+
+ InitialState = ValueNeeded
+ | TypeNeeded
+ | ChildrenNeeded
+ | ChildCountNeeded
+ };
+
+ void setValue(const QByteArray &);
+ void setType(const QString &);
+ void setValueToolTip(const QString &);
+ void setError(const QString &);
+ void setAddress(const QString &address);
+
+ bool isSomethingNeeded() const { return state & NeededMask; }
+ void setAllNeeded() { state = NeededMask; }
+ void setAllUnneeded() { state = State(0); }
+
+ bool isTypeNeeded() const { return state & TypeNeeded; }
+ bool isTypeKnown() const { return !(state & TypeNeeded); }
+ void setTypeNeeded() { state = State(state | TypeNeeded); }
+ void setTypeUnneeded() { state = State(state & ~TypeNeeded); }
+
+ bool isValueNeeded() const { return state & ValueNeeded; }
+ bool isValueKnown() const { return !(state & ValueNeeded); }
+ void setValueNeeded() { state = State(state | ValueNeeded); }
+ void setValueUnneeded() { state = State(state & ~ValueNeeded); }
+
+ bool isChildrenNeeded() const { return state & ChildrenNeeded; }
+ bool isChildrenKnown() const { return !(state & ChildrenNeeded); }
+ void setChildrenNeeded() { state = State(state | ChildrenNeeded); }
+ void setChildrenUnneeded() { state = State(state & ~ChildrenNeeded); }
+
+ bool isChildCountNeeded() const { return state & ChildCountNeeded; }
+ bool isChildCountKnown() const { return !(state & ChildCountNeeded); }
+ void setChildCountNeeded() { state = State(state | ChildCountNeeded); }
+ void setChildCountUnneeded() { state = State(state & ~ChildCountNeeded); }
+ void setChildCount(int n) { childCount = n; setChildCountUnneeded();
+ if (n == 0) setChildrenUnneeded(); }
+
+ QString toString() const;
+ bool isLocal() const { return iname.startsWith(QLatin1String("local.")); }
+ bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); };
+ bool isValid() const { return !iname.isEmpty(); }
+
+public:
+ QString iname; // internal name sth like 'local.baz.public.a'
+ QString exp; // the expression
+ QString name; // displayed name
+ QString value; // displayed value
+ QByteArray editvalue; // displayed value
+ QString valuetooltip; // tooltip in value column
+ QString type; // displayed type
+ QString variable; // name of internal Gdb variable if created
+ QString addr; // displayed adress
+ QString framekey; // key for type cache
+ QScriptValue scriptValue; // if needed...
+ int childCount;
+ bool valuedisabled; // value will be greyed out
+
+private:
+
+public:
+ int state;
+
+ // Model
+ int parentIndex;
+ int row;
+ int level;
+ QList<int> childIndex;
+ bool changed;
+};
+
+enum { INameRole = Qt::UserRole, VisualRole };
+
+
+class WatchHandler : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ WatchHandler();
+ QAbstractItemModel *model() { return this; }
+
+ //
+ // QAbstractItemModel
+ //
+ bool setData(const QModelIndex &index, const QVariant &value, int role);
+ QVariant data(const QModelIndex &index, int role) const;
+ QModelIndex index(int, int, const QModelIndex &idx) const;
+ QModelIndex parent(const QModelIndex &idx) const;
+ int rowCount(const QModelIndex &idx) const;
+ int columnCount(const QModelIndex &idx) const;
+ bool hasChildren(const QModelIndex &idx) const;
+ Qt::ItemFlags flags(const QModelIndex &idx) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ bool checkIndex(int id) const;
+
+//public slots:
+ void cleanup();
+ void watchExpression(const QString &exp);
+ void removeWatchExpression(const QString &exp);
+ void reinitializeWatchers();
+
+ void collapseChildren(const QModelIndex &idx);
+ void expandChildren(const QModelIndex &idx);
+
+ void rebuildModel(); // unconditionally version of above
+ void showEditValue(const WatchData &data);
+
+ bool isDisplayedIName(const QString &iname) const
+ { return m_displayedINames.contains(iname); }
+ bool isExpandedIName(const QString &iname) const
+ { return m_expandedINames.contains(iname); }
+
+ void insertData(const WatchData &data);
+ QList<WatchData> takeCurrentIncompletes();
+
+ bool canFetchMore(const QModelIndex &parent) const;
+ void fetchMore(const QModelIndex &parent);
+
+ WatchData *findData(const QString &iname);
+
+signals:
+ void watchModelUpdateRequested();
+
+private:
+ WatchData takeData(const QString &iname);
+ QString toString() const;
+ void cleanModel();
+
+ bool m_expandPointers;
+ bool m_inChange;
+
+ typedef QMap<QString, QPointer<QWidget> > EditWindows;
+ EditWindows m_editWindows;
+
+ QList<WatchData> m_incompleteSet;
+ QList<WatchData> m_completeSet;
+ QList<WatchData> m_oldSet;
+ QList<WatchData> m_displaySet;
+
+ void setDisplayedIName(const QString &iname, bool on);
+ QSet<QString> m_expandedINames; // those expanded in the treeview
+ QSet<QString> m_displayedINames; // those with "external" viewers
+
+ bool m_inFetchMore;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+Q_DECLARE_METATYPE(Debugger::Internal::WatchData);
+
+#endif // DEBUGGER_WATCHHANDLER_H
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
new file mode 100644
index 0000000000..6f153d2de5
--- /dev/null
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -0,0 +1,253 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "watchwindow.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QHeaderView>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QSplitter>
+
+using namespace Debugger::Internal;
+
+enum { INameRole = Qt::UserRole, VisualRole };
+
+/////////////////////////////////////////////////////////////////////
+//
+// WatchWindow
+//
+/////////////////////////////////////////////////////////////////////
+
+WatchWindow::WatchWindow(Type type, QWidget *parent)
+ : QTreeView(parent), m_type(type)
+{
+ m_blocked = false;
+ setWindowTitle(tr("Locals and Watchers"));
+ setAlternatingRowColors(true);
+ setIndentation(indentation() * 9/10);
+ setUniformRowHeights(true);
+
+ connect(itemDelegate(), SIGNAL(commitData(QWidget *)),
+ this, SLOT(handleChangedItem(QWidget *)));
+ connect(this, SIGNAL(expanded(QModelIndex)),
+ this, SLOT(expandNode(QModelIndex)));
+ connect(this, SIGNAL(collapsed(QModelIndex)),
+ this, SLOT(collapseNode(QModelIndex)));
+}
+
+void WatchWindow::expandNode(const QModelIndex &idx)
+{
+ //QModelIndex mi0 = idx.sibling(idx.row(), 0);
+ //QString iname = model()->data(mi0, INameRole).toString();
+ //QString name = model()->data(mi0, Qt::DisplayRole).toString();
+ //qDebug() << "\n\nEXPAND NODE " // << iname << name
+ // << idx << (m_blocked ? "blocked" : "passed");
+ //if (isExpanded(idx))
+ // return;
+ //if (m_blocked)
+ // return;
+ emit requestExpandChildren(idx);
+}
+
+void WatchWindow::collapseNode(const QModelIndex &idx)
+{
+ //QModelIndex mi0 = idx.sibling(idx.row(), 0);
+ //QString iname = model()->data(mi0, INameRole).toString();
+ //QString name = model()->data(mi0, Qt::DisplayRole).toString();
+ //qDebug() << "COLLAPSE NODE " << idx;
+ if (m_blocked)
+ return;
+ emit requestCollapseChildren(idx);
+}
+
+void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
+{
+ QMenu menu;
+ QAction *act1 = new QAction("Adjust column widths to contents", &menu);
+ QAction *act2 = new QAction("Always adjust column widths to contents", &menu);
+ act2->setCheckable(true);
+ act2->setChecked(m_alwaysResizeColumnsToContents);
+
+ menu.addAction(act1);
+ menu.addAction(act2);
+
+ QAction *act3 = 0;
+ QAction *act4 = 0;
+ QModelIndex idx = indexAt(ev->pos());
+ QModelIndex mi0 = idx.sibling(idx.row(), 0);
+ QString exp = model()->data(mi0).toString();
+ QString iname = model()->data(mi0, INameRole).toString();
+ QModelIndex mi1 = idx.sibling(idx.row(), 0);
+ QString value = model()->data(mi1).toString();
+ bool visual = false;
+ if (idx.isValid()) {
+ menu.addSeparator();
+ if (m_type == LocalsType)
+ act3 = new QAction("Watch expression '" + exp + "'", &menu);
+ else
+ act3 = new QAction("Remove expression '" + exp + "'", &menu);
+ menu.addAction(act3);
+
+ visual = model()->data(mi0, VisualRole).toBool();
+ act4 = new QAction("Watch expression '" + exp + "' in separate widget", &menu);
+ act4->setCheckable(true);
+ act4->setChecked(visual);
+ // FIXME: menu.addAction(act4);
+ }
+
+ QAction *act = menu.exec(ev->globalPos());
+
+ if (!act)
+ ;
+ else if (act == act1)
+ resizeColumnsToContents();
+ else if (act == act2)
+ setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
+ else if (act == act3)
+ if (m_type == LocalsType)
+ emit requestWatchExpression(exp);
+ else
+ emit requestRemoveWatchExpression(iname);
+ else if (act == act4)
+ model()->setData(mi0, !visual, VisualRole);
+}
+
+void WatchWindow::resizeColumnsToContents()
+{
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+}
+
+void WatchWindow::setAlwaysResizeColumnsToContents(bool on)
+{
+ if (!header())
+ return;
+ m_alwaysResizeColumnsToContents = on;
+ QHeaderView::ResizeMode mode = on
+ ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
+ header()->setResizeMode(0, mode);
+ header()->setResizeMode(1, mode);
+}
+
+void WatchWindow::editItem(const QModelIndex &idx)
+{
+ Q_UNUSED(idx); // FIXME
+}
+
+void WatchWindow::reset()
+{
+ int row = 0;
+ if (m_type == TooltipType)
+ row = 1;
+ else if (m_type == WatchersType)
+ row = 2;
+ //qDebug() << "WATCHWINDOW::RESET" << row;
+ QTreeView::reset();
+ setRootIndex(model()->index(row, 0, model()->index(0, 0)));
+ //setRootIndex(model()->index(0, 0));
+}
+
+void WatchWindow::setModel(QAbstractItemModel *model)
+{
+ QTreeView::setModel(model);
+
+ setRootIsDecorated(true);
+ header()->setDefaultAlignment(Qt::AlignLeft);
+ header()->setResizeMode(QHeaderView::ResizeToContents);
+ if (m_type != LocalsType)
+ header()->hide();
+
+ connect(model, SIGNAL(modelAboutToBeReset()),
+ this, SLOT(modelAboutToBeReset()));
+ connect(model, SIGNAL(modelReset()),
+ this, SLOT(modelReset()));
+}
+
+void WatchWindow::modelAboutToBeReset()
+{
+ m_blocked = true;
+ //qDebug() << "Model about to be reset";
+ m_expandedItems.clear();
+ m_expandedItems.insert("local");
+ m_expandedItems.insert("watch");
+ modelAboutToBeResetHelper(model()->index(0, 0));
+ //qDebug() << " expanded: " << m_expandedItems;
+}
+
+void WatchWindow::modelAboutToBeResetHelper(const QModelIndex &idx)
+{
+ QString iname = model()->data(idx, INameRole).toString();
+ //qDebug() << "Model about to be reset helper" << iname << idx
+ // << isExpanded(idx);
+ if (isExpanded(idx))
+ m_expandedItems.insert(iname);
+ for (int i = 0, n = model()->rowCount(idx); i != n; ++i) {
+ QModelIndex idx1 = model()->index(i, 0, idx);
+ modelAboutToBeResetHelper(idx1);
+ }
+}
+
+void WatchWindow::modelReset()
+{
+ //qDebug() << "Model reset";
+ expand(model()->index(0, 0));
+ modelResetHelper(model()->index(0, 0));
+ m_blocked = false;
+}
+
+void WatchWindow::modelResetHelper(const QModelIndex &idx)
+{
+ QString name = model()->data(idx, Qt::DisplayRole).toString();
+ QString iname = model()->data(idx, INameRole).toString();
+ //qDebug() << "Model reset helper" << iname << name;
+ if (m_expandedItems.contains(iname)) {
+ expand(idx);
+ for (int i = 0, n = model()->rowCount(idx); i != n; ++i) {
+ QModelIndex idx1 = model()->index(i, 0, idx);
+ modelResetHelper(idx1);
+ }
+ }
+}
+
+void WatchWindow::handleChangedItem(QWidget *widget)
+{
+ QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
+ if (lineEdit)
+ requestAssignValue("foo", lineEdit->text());
+}
+
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
new file mode 100644
index 0000000000..da0ee9ee8f
--- /dev/null
+++ b/src/plugins/debugger/watchwindow.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEBUGGER_WATCHWINDOW_H
+#define DEBUGGER_WATCHWINDOW_H
+
+#include <QtGui/QTreeView>
+
+namespace Debugger {
+namespace Internal {
+
+/////////////////////////////////////////////////////////////////////
+//
+// WatchWindow
+//
+/////////////////////////////////////////////////////////////////////
+
+class WatchWindow : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ enum Type { LocalsType, TooltipType, WatchersType };
+
+ WatchWindow(Type type, QWidget *parent = 0);
+ void setType(Type type) { m_type = type; }
+ Type type() const { return m_type; }
+
+public slots:
+ void resizeColumnsToContents();
+ void setAlwaysResizeColumnsToContents(bool on = true);
+ void setModel(QAbstractItemModel *model);
+
+signals:
+ void requestWatchExpression(const QString &exp);
+ void requestRemoveWatchExpression(const QString &iname);
+ void requestAssignValue(const QString &exp, const QString &value);
+ void requestExpandChildren(const QModelIndex &idx);
+ void requestCollapseChildren(const QModelIndex &idx);
+
+private slots:
+ void handleChangedItem(QWidget *);
+ void expandNode(const QModelIndex &index);
+ void collapseNode(const QModelIndex &index);
+ void modelAboutToBeReset();
+ void modelReset();
+
+private:
+ void contextMenuEvent(QContextMenuEvent *ev);
+ void editItem(const QModelIndex &idx);
+ void reset(); /* reimpl */
+
+ void modelAboutToBeResetHelper(const QModelIndex &idx);
+ void modelResetHelper(const QModelIndex &idx);
+
+ bool m_alwaysResizeColumnsToContents;
+ Type m_type;
+ bool m_blocked;
+ QSet<QString> m_expandedItems;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_WATCHWINDOW_H
diff --git a/src/plugins/designer/Designer.mimetypes.xml b/src/plugins/designer/Designer.mimetypes.xml
new file mode 100644
index 0000000000..f093afb0e1
--- /dev/null
+++ b/src/plugins/designer/Designer.mimetypes.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/x-designer">
+ <sub-class-of type="application/xml"/>
+ <comment>Qt Designer file</comment>
+ <glob pattern="*.ui"/>
+ <comment xml:lang="bg">Файл, формат Qt Designer</comment>
+ <comment xml:lang="ca">fitxer de Qt Designer</comment>
+ <comment xml:lang="cs">Soubor Qt Designeru</comment>
+ <comment xml:lang="cy">Ffeil Qt Designer</comment>
+ <comment xml:lang="da">Qt Designer-fil</comment>
+ <comment xml:lang="de">QT Designer-Datei</comment>
+ <comment xml:lang="el">αÏχείο Qt Designer</comment>
+ <comment xml:lang="eo">dosiero de Qt Designer</comment>
+ <comment xml:lang="es">fichero de Qt Designer</comment>
+ <comment xml:lang="eu">Qt Designer Fitxategia</comment>
+ <comment xml:lang="fi">Qt Designer -tiedosto</comment>
+ <comment xml:lang="fr">fichier Qt Designer</comment>
+ <comment xml:lang="hu">Qt Designer-fájl</comment>
+ <comment xml:lang="it">File Qt Designer</comment>
+ <comment xml:lang="ja">Qt Designer ファイル</comment>
+ <comment xml:lang="ko">Qt ë””ìžì´ë„ˆ 파ì¼</comment>
+ <comment xml:lang="lt">Qt Designer rinkmena</comment>
+ <comment xml:lang="ms">Fail Qt Designer</comment>
+ <comment xml:lang="nb">Qt Designer-fil</comment>
+ <comment xml:lang="nl">Qt Designer-bestand</comment>
+ <comment xml:lang="nn">Qt Designer-fil</comment>
+ <comment xml:lang="pl">Plik Qt Designera</comment>
+ <comment xml:lang="pt">ficheiro do Qt Designer</comment>
+ <comment xml:lang="pt_BR">Arquivo do Qt Designer</comment>
+ <comment xml:lang="ru">файл Qt Designer</comment>
+ <comment xml:lang="sq">File Qt Designer</comment>
+ <comment xml:lang="sr">Qt Designer датотека</comment>
+ <comment xml:lang="sv">Qt Designer-fil</comment>
+ <comment xml:lang="uk">Файл програми Qt-дизайнер</comment>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/designer/Designer.pluginspec b/src/plugins/designer/Designer.pluginspec
new file mode 100644
index 0000000000..d1df125dbe
--- /dev/null
+++ b/src/plugins/designer/Designer.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="Designer" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Qt Designer integration.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+<!-- For compiling with CPP support enabled -->
+ <dependency name="CppEditor" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/designer/README.txt b/src/plugins/designer/README.txt
new file mode 100644
index 0000000000..eeef2a6c1d
--- /dev/null
+++ b/src/plugins/designer/README.txt
@@ -0,0 +1,37 @@
+The subdirectory cpp contains classes for CPP-Editor/Designer integration.
+They are dependent on the CPP editor plugin.
+
+Including cpp.pri in designer.pro enables them and defines
+CPP_ENABLED.
+
+Resource handling:
+
+When the editor is opened for the ui file we remember the internal qrc list
+read from the ui file (m_originalUiQrcPaths). In next step (a call to
+updateResources()), we detect if the ui file is inside any project or not.
+
+In case the ui file is not in any project (standalone), we apply
+m_originalUiQrcPaths to the form.
+
+Otherwise we take the list of qrc files from the project and apply the list
+into the form.
+
+Depending if the form is opened in standalone mode or not we save all
+resources or only those which are used inside a form (a call to
+setSaveResourcesBehaviour()).
+
+We need to update resources of the opened form in following cases:
+- a new qrc file is added to / removed from the project in which the form
+ exists (we connect filesAdded()/filesRemoved() to the updateResources() slot)
+- a new project is added which contains a form (which was opened in standalone
+ mode) (we connect foldersAdded()/foldersRemoved() to the updateResources()
+ slot)
+- the opened form is being saved as... with new name, what causes the editor
+ for the form points to a new file which is not in the project (we connect
+ changed() to updateResources() slot)
+
+Changes to qrc file contents are not needed to be handled here, since
+designer's internal file watcher updates the changes to qrc files silently.
+
+A call to setResourceEditingEnabled(false) removes the edit resources action
+form resource browser in designer
diff --git a/src/plugins/designer/cpp/cpp.pri b/src/plugins/designer/cpp/cpp.pri
new file mode 100644
index 0000000000..3827bc836f
--- /dev/null
+++ b/src/plugins/designer/cpp/cpp.pri
@@ -0,0 +1,15 @@
+INCLUDEPATH+=$$PWD
+
+DEFINES+=CPP_ENABLED
+
+HEADERS+=$$PWD/formclasswizardpage.h \
+ $$PWD/formclasswizarddialog.h \
+ $$PWD/formclasswizard.h \
+ $$PWD/formclasswizardparameters.h
+
+SOURCES+=$$PWD/formclasswizardpage.cpp \
+ $$PWD/formclasswizarddialog.cpp \
+ $$PWD/formclasswizard.cpp \
+ $$PWD/formclasswizardparameters.cpp
+
+FORMS+=$$PWD/formclasswizardpage.ui
diff --git a/src/plugins/designer/cpp/formclasswizard.cpp b/src/plugins/designer/cpp/formclasswizard.cpp
new file mode 100644
index 0000000000..43e2c0f44c
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizard.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formclasswizard.h"
+#include "formclasswizarddialog.h"
+#include "designerconstants.h"
+#include "formwindoweditor.h"
+
+#include <coreplugin/icore.h>
+#include <cppeditor/cppeditorconstants.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+enum { debugFormClassWizard = 0 };
+
+using namespace Designer;
+using namespace Designer::Internal;
+
+FormClassWizard::FormClassWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent) :
+ Core::BaseFileWizard(parameters, core, parent)
+{
+}
+
+QString FormClassWizard::headerSuffix() const
+{
+ return preferredSuffix(QLatin1String(CppEditor::Constants::CPP_HEADER_MIMETYPE));
+}
+
+QString FormClassWizard::sourceSuffix() const
+{
+ return preferredSuffix(QLatin1String(CppEditor::Constants::CPP_SOURCE_MIMETYPE));
+}
+
+QString FormClassWizard::formSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::FORM_MIMETYPE));
+}
+
+QWizard *FormClassWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ FormClassWizardDialog *wizardDialog = new FormClassWizardDialog(extensionPages,
+ parent);
+ wizardDialog->setSuffixes(headerSuffix(), sourceSuffix(), formSuffix());
+ wizardDialog->setPath(defaultPath);
+ return wizardDialog;
+}
+
+Core::GeneratedFiles FormClassWizard::generateFiles(const QWizard *w, QString *errorMessage) const
+{
+ const FormClassWizardDialog *wizardDialog = qobject_cast<const FormClassWizardDialog *>(w);
+ const FormClassWizardParameters params = wizardDialog->parameters();
+
+ if (params.uiTemplate.isEmpty()) {
+ *errorMessage = tr("Internal error: FormClassWizard::generateFiles: empty template contents");
+ return Core::GeneratedFiles();
+ }
+
+ // header
+ const QString formFileName = buildFileName(params.path, params.uiFile, formSuffix());
+ const QString headerFileName = buildFileName(params.path, params.headerFile, headerSuffix());
+ const QString sourceFileName = buildFileName(params.path, params.sourceFile, sourceSuffix());
+
+ Core::GeneratedFile headerFile(headerFileName);
+ headerFile.setEditorKind(QLatin1String(CppEditor::Constants::CPPEDITOR_KIND));
+
+ // Source
+ Core::GeneratedFile sourceFile(sourceFileName);
+ sourceFile.setEditorKind(QLatin1String(CppEditor::Constants::CPPEDITOR_KIND));
+
+ // UI
+ Core::GeneratedFile uiFile(formFileName);
+ uiFile.setContents(params.uiTemplate);
+ uiFile.setEditorKind(QLatin1String(Constants::C_FORMEDITOR));
+
+ QString source, header;
+ params.generateCpp(&header, &source);
+ sourceFile.setContents(source);
+ headerFile.setContents(header);
+
+ if (debugFormClassWizard)
+ qDebug() << Q_FUNC_INFO << '\n' << header << '\n' << source;
+
+ return Core::GeneratedFiles() << headerFile << sourceFile << uiFile;
+}
diff --git a/src/plugins/designer/cpp/formclasswizard.h b/src/plugins/designer/cpp/formclasswizard.h
new file mode 100644
index 0000000000..3fce385ebd
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizard.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMCLASSWIZARD_H
+#define FORMCLASSWIZARD_H
+
+#include "formclasswizardparameters.h"
+
+#include <coreplugin/basefilewizard.h>
+
+QT_BEGIN_NAMESPACE
+class QWizard;
+QT_END_NAMESPACE
+
+namespace Designer {
+namespace Internal {
+
+struct FormClassWizardParameters;
+
+class FormClassWizard : public Core::BaseFileWizard
+{
+ Q_DISABLE_COPY(FormClassWizard)
+ Q_OBJECT
+
+public:
+ typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
+
+ FormClassWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent);
+
+ QString headerSuffix() const;
+ QString sourceSuffix() const;
+ QString formSuffix() const;
+
+protected:
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+
+ virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+
+private:
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // FORMCLASSWIZARD_H
diff --git a/src/plugins/designer/cpp/formclasswizarddialog.cpp b/src/plugins/designer/cpp/formclasswizarddialog.cpp
new file mode 100644
index 0000000000..e340d5ca88
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizarddialog.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formclasswizarddialog.h"
+#include "formtemplatewizardpage.h"
+#include "formclasswizardpage.h"
+#include "formclasswizardparameters.h"
+
+#include <coreplugin/icore.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QAbstractButton>
+
+enum { FormPageId, ClassPageId };
+
+namespace Designer {
+namespace Internal {
+
+// ----------------- FormClassWizardDialog
+FormClassWizardDialog::FormClassWizardDialog(const WizardPageList &extensionPages,
+ QWidget *parent) :
+ QWizard(parent),
+ m_formPage(new FormTemplateWizardPagePage),
+ m_classPage(new FormClassWizardPage)
+{
+ setWindowTitle(tr("Qt Designer Form Class"));
+
+ setPage(FormPageId, m_formPage);
+ connect(m_formPage, SIGNAL(templateActivated()),
+ button(QWizard::NextButton), SLOT(animateClick()));
+
+ setPage(ClassPageId, m_classPage);
+
+ foreach (QWizardPage *p, extensionPages)
+ addPage(p);
+
+ connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentIdChanged(int)));
+}
+
+void FormClassWizardDialog::setSuffixes(const QString &header, const QString &source, const QString &form)
+{
+ m_classPage->setSuffixes(header, source, form);
+}
+
+QString FormClassWizardDialog::path() const
+{
+ return m_classPage->path();
+}
+
+void FormClassWizardDialog::setPath(const QString &p)
+{
+ m_classPage->setPath(p);
+}
+
+bool FormClassWizardDialog::validateCurrentPage()
+{
+ return QWizard::validateCurrentPage();
+}
+
+void FormClassWizardDialog::slotCurrentIdChanged(int id)
+{
+ // Switching from form to class page: store XML template and set a suitable
+ // class name in the class page based on the form base class
+ if (id == ClassPageId) {
+ QString formBaseClass;
+ QString uiClassName;
+ m_rawFormTemplate = m_formPage->templateContents();
+ // Strip namespaces from the ui class and suggest it as a new class
+ // name
+ if (FormTemplateWizardPagePage::getUIXmlData(m_rawFormTemplate, &formBaseClass, &uiClassName))
+ m_classPage->setClassName(FormTemplateWizardPagePage::stripNamespaces(uiClassName));
+ }
+}
+
+FormClassWizardParameters FormClassWizardDialog::parameters() const
+{
+ FormClassWizardParameters rc;
+ m_classPage->getParameters(&rc);
+ // Name the ui class in the Ui namespace after the class specified
+ rc.uiTemplate = FormTemplateWizardPagePage::changeUiClassName(m_rawFormTemplate, rc.className);
+ return rc;
+}
+
+} // namespace Internal
+} // namespace Designer
diff --git a/src/plugins/designer/cpp/formclasswizarddialog.h b/src/plugins/designer/cpp/formclasswizarddialog.h
new file mode 100644
index 0000000000..849a1cca6b
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizarddialog.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMCLASSWIZARDDIALOG_H
+#define FORMCLASSWIZARDDIALOG_H
+
+#include <QtGui/QWizard>
+
+namespace Core {
+ class ICore;
+}
+
+namespace Designer {
+namespace Internal {
+
+struct FormClassWizardParameters;
+class FormClassWizardPage;
+class FormTemplateWizardPagePage;
+
+class FormClassWizardDialog : public QWizard
+{
+ Q_DISABLE_COPY(FormClassWizardDialog)
+ Q_OBJECT
+
+public:
+ typedef QList<QWizardPage *> WizardPageList;
+
+ explicit FormClassWizardDialog(const WizardPageList &extensionPages,
+ QWidget *parent = 0);
+
+ void setSuffixes(const QString &header, const QString &source, const QString &form);
+
+ QString path() const;
+
+ FormClassWizardParameters parameters() const;
+
+ bool validateCurrentPage();
+
+public slots:
+ void setPath(const QString &);
+
+private slots:
+ void slotCurrentIdChanged(int id);
+
+private:
+ FormTemplateWizardPagePage *m_formPage;
+ FormClassWizardPage *m_classPage;
+ QString m_rawFormTemplate;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // FORMCLASSWIZARDDIALOG_H
diff --git a/src/plugins/designer/cpp/formclasswizardpage.cpp b/src/plugins/designer/cpp/formclasswizardpage.cpp
new file mode 100644
index 0000000000..a65cc21939
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizardpage.cpp
@@ -0,0 +1,209 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formclasswizardpage.h"
+#include "ui_formclasswizardpage.h"
+#include "formclasswizardparameters.h"
+
+#include <coreplugin/icore.h>
+#include <cppeditor/cppeditorconstants.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QAbstractButton>
+
+static const char *formClassWizardPageGroupC = "FormClassWizardPage";
+static const char *translationKeyC = "RetranslationSupport";
+static const char *embeddingModeKeyC = "Embedding";
+
+namespace Designer {
+namespace Internal {
+
+// ----------------- FormClassWizardPage
+
+FormClassWizardPage::FormClassWizardPage(QWidget * parent) :
+ QWizardPage(parent),
+ m_ui(new Ui::FormClassWizardPage),
+ m_isValid(false)
+{
+ m_ui->setupUi(this);
+
+ m_ui->newClassWidget->setBaseClassInputVisible(false);
+ m_ui->newClassWidget->setNamespacesEnabled(true);
+
+ connect(m_ui->newClassWidget, SIGNAL(validChanged()), this, SLOT(slotValidChanged()));
+
+ m_ui->extensionWidget->setVisible(false);
+ connect(m_ui->moreButton, SIGNAL(clicked(bool)), m_ui->extensionWidget, SLOT(setVisible(bool)));
+
+ restoreSettings();
+}
+
+FormClassWizardPage::~FormClassWizardPage()
+{
+ delete m_ui;
+}
+
+void FormClassWizardPage::setSuffixes(const QString &header, const QString &source, const QString &form)
+{
+ m_ui->newClassWidget->setSourceExtension(source);
+ m_ui->newClassWidget->setHeaderExtension(header);
+ m_ui->newClassWidget->setFormExtension(form);
+}
+
+void FormClassWizardPage::setClassName(const QString &suggestedClassName)
+{
+ // Is it valid, now?
+ m_ui->newClassWidget->setClassName(suggestedClassName);
+ slotValidChanged();
+}
+
+int FormClassWizardPage::uiClassEmbedding() const
+{
+ if (m_ui->ptrAggregationRadioButton->isChecked())
+ return PointerAggregatedUiClass;
+ if (m_ui->aggregationButton->isChecked())
+ return AggregatedUiClass;
+ return InheritedUiClass;
+}
+
+void FormClassWizardPage::setUiClassEmbedding(int v)
+{
+ switch (v) {
+ case PointerAggregatedUiClass:
+ m_ui->ptrAggregationRadioButton->setChecked(true);
+ break;
+ case AggregatedUiClass:
+ m_ui->aggregationButton->setChecked(true);
+ break;
+ case InheritedUiClass:
+ m_ui->multipleInheritanceButton->setChecked(true);
+ break;
+ }
+}
+
+bool FormClassWizardPage::hasRetranslationSupport() const
+{
+ return m_ui->retranslateCheckBox->isChecked();
+}
+
+void FormClassWizardPage::setRetranslationSupport(bool v)
+{
+ m_ui->retranslateCheckBox->setChecked(v);
+}
+
+QString FormClassWizardPage::path() const
+{
+ return m_ui->newClassWidget->path();
+}
+
+void FormClassWizardPage::setPath(const QString &p)
+{
+ m_ui->newClassWidget->setPath(p);
+}
+
+void FormClassWizardPage::getParameters(FormClassWizardParameters *p) const
+{
+ p->embedding = static_cast<UiClassEmbedding>(uiClassEmbedding());
+ p->languageChange = m_ui->retranslateCheckBox->isChecked();
+ p->className = m_ui->newClassWidget->className();
+ p->path = path();
+ p->sourceFile = m_ui->newClassWidget->sourceFileName();
+ p->headerFile = m_ui->newClassWidget->headerFileName();
+ p->uiFile = m_ui->newClassWidget-> formFileName();
+}
+
+void FormClassWizardPage::slotValidChanged()
+{
+ const bool validNow = m_ui->newClassWidget->isValid();
+ if (m_isValid != validNow) {
+ m_isValid = validNow;
+ emit completeChanged();
+ }
+}
+
+bool FormClassWizardPage::isComplete() const
+{
+ return m_isValid;
+}
+
+bool FormClassWizardPage::validatePage()
+{
+ QString errorMessage;
+ const bool rc = m_ui->newClassWidget->isValid(&errorMessage);
+ if (rc) {
+ saveSettings();
+ } else {
+ QMessageBox::critical(this, tr("%1 - Error").arg(title()), errorMessage);
+ }
+ return rc;
+}
+
+void FormClassWizardPage::saveSettings()
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (QSettings *settings = core->settings()) {
+ settings->beginGroup(QLatin1String(formClassWizardPageGroupC));
+ settings->setValue(QLatin1String(translationKeyC), hasRetranslationSupport());
+ settings->setValue(QLatin1String(embeddingModeKeyC), uiClassEmbedding());
+ settings->endGroup();
+ }
+}
+
+void FormClassWizardPage::restoreSettings()
+{
+ bool retranslationSupport = true;
+ int embedding = PointerAggregatedUiClass;
+
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (QSettings *settings = core->settings()) {
+
+ QString key = QLatin1String(formClassWizardPageGroupC);
+ key += QLatin1Char('/');
+ const int groupLength = key.size();
+
+ key += QLatin1String(translationKeyC);
+ retranslationSupport = settings->value(key, retranslationSupport).toBool();
+
+ key.truncate(groupLength);
+ key += QLatin1String(embeddingModeKeyC);
+ embedding = settings->value(key, embedding).toInt();
+ }
+ setUiClassEmbedding(embedding);
+ setRetranslationSupport(retranslationSupport);
+}
+
+} // namespace Internal
+} // namespace Designer
diff --git a/src/plugins/designer/cpp/formclasswizardpage.h b/src/plugins/designer/cpp/formclasswizardpage.h
new file mode 100644
index 0000000000..1a58feb369
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizardpage.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMCLASSWIZARDPAGE_H
+#define FORMCLASSWIZARDPAGE_H
+
+#include <QtGui/QWizardPage>
+
+namespace Designer {
+namespace Internal {
+
+namespace Ui {
+ class FormClassWizardPage;
+}
+
+struct FormClassWizardParameters;
+
+class FormClassWizardPage : public QWizardPage
+{
+ Q_DISABLE_COPY(FormClassWizardPage)
+ Q_OBJECT
+public:
+ explicit FormClassWizardPage(QWidget * parent = 0);
+ ~FormClassWizardPage();
+
+ void setSuffixes(const QString &header, const QString &source, const QString &form);
+
+ virtual bool isComplete () const;
+ virtual bool validatePage();
+
+ int uiClassEmbedding() const;
+ bool hasRetranslationSupport() const;
+ QString path() const;
+
+ // Fill out applicable parameters
+ void getParameters(FormClassWizardParameters *) const;
+
+public slots:
+ void setClassName(const QString &suggestedClassName);
+ void setPath(const QString &);
+ void setRetranslationSupport(bool);
+ void setUiClassEmbedding(int v);
+
+private slots:
+ void slotValidChanged();
+
+private:
+ void saveSettings();
+ void restoreSettings();
+
+ Ui::FormClassWizardPage *m_ui;
+ bool m_isValid;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //FORMCLASSWIZARDPAGE_H
diff --git a/src/plugins/designer/cpp/formclasswizardpage.ui b/src/plugins/designer/cpp/formclasswizardpage.ui
new file mode 100644
index 0000000000..236e2059ca
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizardpage.ui
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Designer::Internal::FormClassWizardPage</class>
+ <widget class="QWizardPage" name="Designer::Internal::FormClassWizardPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>552</width>
+ <height>498</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Choose a class name</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="classGroupBox">
+ <property name="title">
+ <string>Class</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="Core::Utils::NewClassWidget" name="newClassWidget" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="moreButton">
+ <property name="text">
+ <string>More</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QWidget" name="extensionWidget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="uiclassGroupBox">
+ <property name="title">
+ <string>Embedding of the UI class</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QRadioButton" name="ptrAggregationRadioButton">
+ <property name="text">
+ <string>Aggregation as a pointer member</string>
+ </property>
+ <attribute name="buttonGroup">
+ <string>buttonGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="aggregationButton">
+ <property name="text">
+ <string>Aggregation</string>
+ </property>
+ <attribute name="buttonGroup">
+ <string>buttonGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="multipleInheritanceButton">
+ <property name="text">
+ <string>Multiple Inheritance</string>
+ </property>
+ <attribute name="buttonGroup">
+ <string>buttonGroup</string>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ <zorder>aggregationButton</zorder>
+ <zorder>multipleInheritanceButton</zorder>
+ <zorder>ptrAggregationRadioButton</zorder>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="variousGroupBox">
+ <property name="title">
+ <string/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="retranslateCheckBox">
+ <property name="text">
+ <string>Support for changing languages at runtime</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>57</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::NewClassWidget</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/newclasswidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+ <buttongroups>
+ <buttongroup name="buttonGroup"/>
+ </buttongroups>
+</ui>
diff --git a/src/plugins/designer/cpp/formclasswizardparameters.cpp b/src/plugins/designer/cpp/formclasswizardparameters.cpp
new file mode 100644
index 0000000000..0d7fc70102
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizardparameters.cpp
@@ -0,0 +1,174 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formclasswizardparameters.h"
+#include "formtemplatewizardpage.h"
+
+#include <utils/codegeneration.h>
+
+#include <QtCore/QTextStream>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+static const char *uiMemberC = "m_ui";
+static const char *uiNamespaceC = "Ui";
+
+namespace Designer {
+namespace Internal {
+
+FormClassWizardParameters::FormClassWizardParameters() :
+ embedding(PointerAggregatedUiClass),
+ languageChange(true)
+{
+}
+
+bool FormClassWizardParameters::generateCpp(QString *header, QString *source, int indentation) const
+{
+ const QString indent = QString(indentation, QLatin1Char(' '));
+ QString formBaseClass;
+ QString uiClassName;
+ if (!FormTemplateWizardPagePage::getUIXmlData(uiTemplate, &formBaseClass, &uiClassName)) {
+ qWarning("Unable to determine the form base class from %s.", uiTemplate.toUtf8().constData());
+ return false;
+ }
+
+ // Do we have namespaces?
+ QStringList namespaceList = className.split(QLatin1String("::"));
+ if (namespaceList.empty()) // Paranoia!
+ return false;
+
+ const QString unqualifiedClassName = namespaceList.takeLast();
+
+ // Include guards
+ const QString guard = Core::Utils::headerGuard(unqualifiedClassName);
+
+ QString uiInclude = QLatin1String("ui_");
+ uiInclude += QFileInfo(uiFile).baseName();
+ uiInclude += QLatin1String(".h");
+
+ // 1) Header file
+ QTextStream headerStr(header);
+ headerStr << "#ifndef " << guard
+ << "\n#define " << guard << '\n' << '\n';
+
+ // Include 'ui_'
+ if (embedding != PointerAggregatedUiClass) {
+ Core::Utils::writeIncludeFileDirective(uiInclude, false, headerStr);
+ } else {
+ // Todo: Can we obtain the header from the code model for custom widgets?
+ // Alternatively, from Designer.
+ if (formBaseClass.startsWith(QLatin1Char('Q'))) {
+ QString baseInclude = QLatin1String("QtGui/");
+ baseInclude += formBaseClass;
+ Core::Utils::writeIncludeFileDirective(baseInclude, true, headerStr);
+ }
+ }
+
+ // Forward-declare the UI class
+ if (embedding == PointerAggregatedUiClass) {
+ headerStr << "\nnamespace " << uiNamespaceC << " {\n"
+ << indent << "class " << uiClassName << ";\n}\n";
+ }
+
+ const QString namespaceIndent = Core::Utils::writeOpeningNameSpaces(namespaceList, indent, headerStr);
+ // Class declaration
+ headerStr << '\n' << namespaceIndent << "class " << unqualifiedClassName
+ << " : public " << formBaseClass;
+ if (embedding == InheritedUiClass) {
+ headerStr << ", private " << uiNamespaceC << "::" << uiClassName;
+ }
+ headerStr << " {\n" << namespaceIndent << indent << "Q_OBJECT\n"
+ << namespaceIndent << indent << "Q_DISABLE_COPY(" << unqualifiedClassName << ")\n"
+ << namespaceIndent << "public:\n"
+ << namespaceIndent << indent << "explicit " << unqualifiedClassName << "(QWidget *parent = 0);\n";
+ if (embedding == PointerAggregatedUiClass)
+ headerStr << namespaceIndent << indent << "virtual ~" << unqualifiedClassName << "();\n";
+ // retranslation
+ if (languageChange)
+ headerStr << '\n' << namespaceIndent << "protected:\n"
+ << namespaceIndent << indent << "virtual void changeEvent(QEvent *e);\n";
+ // Member variable
+ if (embedding != InheritedUiClass) {
+ headerStr << '\n' << namespaceIndent << "private:\n"
+ << namespaceIndent << indent << uiNamespaceC << "::" << uiClassName << ' ';
+ if (embedding == PointerAggregatedUiClass)
+ headerStr << '*';
+ headerStr << uiMemberC << ";\n";
+ }
+ headerStr << namespaceIndent << "};\n\n";
+ Core::Utils::writeClosingNameSpaces(namespaceList, indent, headerStr);
+ headerStr << "#endif // "<< guard << '\n';
+
+ // 2) Source file
+ QTextStream sourceStr(source);
+ Core::Utils::writeIncludeFileDirective(headerFile, false, sourceStr);
+ if (embedding == PointerAggregatedUiClass)
+ Core::Utils::writeIncludeFileDirective(uiInclude, false, sourceStr);
+ // NameSpaces(
+ Core::Utils::writeOpeningNameSpaces(namespaceList, indent, sourceStr);
+ // Constructor with setupUi
+ sourceStr << '\n' << namespaceIndent << unqualifiedClassName << "::" << unqualifiedClassName << "(QWidget *parent) :\n"
+ << namespaceIndent << indent << formBaseClass << "(parent)";
+ if (embedding == PointerAggregatedUiClass)
+ sourceStr << ",\n" << namespaceIndent << indent << uiMemberC << "(new " << uiNamespaceC << "::" << uiClassName << ")\n";
+ sourceStr << namespaceIndent << "{\n" << namespaceIndent << indent;
+ if (embedding != InheritedUiClass)
+ sourceStr << uiMemberC << (embedding == PointerAggregatedUiClass ? "->" : ".");
+ sourceStr << "setupUi(this);\n" << namespaceIndent << "}\n";
+ // Deleting destructor for ptr
+ if (embedding == PointerAggregatedUiClass) {
+ sourceStr << '\n' << namespaceIndent << unqualifiedClassName << "::~" << unqualifiedClassName
+ << "()\n" << namespaceIndent << "{\n"
+ << namespaceIndent << indent << "delete " << uiMemberC << ";\n"
+ << namespaceIndent << "}\n";
+ }
+ // retranslation
+ if (languageChange) {
+ sourceStr << '\n' << namespaceIndent << "void " << unqualifiedClassName << "::" << "changeEvent(QEvent *e)\n"
+ << namespaceIndent << "{\n"
+ << namespaceIndent << indent << "switch(e->type()) {\n" << namespaceIndent << indent << "case QEvent::LanguageChange:\n"
+ << namespaceIndent << indent << indent;
+ if (embedding != InheritedUiClass)
+ sourceStr << uiMemberC << (embedding == PointerAggregatedUiClass ? "->" : ".");
+ sourceStr << "retranslateUi(this);\n"
+ << namespaceIndent << indent << indent << "break;\n"
+ << namespaceIndent << indent << "default:\n"
+ << namespaceIndent << indent << indent << "break;\n"
+ << namespaceIndent << indent << "}\n"
+ << namespaceIndent << "}\n";
+ }
+ Core::Utils::writeClosingNameSpaces(namespaceList, indent, sourceStr);
+ return true;
+}
+
+} // namespace Internal
+} // namespace Designer
diff --git a/src/plugins/designer/cpp/formclasswizardparameters.h b/src/plugins/designer/cpp/formclasswizardparameters.h
new file mode 100644
index 0000000000..4a51444531
--- /dev/null
+++ b/src/plugins/designer/cpp/formclasswizardparameters.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMCLASSWIZARDPARAMETERS_H
+#define FORMCLASSWIZARDPARAMETERS_H
+
+#include <QtCore/QString>
+
+namespace Designer {
+namespace Internal {
+
+
+enum UiClassEmbedding {
+ PointerAggregatedUiClass,
+ AggregatedUiClass,
+ InheritedUiClass
+};
+
+struct FormClassWizardParameters {
+ explicit FormClassWizardParameters();
+
+ bool generateCpp(QString *header, QString *source, int indentation = 4) const;
+
+ UiClassEmbedding embedding;
+ bool languageChange; // Add handling for language change events
+ QString uiTemplate;
+ QString className;
+
+ QString path;
+ QString sourceFile;
+ QString headerFile;
+ QString uiFile;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // FORMCLASSWIZARDPARAMETERS_H
diff --git a/src/plugins/designer/designer.pro b/src/plugins/designer/designer.pro
new file mode 100644
index 0000000000..a039bf2991
--- /dev/null
+++ b/src/plugins/designer/designer.pro
@@ -0,0 +1,57 @@
+TEMPLATE = lib
+TARGET = Designer
+
+include(../../qworkbenchplugin.pri)
+include(../../../shared/designerintegrationv2/designerintegration.pri)
+include(cpp/cpp.pri)
+include(designer_dependencies.pri)
+
+# -- check the Qt version
+TOO_OLD_LIST=$$find(QT_VERSION, ^4\.[0-4])
+count(TOO_OLD_LIST, 1) {
+ error("Cannot build the designer plugin with a Qt version that old:" $$QT_VERSION)
+}
+# -- figure out shared dir location
+!exists($$[QT_INSTALL_HEADERS]/QtDesigner/private/qdesigner_integration_p.h) {
+ QT_SOURCE_TREE=$$fromfile($$(QTDIR)/.qmake.cache,QT_SOURCE_TREE)
+ INCLUDEPATH += $$QT_SOURCE_TREE/include
+}
+
+INCLUDEPATH += $$QMAKE_INCDIR_QT/QtDesigner \
+ ../../tools/utils
+
+qtAddLibrary(QtDesigner)
+qtAddLibrary(QtDesignerComponents)
+
+QT+=xml
+
+HEADERS += formeditorplugin.h \
+ formeditorfactory.h \
+ formwindoweditor.h \
+ formwindowfile.h \
+ formwindowhost.h \
+ formwizard.h \
+ workbenchintegration.h \
+ designerconstants.h \
+ settingspage.h \
+ editorwidget.h \
+ formeditorw.h \
+ settingsmanager.h \
+ formtemplatewizardpage.h \
+ formwizarddialog.h
+
+SOURCES += formeditorplugin.cpp \
+ formeditorfactory.cpp \
+ formwindoweditor.cpp \
+ formwindowfile.cpp \
+ formwindowhost.cpp \
+ formwizard.cpp \
+ workbenchintegration.cpp \
+ settingspage.cpp \
+ editorwidget.cpp \
+ formeditorw.cpp \
+ settingsmanager.cpp \
+ formtemplatewizardpage.cpp \
+ formwizarddialog.cpp
+
+RESOURCES += designer.qrc
diff --git a/src/plugins/designer/designer.qrc b/src/plugins/designer/designer.qrc
new file mode 100644
index 0000000000..7565ed0032
--- /dev/null
+++ b/src/plugins/designer/designer.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/formeditor" >
+ <file>images/qt_ui.png</file>
+ <file>Designer.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/designer/designer_dependencies.pri b/src/plugins/designer/designer_dependencies.pri
new file mode 100644
index 0000000000..4c98d46428
--- /dev/null
+++ b/src/plugins/designer/designer_dependencies.pri
@@ -0,0 +1,3 @@
+include(../../plugins/cppeditor/cppeditor.pri)
+include(../../libs/utils/utils.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/designer/designerconstants.h b/src/plugins/designer/designerconstants.h
new file mode 100644
index 0000000000..28252e608a
--- /dev/null
+++ b/src/plugins/designer/designerconstants.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DESIGNERPLUGIN_CONSTANTS_H
+#define DESIGNERPLUGIN_CONSTANTS_H
+
+namespace Designer {
+ namespace Constants {
+ // context
+ const char * const C_FORMEDITOR = "Formeditor";
+ const char * const T_FORMEDITOR = "Formeditor.Toolbar";
+ const char * const M_FORMEDITOR = "Formeditor.Menu";
+ const char * const M_FORMEDITOR_PREVIEW = "Formeditor.Menu.Preview";
+ const char * const C_FORMWINDOW = "Formwindow";
+ // Wizard type
+ const char * const FORM_FILE_TYPE = "Qt4FormFiles";
+ const char * const FORM_MIMETYPE = "application/x-designer";
+
+ enum DesignerSubWindows {
+ WidgetBoxSubWindow,
+ ObjectInspectorSubWindow,
+ PropertyEditorSubWindow,
+ SignalSlotEditorSubWindow,
+ ActionEditorSubWindow,
+ DesignerSubWindowCount };
+
+ enum EditModes {
+ EditModeWidgetEditor,
+ EditModeSignalsSlotEditor,
+ EditModeBuddyEditor,
+ EditModeTabOrderEditor,
+ NumEditModes };
+ }
+}
+
+#endif //DESIGNERPLUGIN_CONSTANTS_H
diff --git a/src/plugins/designer/editorwidget.cpp b/src/plugins/designer/editorwidget.cpp
new file mode 100644
index 0000000000..c164ddfe23
--- /dev/null
+++ b/src/plugins/designer/editorwidget.cpp
@@ -0,0 +1,270 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+
+#include "editorwidget.h"
+#include "formeditorw.h"
+
+#include <QtCore/QEvent>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QTabWidget>
+#include <coreplugin/minisplitter.h>
+
+using namespace Designer::Constants;
+
+enum { ActionEditorTab, SignalSlotEditorTab };
+
+enum { wantSignalSlotEditor = 0 };
+
+namespace Designer {
+namespace Internal {
+
+ SharedSubWindow::SharedSubWindow(QWidget *shared, QWidget *parent) :
+ QWidget(parent),
+ m_shared(shared),
+ m_layout(new QVBoxLayout)
+ {
+ Q_ASSERT(m_shared);
+ m_layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(m_layout);
+ }
+
+ void SharedSubWindow::activate()
+ {
+ // Take the widget off the other parent
+ Q_ASSERT(m_shared);
+ QWidget *currentParent = m_shared->parentWidget();
+ if (currentParent == this)
+ return;
+
+ if (currentParent) {
+ QVBoxLayout *lt = qobject_cast<QVBoxLayout *>(currentParent->layout());
+ Q_ASSERT(lt);
+ m_shared->setParent(0);
+ delete lt->takeAt(0);
+ }
+ m_layout->addWidget(m_shared);
+ m_layout->invalidate();
+ }
+
+ SharedSubWindow::~SharedSubWindow()
+ {
+ // Do not destroy the shared sub window if we currently own it
+ if (m_layout->count()) {
+ m_shared->setParent(0);
+ delete m_layout->takeAt(0);
+ }
+ }
+
+ // ---------- Global EditorState
+ Q_GLOBAL_STATIC(EditorWidgetState, editorWidgetState)
+
+ enum { Version = 1 };
+ // Simple conversion of an int list to QVariantList, size as leading element
+ static void intToVariantList(const QList<int> &il, QVariantList& vl)
+ {
+ const int size = il.size();
+ vl.push_back(size);
+ if (size != 0) {
+ const QList<int>::const_iterator cend = il.constEnd();
+ for (QList<int>::const_iterator it = il.constBegin(); it != cend; ++it)
+ vl.push_back(QVariant(*it));
+ }
+ }
+ // Simple conversion of a QVariantList portion saved by the above function to int list
+ bool variantListToIntList(const QVariantList& vl, int &index, QList<int> &list)
+ {
+ list.clear();
+ if (index >= vl.size())
+ return false;
+ const int size = vl.at(index++).toInt();
+ const int end = index + size;
+ if (end > vl.size())
+ return false;
+ if (size != 0) {
+ for ( ; index < end; index++)
+ list.push_back(vl.at(index).toInt());
+ }
+ return true;
+ }
+
+ // ------------------ EditorWidgetState
+ QVariant EditorWidgetState::toVariant() const
+ {
+ QVariantList rc;
+ rc.push_back(Version);
+ intToVariantList(horizontalSizes, rc);
+ intToVariantList(centerVerticalSizes, rc);
+ intToVariantList(rightVerticalSizes, rc);
+ return QVariant(rc);
+ }
+
+ bool EditorWidgetState::fromVariant(const QVariant &v)
+ {
+ // Restore state. The weird thing is that QSettings might return
+ // a QStringList although it was saved as QVariantList<int>.
+ if (v.type() != QVariant::List && v.type() != QVariant::StringList)
+ return false;
+ const QVariantList vl = v.toList();
+ if (vl.empty())
+ return false;
+ int index = 0;
+ const QVariant &versionV = vl.at(index++);
+ if (versionV.type() != QVariant::Int && versionV.type() != QVariant::String)
+ return false;
+ if (versionV.toInt() > Version)
+ return false;
+ return variantListToIntList(vl, index, horizontalSizes) &&
+ variantListToIntList(vl, index, centerVerticalSizes) &&
+ variantListToIntList(vl, index, rightVerticalSizes);
+ }
+
+ // ---------- EditorWidget
+ EditorWidget::EditorWidget(QWidget *formWindow) :
+ Core::MiniSplitter(Qt::Horizontal),
+ m_centerVertSplitter(new Core::MiniSplitter(Qt::Vertical)),
+ m_bottomTab(0),
+ m_rightVertSplitter(new Core::MiniSplitter(Qt::Vertical))
+ {
+ // Get shared sub windows from Form Editor
+ FormEditorW *few = FormEditorW::instance();
+ QWidget * const*subs = few->designerSubWindows();
+ // Create shared sub windows except SignalSlotEditor
+ qFill(m_designerSubWindows, m_designerSubWindows + DesignerSubWindowCount, static_cast<SharedSubWindow*>(0));
+ for (int i=0; i < DesignerSubWindowCount; i++)
+ if (wantSignalSlotEditor || i != SignalSlotEditorSubWindow)
+ m_designerSubWindows[i] = new SharedSubWindow(subs[i]);
+ // Create splitter
+ addWidget(m_designerSubWindows[WidgetBoxSubWindow]);
+
+ // center
+ m_centerVertSplitter->addWidget(formWindow);
+
+ if (wantSignalSlotEditor) {
+ m_bottomTab = new QTabWidget;
+ m_bottomTab->setTabPosition(QTabWidget::South);
+ m_bottomTab->addTab(m_designerSubWindows[ActionEditorSubWindow], tr("Action editor"));
+ m_bottomTab->addTab(m_designerSubWindows[SignalSlotEditorSubWindow], tr("Signals and slots editor"));
+ m_centerVertSplitter->addWidget(m_bottomTab);
+ } else {
+ m_centerVertSplitter->addWidget(m_designerSubWindows[ActionEditorSubWindow]);
+ }
+
+ addWidget(m_centerVertSplitter);
+
+ m_rightVertSplitter->addWidget(m_designerSubWindows[ObjectInspectorSubWindow]);
+ m_rightVertSplitter->addWidget(m_designerSubWindows[PropertyEditorSubWindow]);
+ addWidget(m_rightVertSplitter);
+ }
+
+ void EditorWidget::setInitialSizes()
+ {
+ QList<int> sizes;
+ // center vertical. Either the tab containing signal slot editor/
+ // action editor or the action editor itself
+ const QWidget *bottomWidget = m_bottomTab;
+ if (!bottomWidget)
+ bottomWidget = m_designerSubWindows[ActionEditorSubWindow];
+ const int tabHeight = bottomWidget->sizeHint().height();
+ sizes.push_back(height() - handleWidth() - tabHeight);
+ sizes.push_back( tabHeight);
+ m_centerVertSplitter->setSizes(sizes);
+ // right vert
+ sizes.clear();
+ sizes.push_back(height() /2 - (handleWidth() / 2));
+ sizes.push_back(height() / 2 - (handleWidth() / 2));
+ m_rightVertSplitter->setSizes(sizes);
+ // horiz sizes
+ sizes.clear();
+ const int wboxWidth = m_designerSubWindows[WidgetBoxSubWindow]->sizeHint().width();
+ const int vSplitterWidth = m_rightVertSplitter->sizeHint().width();
+ sizes.push_back(wboxWidth);
+ sizes.push_back(width() - 2 * handleWidth() - wboxWidth - vSplitterWidth);
+ sizes.push_back(vSplitterWidth);
+ setSizes(sizes);
+ }
+
+ void EditorWidget::activate()
+ {
+ for (int i=0; i < DesignerSubWindowCount; i++)
+ if (SharedSubWindow *sw = m_designerSubWindows[i]) // Signal slot might be deactivated
+ sw->activate();
+ if (!restore(*editorWidgetState()))
+ setInitialSizes();
+ }
+
+ bool EditorWidget::event(QEvent * e)
+ {
+ if (e->type() == QEvent::Hide)
+ *editorWidgetState() = save();
+ return QSplitter::event(e);
+ }
+
+ EditorWidgetState EditorWidget::save() const
+ {
+ EditorWidgetState rc;
+ rc.horizontalSizes = sizes();
+ rc.centerVerticalSizes = m_centerVertSplitter->sizes();
+ rc.rightVerticalSizes = m_rightVertSplitter->sizes();
+ return rc;
+ }
+
+ bool EditorWidget::restore(const EditorWidgetState &s)
+ {
+ if (s.horizontalSizes.size() != count() ||
+ s.centerVerticalSizes.size() != m_centerVertSplitter->count() ||
+ s.rightVerticalSizes.size() != m_rightVertSplitter->count())
+ return false;
+ m_centerVertSplitter->setSizes(s.centerVerticalSizes);
+ m_rightVertSplitter->setSizes(s.rightVerticalSizes);
+ setSizes(s.horizontalSizes);
+ return true;
+ }
+
+ void EditorWidget::toolChanged(int i)
+ {
+ if (m_bottomTab)
+ m_bottomTab->setCurrentIndex(i == EditModeSignalsSlotEditor ? SignalSlotEditorTab : ActionEditorTab);
+ }
+
+ EditorWidgetState EditorWidget::state()
+ {
+ return *editorWidgetState();
+ }
+
+ void EditorWidget::setState(const EditorWidgetState& st)
+ {
+ *editorWidgetState() = st;
+ }
+}
+}
diff --git a/src/plugins/designer/editorwidget.h b/src/plugins/designer/editorwidget.h
new file mode 100644
index 0000000000..790550cb3e
--- /dev/null
+++ b/src/plugins/designer/editorwidget.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DESIGNER_EDITORWIDGET_H
+#define DESIGNER_EDITORWIDGET_H
+
+#include "designerconstants.h"
+
+#include <coreplugin/minisplitter.h>
+
+#include <QtCore/QPointer>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QTabWidget;
+class QVBoxLayout;
+QT_END_NAMESPACE
+
+namespace Designer {
+namespace Internal {
+
+ /* A widget that shares its embedded sub window with others. For example,
+ * the designer editors need to share the widget box, etc. */
+ class SharedSubWindow : public QWidget {
+ Q_OBJECT
+ Q_DISABLE_COPY(SharedSubWindow)
+
+ public:
+ SharedSubWindow(QWidget *shared, QWidget *parent = 0);
+ virtual ~SharedSubWindow();
+
+ public slots:
+ // Takes the shared widget off the current parent and adds it to its
+ // layout
+ void activate();
+
+ private:
+ QPointer <QWidget> m_shared;
+ QVBoxLayout *m_layout;
+ };
+
+ /** State of the editor window (splitter sizes)
+ * Shared as a global struct between the instances and stored
+ * in QSettings. */
+ struct EditorWidgetState {
+ QVariant toVariant() const; // API to conveniently store in QSettings
+ bool fromVariant(const QVariant &v);
+
+ QList<int> horizontalSizes;
+ QList<int> centerVerticalSizes;
+ QList<int> rightVerticalSizes;
+ };
+
+ /* Form editor splitter used as editor window. Contains the shared designer
+ * windows. */
+ class EditorWidget : public Core::MiniSplitter {
+ Q_OBJECT
+ Q_DISABLE_COPY(EditorWidget)
+ public:
+ explicit EditorWidget(QWidget *formWindow);
+
+ virtual bool event(QEvent * e);
+
+ EditorWidgetState save() const;
+ bool restore(const EditorWidgetState &s);
+
+ // Get/Set the shared splitter state of all editors of that type for
+ // settings
+ static EditorWidgetState state();
+ static void setState(const EditorWidgetState&st);
+
+ public slots:
+ void activate();
+ void toolChanged(int);
+
+ private:
+ void setInitialSizes();
+
+ SharedSubWindow* m_designerSubWindows[Designer::Constants::DesignerSubWindowCount];
+ QSplitter *m_centerVertSplitter;
+ QTabWidget *m_bottomTab;
+ QSplitter *m_rightVertSplitter;
+ };
+}
+}
+
+#endif
diff --git a/src/plugins/designer/formeditorfactory.cpp b/src/plugins/designer/formeditorfactory.cpp
new file mode 100644
index 0000000000..29ceb8b06c
--- /dev/null
+++ b/src/plugins/designer/formeditorfactory.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formeditorfactory.h"
+#include "formeditorw.h"
+#include "formwindoweditor.h"
+#include "designerconstants.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+using namespace Designer::Internal;
+using namespace Designer::Constants;
+
+FormEditorFactory::FormEditorFactory(Core::ICore *core) :
+ Core::IEditorFactory(core),
+ m_kind(QLatin1String(C_FORMEDITOR)),
+ m_mimeTypes(QLatin1String(FORM_MIMETYPE)),
+ m_core(core)
+{
+ Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
+ iconProvider->registerIconForSuffix(QIcon(":/formeditor/images/qt_ui.png"),
+ QLatin1String("ui"));
+}
+
+QString FormEditorFactory::kind() const
+{
+ return C_FORMEDITOR;
+}
+
+Core::IFile *FormEditorFactory::open(const QString &fileName)
+{
+ Core::IEditor *iface = m_core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *FormEditorFactory::createEditor(QWidget *parent)
+{
+ return FormEditorW::instance()->createFormWindowEditor(parent);
+}
+
+QStringList FormEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
diff --git a/src/plugins/designer/formeditorfactory.h b/src/plugins/designer/formeditorfactory.h
new file mode 100644
index 0000000000..5e8c7c2abf
--- /dev/null
+++ b/src/plugins/designer/formeditorfactory.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMEDITORFACTORY_H
+#define FORMEDITORFACTORY_H
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+#include <QtCore/QStringList>
+
+namespace Core {
+class ICore;
+class IEditor;
+class IFile;
+}
+
+namespace Designer {
+namespace Internal {
+
+class FormEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ FormEditorFactory(Core::ICore *core);
+
+ virtual QStringList mimeTypes() const;
+ //EditorFactory
+ virtual QString kind() const;
+ Core::IFile *open(const QString &fileName);
+ Core::IEditor *createEditor(QWidget *parent);
+
+private:
+ const QString m_kind;
+ const QStringList m_mimeTypes;
+ Core::ICore *m_core;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif
+
diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp
new file mode 100644
index 0000000000..eacc1f5312
--- /dev/null
+++ b/src/plugins/designer/formeditorplugin.cpp
@@ -0,0 +1,146 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formeditorplugin.h"
+#include "formeditorfactory.h"
+#include "formeditorw.h"
+#include "formwizard.h"
+
+#ifdef CPP_ENABLED
+# include "formclasswizard.h"
+# include <cppeditor/cppeditorconstants.h>
+#endif
+
+#include "designerconstants.h"
+#if QT_VERSION < 0x040500
+# include "settings.h"
+#endif
+
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+
+#ifdef CPP_ENABLED
+# include <QtGui/QAction>
+# include <QtGui/QWizard>
+# include <QtGui/QMainWindow>
+#endif
+
+using namespace Designer::Internal;
+using namespace Designer::Constants;
+
+FormEditorPlugin::FormEditorPlugin() :
+ m_factory(0),
+ m_formWizard(0),
+ m_formClassWizard(0)
+{
+}
+
+FormEditorPlugin::~FormEditorPlugin()
+{
+ if (m_factory)
+ removeObject(m_factory);
+ if (m_formWizard)
+ removeObject(m_formWizard);
+ if (m_formClassWizard)
+ removeObject(m_formClassWizard);
+ delete m_factory;
+ delete m_formWizard;
+ delete m_formClassWizard;
+ FormEditorW::deleteInstance();
+}
+
+////////////////////////////////////////////////////
+//
+// INHERITED FROM ExtensionSystem::Plugin
+//
+////////////////////////////////////////////////////
+bool FormEditorPlugin::initialize(const QStringList & /*arguments*/, QString *error_message/* = 0*/) // =0;
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/formeditor/Designer.mimetypes.xml"), error_message))
+ return false;
+
+ if (!initializeTemplates(error_message))
+ return false;
+
+ const int uid = core->uniqueIDManager()->uniqueIdentifier(QLatin1String(C_FORMEDITOR));
+ const QList<int> context = QList<int>() << uid;
+
+ m_factory = new FormEditorFactory(core);
+ addObject(m_factory);
+
+ // Make sure settings pages and action shortcuts are registered
+ FormEditorW::ensureInitStage(FormEditorW::RegisterPlugins);
+
+ error_message->clear();
+ return true;
+}
+
+void FormEditorPlugin::extensionsInitialized()
+{
+}
+
+////////////////////////////////////////////////////
+//
+// PRIVATE methods
+//
+////////////////////////////////////////////////////
+
+bool FormEditorPlugin::initializeTemplates(QString * /* error_message */)
+{
+
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ FormWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+ wizardParameters.setCategory(QLatin1String("Qt"));
+ wizardParameters.setTrCategory(tr("Qt"));
+ const QString formFileType = QLatin1String(Constants::FORM_FILE_TYPE);
+ wizardParameters.setName(tr("Qt Designer Form"));
+ wizardParameters.setDescription(tr("This creates a new Qt Designer form file."));
+ m_formWizard = new FormWizard(wizardParameters, core, this);
+ addObject(m_formWizard);
+
+#ifdef CPP_ENABLED
+ wizardParameters.setKind(Core::IWizard::ClassWizard);
+ wizardParameters.setName(tr("Qt Designer Form Class"));
+ wizardParameters.setDescription(tr("This creates a new Qt Designer form class."));
+ m_formClassWizard = new FormClassWizard(wizardParameters, core, this);
+ addObject(m_formClassWizard);
+#endif
+ return true;
+}
+
+Q_EXPORT_PLUGIN(FormEditorPlugin)
diff --git a/src/plugins/designer/formeditorplugin.h b/src/plugins/designer/formeditorplugin.h
new file mode 100644
index 0000000000..01dbb1d236
--- /dev/null
+++ b/src/plugins/designer/formeditorplugin.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMEDITORPLUGIN_H
+#define FORMEDITORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+namespace Core {
+ class IWizard;
+ class ICore;
+}
+
+namespace Designer {
+namespace Internal {
+
+class FormEditorFactory;
+class FormWizard;
+class FormEditorW;
+
+class FormEditorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ FormEditorPlugin();
+ ~FormEditorPlugin();
+
+ //Plugin
+ bool initialize(const QStringList &arguments, QString *error_message = 0);
+ void extensionsInitialized();
+
+private:
+ bool initializeTemplates(QString *error_message);
+
+ FormEditorFactory *m_factory;
+
+ Core::IWizard *m_formWizard;
+ Core::IWizard *m_formClassWizard;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // FORMEDITORPLUGIN_H
diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditorw.cpp
new file mode 100644
index 0000000000..546be02afc
--- /dev/null
+++ b/src/plugins/designer/formeditorw.cpp
@@ -0,0 +1,720 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formeditorw.h"
+#include "formwindoweditor.h"
+#include "designerconstants.h"
+#include "settingsmanager.h"
+#include "settingspage.h"
+#include "editorwidget.h"
+#include "workbenchintegration.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtDesigner/QDesignerFormEditorPluginInterface>
+#include <QtDesigner/private/pluginmanager_p.h>
+
+#include <QtDesigner/private/iconloader_p.h> // createIconSet
+#include <QtDesigner/private/qdesigner_formwindowmanager_p.h>
+#include <QtDesigner/private/formwindowbase_p.h>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerComponents>
+
+#include <QtDesigner/QDesignerWidgetBoxInterface>
+#include <QtDesigner/abstractobjectinspector.h>
+#include <QtDesigner/QDesignerComponents>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+#include <QtDesigner/QDesignerActionEditorInterface>
+
+#include <QtCore/QPluginLoader>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDir>
+#include <QtCore/QTime>
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#include <QtGui/QApplication>
+#include <QtGui/QCursor>
+#include <QtGui/QMenu>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QKeySequence>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QPrinter>
+#include <QtGui/QPainter>
+#include <QtGui/QStatusBar>
+#include <QtGui/QStyle>
+#include <QtGui/QToolBar>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+
+enum { debugFormEditor = 0 };
+enum { wantCodeGenerationAction = 0 };
+
+static const char *editorWidgetStateKeyC = "editorWidgetState";
+static const char *settingsGroup = "Designer";
+
+static inline QIcon designerIcon(const QString &iconName)
+{
+ const QIcon icon = qdesigner_internal::createIconSet(iconName);
+ if (icon.isNull())
+ qWarning() << "Unable to locate " << iconName;
+ return icon;
+}
+
+// Create an action to activate a designer tool
+static inline QAction *createEditModeAction(QActionGroup *ag,
+ const QList<int> &context,
+ Core::ActionManagerInterface *am,
+ Core::IActionContainer *medit,
+ const QString &actionName,
+ const QString &name,
+ int toolNumber,
+ const QString &iconName = QString(),
+ const QString &keySequence = QString())
+{
+ QAction *rc = new QAction(actionName, ag);
+ rc->setCheckable(true);
+ if (!iconName.isEmpty())
+ rc->setIcon(designerIcon(iconName));
+ Core::ICommand *command = am->registerAction(rc, name, context);
+ if (!keySequence.isEmpty())
+ command->setDefaultKeySequence(QKeySequence(keySequence));
+ command->setAttribute(Core::ICommand::CA_Hide);
+ medit->addAction(command, Core::Constants::G_EDIT_OTHER);
+ rc->setData(toolNumber);
+ ag->addAction(rc);
+ return rc;
+}
+
+
+// Create a menu separato
+static inline QAction * createSeparator(QObject *parent,
+ Core::ActionManagerInterface *am,
+ const QList<int> &context,
+ Core::IActionContainer *container,
+ const QString &name = QString(),
+ const QString &group = QString())
+{
+ QAction *actSeparator = new QAction(parent);
+ actSeparator->setSeparator(true);
+ Core::ICommand *command = am->registerAction(actSeparator, name, context);
+ container->addAction(command, group);
+ return actSeparator;
+}
+
+// Create a tool action
+static inline void addToolAction(QAction *a,
+ Core::ActionManagerInterface *am,
+ const QList<int> &context,
+ const QString &name,
+ Core::IActionContainer *c1,
+ const QString &keySequence = QString())
+{
+ Core::ICommand *command = am->registerAction(a, name, context);
+ if (!keySequence.isEmpty())
+ command->setDefaultKeySequence(QKeySequence(keySequence));
+ c1->addAction(command);
+}
+
+// --------- FormEditorW
+
+using namespace Designer::Internal;
+using namespace Designer::Constants;
+
+FormEditorW *FormEditorW::m_self = 0;
+
+FormEditorW::FormEditorW() :
+ m_formeditor(QDesignerComponents::createFormEditor(0)),
+ m_integration(0),
+ m_fwm(0),
+ m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()),
+ m_initStage(RegisterPlugins),
+ m_actionGroupEditMode(0),
+ m_actionPrint(0),
+ m_actionGenerateCode(0)
+{
+ if (debugFormEditor)
+ qDebug() << Q_FUNC_INFO;
+ Q_ASSERT(!m_self);
+ m_self = this;
+ Q_ASSERT(m_core);
+
+ qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount,
+ static_cast<QWidget *>(0));
+
+ m_formeditor->setTopLevel(qobject_cast<QWidget *>(m_core->editorManager()));
+ m_formeditor->setSettingsManager(new SettingsManager());
+
+ m_fwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager*>(m_formeditor->formWindowManager());
+ Q_ASSERT(m_fwm);
+
+ const int uid = m_core->uniqueIDManager()->uniqueIdentifier(QLatin1String(C_FORMEDITOR));
+ m_context << uid;
+
+ setupActions();
+
+ foreach (QDesignerOptionsPageInterface *designerPage, m_formeditor->optionsPages()) {
+ SettingsPage *settingsPage = new SettingsPage(designerPage);
+ ExtensionSystem::PluginManager::instance()->addObject(settingsPage);
+ m_settingsPages.append(settingsPage);
+ }
+ restoreSettings(m_core->settings());
+
+ connect(m_core->editorManager(), SIGNAL(currentEditorChanged(Core::IEditor *)),
+ this, SLOT(currentEditorChanged(Core::IEditor *)));
+}
+
+FormEditorW::~FormEditorW()
+{
+ saveSettings(m_core->settings());
+
+ for (int i = 0; i < Designer::Constants::DesignerSubWindowCount; ++i)
+ delete m_designerSubWindows[i];
+
+ delete m_formeditor;
+ foreach (SettingsPage *settingsPage, m_settingsPages) {
+ ExtensionSystem::PluginManager::instance()->removeObject(settingsPage);
+ delete settingsPage;
+ }
+ delete m_integration;
+ m_self = 0;
+}
+
+void FormEditorW::fullInit()
+{
+ Q_ASSERT(m_initStage == RegisterPlugins);
+ QTime *initTime = 0;
+ if (debugFormEditor) {
+ initTime = new QTime;
+ initTime->start();
+ }
+
+ QDesignerComponents::createTaskMenu(m_formeditor, parent());
+ QDesignerComponents::initializePlugins(designerEditor());
+ QDesignerComponents::initializeResources();
+ initDesignerSubWindows();
+ m_integration = new WorkbenchIntegration(m_formeditor, this);
+ m_formeditor->setIntegration(m_integration);
+
+ /**
+ * This will initialize our TabOrder, Signals and slots and Buddy editors.
+ */
+ QList<QObject*> plugins = QPluginLoader::staticInstances();
+ plugins += m_formeditor->pluginManager()->instances();
+ foreach (QObject *plugin, plugins) {
+ if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) {
+ if (!formEditorPlugin->isInitialized())
+ formEditorPlugin->initialize(m_formeditor);
+ }
+ }
+
+ if (debugFormEditor) {
+ qDebug() << Q_FUNC_INFO << initTime->elapsed() << "ms";
+ delete initTime;
+ }
+ m_initStage = FullyInitialized;
+}
+
+void FormEditorW::initDesignerSubWindows()
+{
+ qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount, static_cast<QWidget*>(0));
+
+ QDesignerWidgetBoxInterface *wb = QDesignerComponents::createWidgetBox(m_formeditor, 0);
+ wb->setWindowTitle(tr("Designer widgetbox"));
+ m_formeditor->setWidgetBox(wb);
+ m_designerSubWindows[WidgetBoxSubWindow] = wb;
+
+ QDesignerObjectInspectorInterface *oi = QDesignerComponents::createObjectInspector(m_formeditor, 0);
+ oi->setWindowTitle(tr("Object inspector"));
+ m_formeditor->setObjectInspector(oi);
+ m_designerSubWindows[ObjectInspectorSubWindow] = oi;
+
+ QDesignerPropertyEditorInterface *pe = QDesignerComponents::createPropertyEditor(m_formeditor, 0);
+ pe->setWindowTitle(tr("Property editor"));
+ m_formeditor->setPropertyEditor(pe);
+ m_designerSubWindows[PropertyEditorSubWindow] = pe;
+
+ QWidget *se = QDesignerComponents::createSignalSlotEditor(m_formeditor, 0);
+ se->setWindowTitle(tr("Signals and slots editor"));
+ m_designerSubWindows[SignalSlotEditorSubWindow] = se;
+
+ QDesignerActionEditorInterface *ae = QDesignerComponents::createActionEditor(m_formeditor, 0);
+ ae->setWindowTitle(tr("Action editor"));
+ m_formeditor->setActionEditor(ae);
+ m_designerSubWindows[ActionEditorSubWindow] = ae;
+}
+
+void FormEditorW::ensureInitStage(InitializationStage s)
+{
+ if (debugFormEditor)
+ qDebug() << Q_FUNC_INFO << s;
+ if (!m_self)
+ m_self = new FormEditorW;
+ if (m_self->m_initStage >= s)
+ return;
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ m_self->fullInit();
+ QApplication::restoreOverrideCursor();
+}
+
+FormEditorW *FormEditorW::instance()
+{
+ ensureInitStage(FullyInitialized);
+ return m_self;
+}
+
+void FormEditorW::deleteInstance()
+{
+ delete m_self;
+}
+
+void FormEditorW::setupActions()
+{
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ Core::ICommand *command;
+
+ //menus
+ Core::IActionContainer *medit =
+ am->actionContainer(Core::Constants::M_EDIT);
+ Core::IActionContainer *mtools =
+ am->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *mformtools =
+ am->createMenu(M_FORMEDITOR);
+ mformtools->menu()->setTitle(tr("For&m editor"));
+ mtools->addMenu(mformtools);
+
+ //overridden actions
+ am->registerAction(m_fwm->actionUndo(), Core::Constants::UNDO, m_context);
+ am->registerAction(m_fwm->actionRedo(), Core::Constants::REDO, m_context);
+ am->registerAction(m_fwm->actionCut(), Core::Constants::CUT, m_context);
+ am->registerAction(m_fwm->actionCopy(), Core::Constants::COPY, m_context);
+ am->registerAction(m_fwm->actionPaste(), Core::Constants::PASTE, m_context);
+ am->registerAction(m_fwm->actionSelectAll(), Core::Constants::SELECTALL, m_context);
+
+ m_actionPrint = new QAction(this);
+ am->registerAction(m_actionPrint, Core::Constants::PRINT, m_context);
+ connect(m_actionPrint, SIGNAL(triggered()), this, SLOT(print()));
+
+ //'delete' action
+ command = am->registerAction(m_fwm->actionDelete(), QLatin1String("FormEditor.Edit.Delete"), m_context);
+ command->setDefaultKeySequence(QKeySequence::Delete);
+ command->setAttribute(Core::ICommand::CA_Hide);
+ medit->addAction(command, Core::Constants::G_EDIT_COPYPASTE);
+
+ //editor Modes. Store ids for editor tool bars
+ m_actionGroupEditMode = new QActionGroup(this);
+ m_actionGroupEditMode->setExclusive(true);
+ connect(m_actionGroupEditMode, SIGNAL(triggered(QAction*)), this, SLOT(activateEditMode(QAction*)));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.WidgetEditor"));
+ createEditModeAction(m_actionGroupEditMode, m_context, am, medit,
+ QLatin1String("Edit widgets"), m_toolActionIds.back(),
+ EditModeWidgetEditor, QLatin1String("widgettool.png"), tr("F3"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.SignalsSlotsEditor"));
+ createEditModeAction(m_actionGroupEditMode, m_context, am, medit,
+ QLatin1String("Edit signals/slots"), m_toolActionIds.back(),
+ EditModeSignalsSlotEditor, QLatin1String("signalslottool.png"), tr("F4"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.BuddyEditor"));
+ createEditModeAction(m_actionGroupEditMode, m_context, am, medit,
+ QLatin1String("Edit buddies"), m_toolActionIds.back(),
+ EditModeBuddyEditor, QLatin1String("buddytool.png"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.TabOrderEditor"));
+ createEditModeAction(m_actionGroupEditMode, m_context, am, medit,
+ QLatin1String("Edit tab order"), m_toolActionIds.back(),
+ EditModeTabOrderEditor, QLatin1String("tabordertool.png"));
+
+ //tool actions
+ m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutHorizontally"));
+ addToolAction(m_fwm->actionHorizontalLayout(), am, m_context,
+ m_toolActionIds.back(), mformtools, tr("Ctrl+H"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutVertically"));
+ addToolAction(m_fwm->actionVerticalLayout(), am, m_context,
+ m_toolActionIds.back(), mformtools, tr("Ctrl+L"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.SplitHorizontal"));
+ addToolAction(m_fwm->actionSplitHorizontal(), am, m_context,
+ m_toolActionIds.back(), mformtools);
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.SplitVertical"));
+ addToolAction(m_fwm->actionSplitVertical(), am, m_context,
+ m_toolActionIds.back(), mformtools);
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutForm"));
+ addToolAction(m_fwm->actionFormLayout(), am, m_context,
+ m_toolActionIds.back(), mformtools);
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutGrid"));
+ addToolAction(m_fwm->actionGridLayout(), am, m_context,
+ m_toolActionIds.back(), mformtools, tr("Ctrl+G"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutBreak"));
+ addToolAction(m_fwm->actionBreakLayout(), am, m_context,
+ m_toolActionIds.back(), mformtools);
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutAdjustSize"));
+ addToolAction(m_fwm->actionAdjustSize(), am, m_context,
+ m_toolActionIds.back(), mformtools, tr("Ctrl+J"));
+
+ m_toolActionIds.push_back(QLatin1String("FormEditor.SimplifyLayout"));
+ addToolAction(m_fwm->actionSimplifyLayout(), am, m_context,
+ m_toolActionIds.back(), mformtools);
+
+ createSeparator(this, am, m_context, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator1"));
+
+ addToolAction(m_fwm->actionLower(), am, m_context,
+ QLatin1String("FormEditor.Lower"), mformtools);
+
+ addToolAction(m_fwm->actionRaise(), am, m_context,
+ QLatin1String("FormEditor.Raise"), mformtools);
+
+ // Commands that do not go into the editor toolbar
+ createSeparator(this, am, m_context, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator2"));
+
+ m_actionPreview = m_fwm->actionDefaultPreview();
+ Q_ASSERT(m_actionPreview);
+ addToolAction(m_actionPreview, am, m_context,
+ QLatin1String("FormEditor.Preview"), mformtools, tr("Ctrl+Alt+R"));
+
+ // Preview in style...
+ m_actionGroupPreviewInStyle = m_fwm->actionGroupPreviewInStyle();
+ mformtools->addMenu(createPreviewStyleMenu(am, m_actionGroupPreviewInStyle));
+
+ // Disabled since we cannot reliably locate uic.
+ if (wantCodeGenerationAction) {
+ m_actionGenerateCode = new QAction(tr("View &code"), this);
+ addToolAction(m_actionGenerateCode, am, m_context,
+ QLatin1String("FormEditor.ViewCode"), mformtools);
+ connect(m_actionGenerateCode, SIGNAL(triggered()), this, SLOT(generateCode()));
+ }
+ // Form settings
+ createSeparator(this, am, m_context, medit, QLatin1String("FormEditor.Edit.Separator2"), Core::Constants::G_EDIT_OTHER);
+
+#if QT_VERSION >= 0x040500
+ createSeparator(this, am, m_context, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator3"));
+ QAction *actionFormSettings = m_fwm->actionShowFormWindowSettingsDialog();
+ addToolAction(actionFormSettings, am, m_context, QLatin1String("FormEditor.FormSettings"), mformtools);
+#endif
+ // FWM
+ connect(m_fwm, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface *)), this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface *)));
+}
+
+
+QToolBar *FormEditorW::createEditorToolBar() const
+{
+ QToolBar *rc = new QToolBar;
+ rc->addSeparator();
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ const QStringList::const_iterator cend = m_toolActionIds.constEnd();
+ for (QStringList::const_iterator it = m_toolActionIds.constBegin(); it != cend; ++it) {
+ Core::ICommand *cmd = am->command(*it);
+ Q_ASSERT(cmd);
+ QAction *action = cmd->action();
+ if (!action->icon().isNull()) // Simplify grid has no action yet
+ rc->addAction(action);
+ }
+ int size = rc->style()->pixelMetric(QStyle::PM_SmallIconSize);
+ rc->setIconSize(QSize(size, size));
+ return rc;
+}
+
+Core::IActionContainer *FormEditorW::createPreviewStyleMenu(Core::ActionManagerInterface *am,
+ QActionGroup *actionGroup)
+{
+ const QString menuId = QLatin1String(M_FORMEDITOR_PREVIEW);
+ Core::IActionContainer *menuPreviewStyle = am->createMenu(menuId);
+ menuPreviewStyle->menu()->setTitle(tr("Preview in"));
+
+ // The preview menu is a list of invisible actions for the embedded design
+ // device profiles (integer data) followed by a separator and the styles
+ // (string data). Make device profiles update their text and hide them
+ // in the configuration dialog.
+ const QList<QAction*> actions = actionGroup->actions();
+
+ const QString deviceProfilePrefix = QLatin1String("DeviceProfile");
+ const QChar dot = QLatin1Char('.');
+
+ foreach(QAction* a, actions) {
+ QString name = menuId;
+ name += dot;
+ const QVariant data = a->data();
+ const bool isDeviceProfile = data.type() == QVariant::Int;
+ if (isDeviceProfile) {
+ name += deviceProfilePrefix;
+ name += dot;
+ }
+ name += data.toString();
+ Core::ICommand *command = am->registerAction(a, name, m_context);
+ if (isDeviceProfile) {
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setAttribute(Core::ICommand::CA_NonConfigureable);
+ }
+ menuPreviewStyle->addAction(command);
+ }
+ return menuPreviewStyle;
+}
+
+void FormEditorW::saveSettings(QSettings *s)
+{
+ s->beginGroup(settingsGroup);
+ s->setValue(QLatin1String(editorWidgetStateKeyC), EditorWidget::state().toVariant());
+ s->endGroup();
+}
+
+void FormEditorW::restoreSettings(const QSettings *s)
+{
+ QString key = QLatin1String(settingsGroup) + QLatin1Char('/')
+ + QLatin1String(editorWidgetStateKeyC);
+ const QVariant ev = s->value(key);
+ if (ev.type() != QVariant::Invalid) {
+ EditorWidgetState st;
+ if (st.fromVariant(ev))
+ EditorWidget::setState(st);
+ }
+}
+
+void FormEditorW::generateCode()
+{
+ const FormWindowEditor *fww = activeFormWindow();
+ if (!fww)
+ return;
+
+ bool ok = false;
+ QString errorMessage;
+
+ do {
+ QByteArray header;
+ if (!fww->generateCode(header, errorMessage))
+ break;
+
+ QString tempPattern = QDir::tempPath();
+ if (!tempPattern.endsWith(QDir::separator())) // platform-dependant
+ tempPattern += QDir::separator();
+ tempPattern += QLatin1String("ui_headerXXXXXX.h");
+ QTemporaryFile headerFile(tempPattern);
+ headerFile.setAutoRemove (false);
+ if (!headerFile.open() || !headerFile.write(header)) {
+ errorMessage = tr("Unable to write to a temporary file.");
+ break;
+ }
+ const QString headerFileName = headerFile.fileName();
+ headerFile.close();
+ Core::IEditor *eif = m_core->editorManager()->openEditor(headerFileName);
+ if (!eif) {
+ errorMessage = tr("Unable open %1.").arg(headerFileName);
+ break;
+ }
+ ok = true;
+ } while (false);
+ if (!ok)
+ critical(errorMessage);
+}
+
+void FormEditorW::critical(const QString &errorMessage)
+{
+ QMessageBox::critical(m_core->mainWindow(), tr("Designer"), errorMessage);
+}
+
+FormWindowEditor *FormEditorW::createFormWindowEditor(QWidget* parentWidget)
+{
+ m_fwm->closeAllPreviews();
+ QDesignerFormWindowInterface *form = m_fwm->createFormWindow(0);
+ connect(form, SIGNAL(toolChanged(int)), this, SLOT(toolChanged(int)));
+ qdesigner_internal::FormWindowBase::setupDefaultAction(form);
+ FormWindowEditor *fww = new FormWindowEditor(m_core, m_context, form, parentWidget);
+ // Store a pointer to all form windows so we can unselect all other formwindows except the active one.
+ m_formWindows.append(fww);
+ connect(fww, SIGNAL(destroyed()), this, SLOT(editorDestroyed()));
+ return fww;
+}
+
+void FormEditorW::editorDestroyed()
+{
+ QObject *source = sender();
+
+ if (debugFormEditor)
+ qDebug() << "FormEditorW::editorDestroyed()" << source;
+
+ for (EditorList::iterator it = m_formWindows.begin(); it != m_formWindows.end(); ) {
+ if (*it == source) {
+ it = m_formWindows.erase(it);
+ break;
+ } else {
+ ++it;
+ }
+ }
+}
+
+void FormEditorW::currentEditorChanged(Core::IEditor *editor)
+{
+ if (debugFormEditor)
+ qDebug() << "FormEditorW::currentEditorChanged" << editor << " of " << m_fwm->formWindowCount();
+
+ // Deactivate Designer if a non-form is being edited
+ if (editor && !qstrcmp(editor->kind(), Constants::C_FORMWINDOW)) {
+ FormWindowEditor *fw = qobject_cast<FormWindowEditor *>(editor);
+ Q_ASSERT(fw);
+ fw->activate();
+ m_fwm->setActiveFormWindow(fw->formWindow());
+ } else {
+ m_fwm->setActiveFormWindow(0);
+ }
+}
+
+void FormEditorW::activeFormWindowChanged(QDesignerFormWindowInterface *afw)
+{
+ if (debugFormEditor)
+ qDebug() << "FormEditorW::activeFormWindowChanged" << afw << " of " << m_fwm->formWindowCount() << m_formWindows;
+
+ m_fwm->closeAllPreviews();
+
+ bool foundFormWindow = false;
+ // Display form selection handles only on active window
+ EditorList::const_iterator cend = m_formWindows.constEnd();
+ for (EditorList::const_iterator it = m_formWindows.constBegin(); it != cend ; ++it) {
+ FormWindowEditor *fwe = *it;
+ const bool active = fwe->formWindow() == afw;
+ if (active)
+ foundFormWindow = true;
+ fwe->updateFormWindowSelectionHandles(active);
+ }
+
+ m_actionPreview->setEnabled(foundFormWindow);
+ if (m_actionGenerateCode)
+ m_actionGenerateCode->setEnabled(foundFormWindow);
+ m_actionGroupPreviewInStyle->setEnabled(foundFormWindow);
+}
+
+FormWindowEditor *FormEditorW::activeFormWindow()
+{
+ QDesignerFormWindowInterface *afw = m_fwm->activeFormWindow();
+ for (int i = 0; i < m_formWindows.count(); ++i) {
+ if (FormWindowEditor *fw = m_formWindows[i]) {
+ QDesignerFormWindowInterface *fwd = fw->formWindow();
+ if (fwd == afw) {
+ return fw;
+ }
+ }
+ }
+ return 0;
+}
+
+void FormEditorW::activateEditMode(int id)
+{
+ if (const int count = m_fwm->formWindowCount())
+ for (int i = 0; i < count; i++)
+ m_fwm->formWindow(i)->setCurrentTool(id);
+}
+
+void FormEditorW::activateEditMode(QAction* a)
+{
+ activateEditMode(a->data().toInt());
+}
+
+void FormEditorW::toolChanged(int t)
+{
+ typedef QList<QAction *> ActionList;
+ if (const QAction *currentAction = m_actionGroupEditMode->checkedAction())
+ if (currentAction->data().toInt() == t)
+ return;
+ const ActionList actions = m_actionGroupEditMode->actions();
+ const ActionList::const_iterator cend = actions.constEnd();
+ for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it)
+ if ( (*it)->data().toInt() == t) {
+ (*it)->setChecked(true);
+ break;
+ }
+}
+
+void FormEditorW::print()
+{
+ // Printing code courtesy of designer_actions.cpp
+ QDesignerFormWindowInterface *fw = m_fwm->activeFormWindow();
+ if (!fw)
+ return;
+
+ const bool oldFullPage = m_core->printer()->fullPage();
+ const QPrinter::Orientation oldOrientation = m_core->printer()->orientation ();
+ m_core->printer()->setFullPage(false);
+ do {
+
+ // Grab the image to be able to a suggest suitable orientation
+ QString errorMessage;
+ const QPixmap pixmap = m_fwm->createPreviewPixmap(&errorMessage);
+ if (pixmap.isNull()) {
+ critical(tr("The image could not be create: %1").arg(errorMessage));
+ break;
+ }
+
+ const QSizeF pixmapSize = pixmap.size();
+ m_core->printer()->setOrientation( pixmapSize.width() > pixmapSize.height() ? QPrinter::Landscape : QPrinter::Portrait);
+
+ // Printer parameters
+ QPrintDialog dialog(m_core->printer(), fw);
+ if (!dialog.exec())
+ break;
+
+ const QCursor oldCursor = m_core->mainWindow()->cursor();
+ m_core->mainWindow()->setCursor(Qt::WaitCursor);
+ // Estimate of required scaling to make form look the same on screen and printer.
+ const double suggestedScaling = static_cast<double>(m_core->printer()->physicalDpiX()) / static_cast<double>(fw->physicalDpiX());
+
+ QPainter painter(m_core->printer());
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+
+ // Clamp to page
+ const QRectF page = painter.viewport();
+ const double maxScaling = qMin(page.size().width() / pixmapSize.width(), page.size().height() / pixmapSize.height());
+ const double scaling = qMin(suggestedScaling, maxScaling);
+
+ const double xOffset = page.left() + qMax(0.0, (page.size().width() - scaling * pixmapSize.width()) / 2.0);
+ const double yOffset = page.top() + qMax(0.0, (page.size().height() - scaling * pixmapSize.height()) / 2.0);
+
+ // Draw.
+ painter.translate(xOffset, yOffset);
+ painter.scale(scaling, scaling);
+ painter.drawPixmap(0, 0, pixmap);
+ m_core->mainWindow()->setCursor(oldCursor);
+
+ m_core->statusBar()->showMessage(tr("Printed %1...").arg(QFileInfo(fw->fileName()).fileName()));
+ } while (false);
+ m_core->printer()->setFullPage(oldFullPage);
+ m_core->printer()->setOrientation(oldOrientation);
+}
diff --git a/src/plugins/designer/formeditorw.h b/src/plugins/designer/formeditorw.h
new file mode 100644
index 0000000000..b8434b2c5d
--- /dev/null
+++ b/src/plugins/designer/formeditorw.h
@@ -0,0 +1,175 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMEDITORW_H
+#define FORMEDITORW_H
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+
+#include "designerconstants.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerIntegrationInterface;
+class QDesignerFormEditorInterface;
+class QDesignerFormWindowInterface;
+
+class QAction;
+class QActionGroup;
+class QFocusEvent;
+
+class QWidget;
+class QSignalMapper;
+class QSettings;
+class QToolBar;
+
+namespace qdesigner_internal {
+ class QDesignerFormWindowManager;
+}
+
+QT_END_NAMESPACE
+
+namespace Core {
+class ActionManagerInterface;
+class IActionContainer;
+class ICore;
+class IEditor;
+}
+
+namespace Designer {
+namespace Internal {
+
+class FormWindowEditor;
+class SettingsPage;
+
+
+/** FormEditorW is a singleton that stores the Designer CoreInterface and
+ * performs centralized operations. The instance() method will return an
+ * instance. However, it must be manually deleted when unloading the
+ * plugin. Since fully initializing Designer at startup is expensive, the
+ * class has an internal partial initialisation stage "RegisterPlugins"
+ * which is there to register the Creator plugin objects
+ * that must be present at startup (settings pages, actions).
+ * The plugin uses this stage at first by calling ensureInitStage().
+ * Requesting an editor via instance() will fully initialize the class.
+ * This is based on the assumption that the Designer settings work with
+ * no plugins loaded. If that does not work, full initialization can be
+ * triggered by connection to the ICore::settingsDialogRequested() signal.
+ */
+class FormEditorW : public QObject
+{
+ Q_OBJECT
+public:
+ enum InitializationStage {
+ // Register Creator plugins (settings pages, actions)
+ RegisterPlugins,
+ // Fully initialized for handling editor requests
+ FullyInitialized
+ };
+
+ virtual ~FormEditorW();
+
+ // Create an instance and initialize up to stage s
+ static void ensureInitStage(InitializationStage s);
+ // Returns fully initialized instance
+ static FormEditorW *instance();
+ // Deletes an existing instance if there is one.
+ static void deleteInstance();
+
+ inline QDesignerFormEditorInterface *designerEditor() const { return m_formeditor; }
+ inline QWidget * const*designerSubWindows() const { return m_designerSubWindows; }
+ QToolBar *createEditorToolBar() const;
+
+ FormWindowEditor *createFormWindowEditor(QWidget* parentWidget);
+
+ FormWindowEditor *activeFormWindow();
+
+private slots:
+ void generateCode();
+ void activateEditMode(int id);
+ void activateEditMode(QAction*);
+ void activeFormWindowChanged(QDesignerFormWindowInterface *);
+ void currentEditorChanged(Core::IEditor *editor);
+ void toolChanged(int);
+ void print();
+
+ void editorDestroyed();
+
+private:
+ FormEditorW();
+ void fullInit();
+
+ void saveSettings(QSettings *s);
+ void restoreSettings(const QSettings *s);
+
+ void initDesignerSubWindows();
+
+ typedef QList<FormWindowEditor *> EditorList;
+
+ void setupActions();
+ Core::IActionContainer *createPreviewStyleMenu(Core::ActionManagerInterface *am,
+ QActionGroup *actionGroup);
+
+ void critical(const QString &errorMessage);
+
+ static FormEditorW *m_self;
+
+ QDesignerFormEditorInterface *m_formeditor;
+ QDesignerIntegrationInterface *m_integration;
+ qdesigner_internal::QDesignerFormWindowManager *m_fwm;
+ Core::ICore *m_core;
+ InitializationStage m_initStage;
+
+ QWidget *m_designerSubWindows[Designer::Constants::DesignerSubWindowCount];
+
+ QList<SettingsPage *> m_settingsPages;
+ QActionGroup *m_actionGroupEditMode;
+ QAction *m_actionPrint;
+ QAction *m_actionGenerateCode;
+ QAction *m_actionPreview;
+ QActionGroup *m_actionGroupPreviewInStyle;
+
+ QList<int> m_context;
+
+ EditorList m_formWindows;
+ QStringList m_toolActionIds;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // FORMEDITORW_H
diff --git a/src/plugins/designer/formtemplatewizardpage.cpp b/src/plugins/designer/formtemplatewizardpage.cpp
new file mode 100644
index 0000000000..a819502b21
--- /dev/null
+++ b/src/plugins/designer/formtemplatewizardpage.cpp
@@ -0,0 +1,330 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formtemplatewizardpage.h"
+#include "formeditorw.h"
+
+#include <QtDesigner/private/abstractnewformwidget_p.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QByteArray>
+#include <QtCore/QBuffer>
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QMessageBox>
+#include <QtGui/QAbstractButton>
+
+#ifdef USE_XSLT
+# include <QtXmlPatterns/QXmlQuery>
+#else
+# include <QtXml/QDomDocument>
+#endif
+
+namespace Designer {
+namespace Internal {
+
+// ----------------- FormTemplateWizardPagePage
+
+FormTemplateWizardPagePage::FormTemplateWizardPagePage(QWidget * parent) :
+ QWizardPage(parent),
+ m_newFormWidget(QDesignerNewFormWidgetInterface::createNewFormWidget(FormEditorW::instance()->designerEditor())),
+ m_templateSelected(m_newFormWidget->hasCurrentTemplate())
+{
+ setTitle(tr("Choose a form template"));
+ QVBoxLayout *layout = new QVBoxLayout;
+
+ connect(m_newFormWidget, SIGNAL(currentTemplateChanged(bool)),
+ this, SLOT(slotCurrentTemplateChanged(bool)));
+ connect(m_newFormWidget, SIGNAL(templateActivated()),
+ this, SIGNAL(templateActivated()));
+ layout->addWidget(m_newFormWidget);
+
+ setLayout(layout);
+}
+
+bool FormTemplateWizardPagePage::isComplete() const
+{
+ return m_templateSelected;
+}
+
+void FormTemplateWizardPagePage::slotCurrentTemplateChanged(bool templateSelected)
+{
+ if (m_templateSelected == templateSelected)
+ return;
+ m_templateSelected = templateSelected;
+ emit completeChanged();
+}
+
+bool FormTemplateWizardPagePage::validatePage()
+{
+ QString errorMessage;
+ m_templateContents = m_newFormWidget->currentTemplate(&errorMessage);
+ if (m_templateContents.isEmpty()) {
+ QMessageBox::critical(this, tr("%1 - Error").arg(title()), errorMessage);
+ return false;
+ }
+ return true;
+}
+
+QString FormTemplateWizardPagePage::stripNamespaces(const QString &className)
+{
+ QString rc = className;
+ const int namespaceIndex = rc.lastIndexOf(QLatin1String("::"));
+ if (namespaceIndex != -1)
+ rc.remove(0, namespaceIndex + 2);
+ return rc;
+}
+
+bool FormTemplateWizardPagePage::getUIXmlData(const QString &uiXml,
+ QString *formBaseClass,
+ QString *uiClassName)
+{
+ // Parse UI xml to determine
+ // 1) The ui class name from "<class>Designer::Internal::FormClassWizardPage</class>"
+ // 2) the base class from: widget class="QWizardPage"...
+ QXmlStreamReader reader(uiXml);
+ while (!reader.atEnd()) {
+ if (reader.readNext() == QXmlStreamReader::StartElement) {
+ if (reader.name() == QLatin1String("class")) {
+ *uiClassName = reader.readElementText();
+ } else {
+ if (reader.name() == QLatin1String("widget")) {
+ const QXmlStreamAttributes attrs = reader.attributes();
+ *formBaseClass = reader.attributes().value(QLatin1String("class")).toString();
+ return !uiClassName->isEmpty() && !formBaseClass->isEmpty();
+ }
+ }
+ }
+ }
+ return false;
+}
+
+#ifdef USE_XSLT
+
+// Change the UI class name in UI xml: This occurs several times, as contents
+// of the <class> element, as name of the first <widget> element, and possibly
+// in the signal/slot connections
+
+static const char *classNameChangingSheetFormatC =
+"<?xml version=\"1.0\"?>\n"
+"<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"2.0\">\n"
+"<xsl:output method=\"xml\" indent=\"yes\" encoding=\"UTF-8\" />\n"
+"\n"
+"<!-- Grab old class name to be replaced by evaluating <ui><class> -->\n"
+"<xsl:param name=\"oldClassName\"><xsl:value-of select=\"/ui/class\"/></xsl:param>\n"
+"\n"
+"<!-- heavy wizardry to copy nodes and attributes (emulating the default rules) -->\n"
+"<xsl:template match=\"@*|node()\">\n"
+" <xsl:copy>\n"
+" <xsl:apply-templates select=\"@*|node()\"/>\n"
+" </xsl:copy>\n"
+"</xsl:template>\n"
+"\n"
+"<!-- Change <ui><class> tag -->\n"
+"<xsl:template match=\"class\">\n"
+" <xsl:element name=\"class\">\n"
+" <xsl:text>%1</xsl:text>\n"
+" </xsl:element>\n"
+"</xsl:template>\n"
+"\n"
+"<!-- Change first <widget> tag -->\n"
+"<xsl:template match=\"/ui/widget/@name\">\n"
+"<xsl:attribute name=\"name\">\n"
+"<xsl:text>%1</xsl:text>\n"
+"</xsl:attribute>\n"
+"</xsl:template>\n"
+"\n"
+"<!-- Change <sender>/<receiver> elements (for pre-wired QDialog signals) -->\n"
+"<xsl:template match=\"receiver[.='Dialog']\">\n"
+" <xsl:element name=\"receiver\">\n"
+" <xsl:text>%1</xsl:text>\n"
+" </xsl:element>\n"
+"</xsl:template>\n"
+"<xsl:template match=\"sender[.='Dialog']\">\n"
+" <xsl:element name=\"sender\">\n"
+" <xsl:text>%1</xsl:text>\n"
+" </xsl:element>\n"
+"</xsl:template>\n"
+"</xsl:stylesheet>\n";
+
+QString FormTemplateWizardPagePage::changeUiClassName(const QString &uiXml, const QString &newUiClassName)
+{
+ // Prepare I/O: Sheet
+ const QString xsltSheet = QString::fromLatin1(classNameChangingSheetFormatC).arg(newUiClassName);
+ QByteArray xsltSheetBA = xsltSheet.toUtf8();
+ QBuffer xsltSheetBuffer(&xsltSheetBA);
+ xsltSheetBuffer.open(QIODevice::ReadOnly);
+ // Prepare I/O: Xml
+ QByteArray xmlBA = uiXml.toUtf8();
+ QBuffer xmlBuffer(&xmlBA);
+ xmlBuffer.open(QIODevice::ReadOnly);
+ // Prepare I/O: output
+ QBuffer outputBuffer;
+ outputBuffer.open(QIODevice::WriteOnly);
+
+ // Run query
+ QXmlQuery query(QXmlQuery::XSLT20);
+ query.setFocus(&xmlBuffer);
+ query.setQuery(&xsltSheetBuffer);
+ if (!query.evaluateTo(&outputBuffer)) {
+ qWarning("Unable to change the ui class name in a form template.\n%s\nUsing:\n%s\n",
+ xmlBA.constData(), xsltSheetBA.constData());
+ return uiXml;
+ }
+ outputBuffer.close();
+ return QString::fromUtf8(outputBuffer.data());
+}
+#else
+
+// Change the contents of a DOM element to a new value if it matches
+// a predicate
+template <class Predicate>
+bool changeDomElementContents(const QDomElement &element,
+ Predicate p,
+ const QString &newValue,
+ QString *ptrToOldValue = 0)
+{
+ // Find text in "<element>text</element>"
+ const QDomNodeList children = element.childNodes();
+ if (children.size() != 1)
+ return false;
+ const QDomNode first = children.at(0);
+ if (first.nodeType() != QDomNode::TextNode)
+ return false;
+ QDomCharacterData data = first.toCharacterData();
+ const QString oldValue = data.data();
+
+ if (p(oldValue)) {
+ if (ptrToOldValue)
+ *ptrToOldValue = oldValue;
+ data.setData(newValue);
+ return true;
+ }
+ return false;
+}
+
+namespace {
+ bool truePredicate(const QString &) { return true; }
+
+ // Predicate that matches a string value
+ class MatchPredicate {
+ public:
+ MatchPredicate(const QString &m) : m_match(m) {}
+ bool operator()(const QString &s) const { return s == m_match; }
+ private:
+ const QString m_match;
+ };
+
+ // Change <sender> and <receiver> in a Dom UI <connections> list
+ // if they match the class name passed on
+ void changeDomConnectionList(const QDomElement &connectionsNode,
+ const QString &oldClassName,
+ const QString &newClassName)
+ {
+ const MatchPredicate oldClassPredicate(oldClassName);
+ const QString senderTag = QLatin1String("sender");
+ const QString receiverTag = QLatin1String("receiver");
+ const QDomNodeList connections = connectionsNode.childNodes();
+ const int connectionsCount = connections.size();
+ // Loop <connection>
+ for (int c = 0; c < connectionsCount; c++) {
+ const QDomNodeList connectionElements = connections.at(c).childNodes();
+ const int connectionElementCount = connectionElements.count();
+ // Loop <sender>, <receiver>, <signal>, <slot>
+ for (int ce = 0; ce < connectionElementCount; ce++) {
+ const QDomNode connectionElementNode = connectionElements.at(ce);
+ if (connectionElementNode.isElement()) {
+ const QDomElement connectionElement = connectionElementNode.toElement();
+ const QString tagName = connectionElement.tagName();
+ if (tagName == senderTag || tagName == receiverTag)
+ changeDomElementContents(connectionElement, oldClassPredicate, newClassName);
+ }
+ }
+ }
+ }
+}
+
+// Change the UI class name in UI xml: This occurs several times, as contents
+// of the <class> element, as name of the first <widget> element, and possibly
+// in the signal/slot connections
+
+QString FormTemplateWizardPagePage::changeUiClassName(const QString &uiXml, const QString &newUiClassName)
+{
+ QDomDocument domUi;
+ if (!domUi.setContent(uiXml)) {
+ qWarning("Failed to parse:\n%s", uiXml.toUtf8().constData());
+ return uiXml;
+ }
+
+ bool firstWidgetElementFound = false;
+ QString oldClassName;
+
+ // Loop first level children. First child is <ui>
+ const QDomNodeList children = domUi.firstChildElement().childNodes();
+ const QString classTag = QLatin1String("class");
+ const QString widgetTag = QLatin1String("widget");
+ const QString connectionsTag = QLatin1String("connections");
+ const int count = children.size();
+ for (int i = 0; i < count; i++) {
+ const QDomNode node = children.at(i);
+ if (node.isElement()) {
+ // Replace <class> element text
+ QDomElement element = node.toElement();
+ const QString name = element.tagName();
+ if (name == classTag) {
+ if (!changeDomElementContents(element, truePredicate, newUiClassName, &oldClassName)) {
+ qWarning("Unable to change the <class> element:\n%s", uiXml.toUtf8().constData());
+ return uiXml;
+ }
+ } else {
+ // Replace first <widget> element name attribute
+ if (!firstWidgetElementFound && name == widgetTag) {
+ firstWidgetElementFound = true;
+ const QString nameAttribute = QLatin1String("name");
+ if (element.hasAttribute(nameAttribute))
+ element.setAttribute(nameAttribute, newUiClassName);
+ } else {
+ // Replace <sender>, <receiver> tags of dialogs.
+ if (name == connectionsTag)
+ changeDomConnectionList(element, oldClassName, newUiClassName);
+ }
+ }
+ }
+ }
+ const QString rc = domUi.toString();
+ return rc;
+}
+#endif
+} // namespace Internal
+} // namespace Designer
diff --git a/src/plugins/designer/formtemplatewizardpage.h b/src/plugins/designer/formtemplatewizardpage.h
new file mode 100644
index 0000000000..2476c9b6e8
--- /dev/null
+++ b/src/plugins/designer/formtemplatewizardpage.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMWIZARDPAGE_H
+#define FORMWIZARDPAGE_H
+
+#include <QtGui/QWizardPage>
+
+QT_BEGIN_NAMESPACE
+class QDesignerNewFormWidgetInterface;
+QT_END_NAMESPACE
+
+namespace Designer {
+namespace Internal {
+
+// A wizard page embedding Qt Designer's QDesignerNewFormWidgetInterface
+// widget.
+
+class FormTemplateWizardPagePage : public QWizardPage
+{
+ Q_DISABLE_COPY(FormTemplateWizardPagePage)
+ Q_OBJECT
+public:
+ explicit FormTemplateWizardPagePage(QWidget * parent = 0);
+
+ virtual bool isComplete () const;
+ virtual bool validatePage();
+
+ QString templateContents() const { return m_templateContents; }
+
+ static bool getUIXmlData(const QString &uiXml, QString *formBaseClass, QString *uiClassName);
+ static QString changeUiClassName(const QString &uiXml, const QString &newUiClassName);
+ static QString stripNamespaces(const QString &className);
+
+signals:
+ void templateActivated();
+
+private slots:
+ void slotCurrentTemplateChanged(bool);
+
+private:
+ QString m_templateContents;
+ QDesignerNewFormWidgetInterface *m_newFormWidget;
+ bool m_templateSelected;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //FORMTEMPLATEWIZARDPAGE_H
diff --git a/src/plugins/designer/formwindoweditor.cpp b/src/plugins/designer/formwindoweditor.cpp
new file mode 100644
index 0000000000..dde574e96f
--- /dev/null
+++ b/src/plugins/designer/formwindoweditor.cpp
@@ -0,0 +1,355 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "designerconstants.h"
+#include "editorwidget.h"
+#include "formeditorw.h"
+#include "formwindoweditor.h"
+#include "formwindowfile.h"
+#include "formwindowhost.h"
+
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectnodes.h>
+#include <projectexplorer/nodesvisitor.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowManagerInterface>
+#include <QtDesigner/private/formwindowbase_p.h>
+#include <QtDesigner/private/qtresourcemodel_p.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QByteArray>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDebug>
+#include <QtGui/QToolBar>
+
+using namespace Designer::Internal;
+using namespace Designer::Constants;
+using namespace SharedTools;
+using ProjectExplorer::NodesVisitor;
+using ProjectExplorer::ProjectNode;
+using ProjectExplorer::FolderNode;
+using ProjectExplorer::FileNode;
+
+enum { debugFormWindowEditor = 0 };
+
+class QrcFilesVisitor : public NodesVisitor {
+public:
+ QStringList qrcFiles() const;
+
+ void visitProjectNode(ProjectNode *node);
+ void visitFolderNode(FolderNode *node);
+private:
+ QStringList m_qrcFiles;
+};
+
+QStringList QrcFilesVisitor::qrcFiles() const
+{
+ return m_qrcFiles;
+}
+
+void QrcFilesVisitor::visitProjectNode(ProjectNode *projectNode)
+{
+ visitFolderNode(projectNode);
+}
+
+void QrcFilesVisitor::visitFolderNode(FolderNode *folderNode)
+{
+ foreach (const FileNode *fileNode, folderNode->fileNodes()) {
+ if (fileNode->fileType() == ProjectExplorer::ResourceType)
+ m_qrcFiles.append(fileNode->path());
+ }
+}
+
+
+FormWindowEditor::FormWindowEditor(Core::ICore *core,
+ const QList<int> &context,
+ QDesignerFormWindowInterface *form,
+ QObject *parent) :
+ Core::IEditor(parent),
+ m_context(context),
+ m_formWindow(form),
+ m_file(new FormWindowFile(core, form, this)),
+ m_host(new FormWindowHost(form)),
+ m_editorWidget(new EditorWidget(m_host)),
+ m_toolBar(0),
+ m_sessionNode(0),
+ m_sessionWatcher(0)
+{
+ if (debugFormWindowEditor)
+ qDebug() << "FormWindowEditor::FormWindowEditor" << form << parent;
+
+ connect(m_file, SIGNAL(reload(QString)), this, SLOT(slotOpen(QString)));
+ connect(m_file, SIGNAL(setDisplayName(QString)), this, SLOT(slotSetDisplayName(QString)));
+ connect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
+ connect(m_file, SIGNAL(changed()), this, SLOT(updateResources()));
+ connect(this, SIGNAL(opened(QString)), m_file, SLOT(setFileName(QString)));
+
+ connect(m_host, SIGNAL(changed()), this, SIGNAL(changed()));
+
+ connect(form, SIGNAL(toolChanged(int)), m_editorWidget, SLOT(toolChanged(int)));
+ m_editorWidget->activate();
+}
+
+FormWindowEditor::~FormWindowEditor()
+{
+ // Close: Delete the Designer form window via embedding widget
+ delete m_toolBar;
+ delete m_host;
+ delete m_editorWidget;
+ if (debugFormWindowEditor)
+ qDebug() << "FormWindowEditor::~FormWindowEditor" << m_displayName;
+ if (m_sessionNode && m_sessionWatcher) {
+ m_sessionNode->unregisterWatcher(m_sessionWatcher);
+ delete m_sessionWatcher;
+ }
+}
+
+bool FormWindowEditor::createNew(const QString &contents)
+{
+ if (debugFormWindowEditor)
+ qDebug() << "FormWindowEditor::createNew()" << contents.size() << "chars";
+
+ if (!m_formWindow)
+ return false;
+
+ m_formWindow->setContents(contents);
+ if (!m_formWindow->mainContainer())
+ return false;
+
+ if (qdesigner_internal::FormWindowBase *fw = qobject_cast<qdesigner_internal::FormWindowBase *>(m_formWindow))
+ fw->setDesignerGrid(qdesigner_internal::FormWindowBase::defaultDesignerGrid());
+ return true;
+}
+
+bool FormWindowEditor::open(const QString &fileName /*= QString()*/)
+{
+ if (debugFormWindowEditor)
+ qDebug() << "FormWindowEditor::open" << fileName;
+
+ if (fileName.isEmpty()) {
+ setDisplayName(tr("untitled"));
+ } else {
+ const QFileInfo fi(fileName);
+ const QString fileName = fi.absoluteFilePath();
+
+ QFile file(fileName);
+ if (!file.exists())
+ return false;
+
+ if (!fi.isReadable())
+ return false;
+
+ if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
+ return false;
+
+ m_formWindow->setFileName(fileName);
+ m_formWindow->setContents(&file);
+ file.close();
+ if (!m_formWindow->mainContainer())
+ return false;
+ m_formWindow->setDirty(false);
+
+ ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance();
+ ProjectExplorer::SessionManager *session = pe->session();
+ m_sessionNode = session->sessionNode();
+ m_sessionWatcher = new ProjectExplorer::NodesWatcher();
+ connect(m_sessionWatcher, SIGNAL(filesAdded()), this, SLOT(updateResources()));
+ connect(m_sessionWatcher, SIGNAL(filesRemoved()), this, SLOT(updateResources()));
+ connect(m_sessionWatcher, SIGNAL(foldersAdded()), this, SLOT(updateResources()));
+ connect(m_sessionWatcher, SIGNAL(foldersRemoved()), this, SLOT(updateResources()));
+ m_sessionNode->registerWatcher(m_sessionWatcher);
+
+ if (qdesigner_internal::FormWindowBase *fw = qobject_cast<qdesigner_internal::FormWindowBase *>(m_formWindow)) {
+ QtResourceSet *rs = fw->resourceSet();
+ m_originalUiQrcPaths = rs->activeQrcPaths();
+ }
+
+ emit opened(fileName);
+ updateResources();
+
+ QDesignerFormWindowManagerInterface *fwm = FormEditorW::instance()->designerEditor()->formWindowManager();
+ fwm->setActiveFormWindow(m_formWindow);
+
+ setDisplayName(fi.fileName());
+ }
+ emit changed();
+ return true;
+}
+
+void FormWindowEditor::updateResources()
+{
+ if (qdesigner_internal::FormWindowBase *fw = qobject_cast<qdesigner_internal::FormWindowBase *>(m_formWindow)) {
+ ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance();
+ // filename could change in the meantime.
+ ProjectExplorer::Project *project = pe->session()->projectForFile(m_file->fileName());
+
+ qdesigner_internal::FormWindowBase::SaveResourcesBehaviour behaviour = qdesigner_internal::FormWindowBase::SaveAll;
+ QtResourceSet *rs = fw->resourceSet();
+ if (project) {
+ ProjectNode *root = project->rootProjectNode();
+ QrcFilesVisitor qrcVisitor;
+ root->accept(&qrcVisitor);
+
+ rs->activateQrcPaths(qrcVisitor.qrcFiles());
+ behaviour = qdesigner_internal::FormWindowBase::SaveOnlyUsedQrcFiles;
+ } else {
+ rs->activateQrcPaths(m_originalUiQrcPaths);
+ }
+ fw->setSaveResourcesBehaviour(behaviour);
+ }
+}
+
+void FormWindowEditor::slotOpen(const QString &fileName)
+{
+ open(fileName);
+}
+
+void FormWindowEditor::slotSetDisplayName(const QString &title)
+{
+ if (debugFormWindowEditor)
+ qDebug() << "FormWindowEditor::slotSetDisplayName" << title;
+ setDisplayName(title);
+}
+
+bool FormWindowEditor::duplicateSupported() const
+{
+ return false;
+}
+
+Core::IEditor *FormWindowEditor::duplicate(QWidget *)
+{
+ return 0;
+}
+
+Core::IFile *FormWindowEditor::file()
+{
+ return m_file;
+}
+
+const char *FormWindowEditor::kind() const
+{
+ return C_FORMWINDOW;
+}
+
+QString FormWindowEditor::displayName() const
+{
+ return m_displayName;
+}
+
+void FormWindowEditor::setDisplayName(const QString &title)
+{
+ m_displayName = title;
+}
+
+QToolBar *FormWindowEditor::toolBar()
+{
+ if (!m_toolBar)
+ m_toolBar = FormEditorW::instance()->createEditorToolBar();
+ return m_toolBar;
+}
+
+QByteArray FormWindowEditor::saveState() const
+{
+ return QByteArray();
+}
+
+bool FormWindowEditor::restoreState(const QByteArray &/*state*/)
+{
+ return true;
+}
+
+QList<int> FormWindowEditor::context() const
+{
+ return m_context;
+}
+
+QWidget *FormWindowEditor::widget()
+{
+ return m_editorWidget;
+}
+
+bool FormWindowEditor::generateCode(QByteArray &header, QString &errorMessage) const
+{
+ if (debugFormWindowEditor)
+ qDebug() << "FormWindowEditor::generateCode";
+
+ QString tempPattern = QDir::tempPath();
+ if (!tempPattern.endsWith(QDir::separator())) // platform-dependant
+ tempPattern += QDir::separator();
+ tempPattern += QLatin1String("formXXXXXX.ui");
+ QTemporaryFile uiFile(tempPattern);
+ uiFile.setAutoRemove(true);
+ if (!uiFile.open()) {
+ errorMessage = tr("Unable to write to a temporary file.");
+ return false;
+ }
+ if (!m_file->writeFile(uiFile, errorMessage)) {
+ errorMessage = tr("Unable to write to a temporary file.");
+ return false;
+ }
+ const QString uiFileName = uiFile.fileName();
+ uiFile.close();
+
+ if (!qdesigner_internal::runUIC(uiFileName, qdesigner_internal::UIC_GenerateCode, header, errorMessage))
+ return false;
+
+ return true;
+}
+
+QDesignerFormWindowInterface *FormWindowEditor::formWindow() const
+{
+ return m_formWindow;
+}
+
+QWidget *FormWindowEditor::integrationContainer()
+{
+ return m_host->integrationContainer();
+}
+
+void FormWindowEditor::updateFormWindowSelectionHandles(bool state)
+{
+ m_host->updateFormWindowSelectionHandles(state);
+}
+
+void FormWindowEditor::setSuggestedFileName(const QString &fileName)
+{
+ m_file->setSuggestedFileName(fileName);
+}
+
+void FormWindowEditor::activate()
+{
+ m_editorWidget->activate();
+}
diff --git a/src/plugins/designer/formwindoweditor.h b/src/plugins/designer/formwindoweditor.h
new file mode 100644
index 0000000000..6cffbdf5df
--- /dev/null
+++ b/src/plugins/designer/formwindoweditor.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMWINDOWEDITOR_H
+#define FORMWINDOWEDITOR_H
+
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QDesignerFormWindowInterface;
+class QDesignerFormWindowManagerInterface;
+class QFile;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace ProjectExplorer {
+class SessionNode;
+class NodesWatcher;
+}
+
+namespace Designer {
+namespace Internal {
+
+class FormWindowFile;
+class FormWindowHost;
+class EditorWidget;
+// Master class maintaining a form window editor,
+// containing file and widget host
+
+class FormWindowEditor : public Core::IEditor
+{
+ Q_OBJECT
+
+public:
+ FormWindowEditor(Core::ICore *core,
+ const QList<int> &context,
+ QDesignerFormWindowInterface *form,
+ QObject *parent = 0);
+ ~FormWindowEditor();
+
+ // IEditor
+ bool createNew(const QString &contents);
+ bool open(const QString &fileName = QString());
+ bool duplicateSupported() const;
+ Core::IEditor *duplicate(QWidget *);
+ Core::IFile *file();
+ const char *kind() const;
+ QString displayName() const;
+ void setDisplayName(const QString &title);
+ QToolBar *toolBar();
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &/*state*/);
+
+ // ContextInterface
+ QList<int> context() const;
+ QWidget *widget();
+
+ // Internal
+ bool generateCode(QByteArray &header, QString &errorMessage) const;
+ QDesignerFormWindowInterface *formWindow() const;
+ QWidget *integrationContainer();
+ void updateFormWindowSelectionHandles(bool state);
+ void setSuggestedFileName(const QString &fileName);
+
+signals:
+ // Internal
+ void opened(const QString &fileName);
+
+public slots:
+ void activate();
+
+private slots:
+ void slotOpen(const QString &fileName);
+ void slotSetDisplayName(const QString &title);
+ void updateResources();
+
+private:
+ QString m_displayName;
+ const QList<int> m_context;
+ QDesignerFormWindowInterface *m_formWindow;
+ FormWindowFile *m_file;
+ FormWindowHost *m_host;
+ EditorWidget *m_editorWidget;
+ QToolBar *m_toolBar;
+ QStringList m_originalUiQrcPaths;
+ ProjectExplorer::SessionNode *m_sessionNode;
+ ProjectExplorer::NodesWatcher *m_sessionWatcher;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //FORMWINDOWEDITOR_H
diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp
new file mode 100644
index 0000000000..8ee26e4ac6
--- /dev/null
+++ b/src/plugins/designer/formwindowfile.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formwindowfile.h"
+#include "designerconstants.h"
+
+#include <coreplugin/icore.h>
+#include <utils/reloadpromptutils.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+
+using namespace Designer::Internal;
+using namespace Designer::Constants;
+using namespace SharedTools;
+
+enum { debugFormWindowFile = 0 };
+
+
+FormWindowFile::FormWindowFile(Core::ICore *core,
+ QDesignerFormWindowInterface *form,
+ QObject *parent) :
+ Core::IFile(parent),
+ m_mimeType(QLatin1String(FORM_MIMETYPE)),
+ m_formWindow(form),
+ m_core(core)
+{
+}
+
+FormWindowFile::~FormWindowFile()
+{
+}
+
+bool FormWindowFile::save(const QString &name /*= QString()*/)
+{
+ const QString actualName = name.isEmpty() ? fileName() : name;
+
+ if (debugFormWindowFile)
+ qDebug() << "FormWindowFile::save" << name << "->" << actualName;
+
+ if (actualName.isEmpty())
+ return false;
+
+ const QFileInfo fi(actualName);
+ const QString oldFormName = m_formWindow->fileName();
+ const QString formName = fi.absoluteFilePath();
+ m_formWindow->setFileName(formName);
+
+ QString errorString;
+ if (!writeFile(actualName, errorString)) {
+ QMessageBox::critical(0, tr("Error saving %1").arg(formName), errorString);
+ m_formWindow->setFileName(oldFormName);
+ return false;
+ }
+
+ m_fileName = fi.absoluteFilePath();
+ emit setDisplayName(fi.fileName());
+ m_formWindow->setDirty(false);
+ emit changed();
+
+ return true;
+}
+
+QString FormWindowFile::fileName() const
+{
+ return m_fileName;
+}
+
+bool FormWindowFile::isModified() const
+{
+ return m_formWindow->isDirty();
+}
+
+bool FormWindowFile::isReadOnly() const
+{
+ if (m_fileName.isEmpty())
+ return false;
+ const QFileInfo fi(m_fileName);
+ return !fi.isWritable();
+}
+
+bool FormWindowFile::isSaveAsAllowed() const
+{
+ return true;
+}
+
+void FormWindowFile::modified(Core::IFile::ReloadBehavior *behavior)
+{
+ if (debugFormWindowFile)
+ qDebug() << "FormWindowFile::modified" << m_fileName << *behavior;
+
+ switch (*behavior) {
+ case Core::IFile::ReloadNone:
+ return;
+ case Core::IFile::ReloadAll:
+ emit reload(m_fileName);
+ return;
+ case Core::IFile::ReloadPermissions:
+ emit changed();
+ return;
+ case Core::IFile::AskForReload:
+ break;
+ }
+
+ switch (Core::Utils::reloadPrompt(m_fileName, m_core->mainWindow())) {
+ case Core::Utils::ReloadCurrent:
+ emit reload(m_fileName);
+ break;
+ case Core::Utils::ReloadAll:
+ emit reload(m_fileName);
+ *behavior = Core::IFile::ReloadAll;
+ break;
+ case Core::Utils::ReloadSkipCurrent:
+ break;
+ case Core::Utils::ReloadNone:
+ *behavior = Core::IFile::ReloadNone;
+ break;
+ }
+}
+
+QString FormWindowFile::defaultPath() const
+{
+ return QString();
+}
+
+void FormWindowFile::setSuggestedFileName(const QString &fileName)
+{
+ if (debugFormWindowFile)
+ qDebug() << "FormWindowFile:setSuggestedFileName" << m_fileName << fileName;
+
+ m_suggestedName = fileName;
+}
+
+QString FormWindowFile::suggestedFileName() const
+{
+ return m_suggestedName;
+}
+
+QString FormWindowFile::mimeType() const
+{
+ return m_mimeType;
+}
+
+bool FormWindowFile::writeFile(const QString &fileName, QString &errorString) const
+{
+ if (debugFormWindowFile)
+ qDebug() << "FormWindowFile::writeFile" << m_fileName << fileName;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ errorString = tr("Unable to open %1: %2").arg(fileName, file.errorString());
+ return false;
+ }
+ const bool rc = writeFile(file, errorString);
+ file.close();
+ return rc;
+}
+
+bool FormWindowFile::writeFile(QFile &file, QString &errorString) const
+{
+ const QByteArray content = m_formWindow->contents().toUtf8();
+ if (!file.write(content)) {
+ errorString = tr("Unable to write to %1: %2").arg(file.fileName(), file.errorString());
+ return false;
+ }
+ return true;
+}
+
+void FormWindowFile::setFileName(const QString &fname)
+{
+ m_fileName = fname;
+}
diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h
new file mode 100644
index 0000000000..fc95b05f86
--- /dev/null
+++ b/src/plugins/designer/formwindowfile.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMWINDOWFILE_H
+#define FORMWINDOWFILE_H
+
+#include <coreplugin/ifile.h>
+
+#include "widgethost.h"
+#include "designerconstants.h"
+
+QT_BEGIN_NAMESPACE
+class QDesignerFormWindowInterface;
+class QDesignerFormWindowManagerInterface;
+class QFile;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace Designer {
+namespace Internal {
+
+class FormWindowSelection;
+
+class FormWindowFile
+ : public Core::IFile
+{
+ Q_OBJECT
+
+public:
+ FormWindowFile(Core::ICore *core,
+ QDesignerFormWindowInterface *form,
+ QObject *parent = 0);
+ ~FormWindowFile();
+
+ //IFile
+ bool save(const QString &fileName = QString());
+ QString fileName() const;
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+ void modified(Core::IFile::ReloadBehavior *behavior);
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+ virtual QString mimeType() const;
+
+ // Internal
+ void setSuggestedFileName(const QString &fileName);
+ bool writeFile(const QString &fileName, QString &errorString) const;
+ bool writeFile(QFile &file, QString &errorString) const;
+
+signals:
+ // IFile
+ void changed();
+ // Internal
+ void reload(const QString &);
+ void setDisplayName(const QString &);
+
+public slots:
+ void setFileName(const QString &);
+
+private:
+ const QString m_mimeType;
+ QString m_fileName;
+ QString m_suggestedName;
+
+ QDesignerFormWindowInterface *m_formWindow;
+ Core::ICore *m_core;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //FORMWINDOWFILE_H
diff --git a/src/plugins/designer/formwindowhost.cpp b/src/plugins/designer/formwindowhost.cpp
new file mode 100644
index 0000000000..c03a17df90
--- /dev/null
+++ b/src/plugins/designer/formwindowhost.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formwindowhost.h"
+#include "formeditorw.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+
+#include <QtCore/QDebug>
+#include <QtCore/QVariant>
+
+using namespace Designer::Internal;
+using namespace SharedTools;
+
+enum { debugFormWindowHost = 0 };
+
+FormWindowHost::FormWindowHost(QDesignerFormWindowInterface *form,
+ QWidget *parent) :
+ WidgetHost(parent, form)
+{
+ connect(formWindow(), SIGNAL(selectionChanged()), this, SIGNAL(changed()));
+ connect(this, SIGNAL(formWindowSizeChanged(int,int)), this, SLOT(formSizeChanged(int,int)));
+ connect(formWindow(), SIGNAL(changed()), this, SIGNAL(changed()));
+}
+
+FormWindowHost::~FormWindowHost()
+{
+ if (debugFormWindowHost)
+ qDebug() << "FormWindowHost::~FormWindowHost";
+}
+
+void FormWindowHost::formSizeChanged(int w, int h)
+{
+ if (debugFormWindowHost)
+ qDebug() << "FormWindowHost::formSizeChanged" << w << h;
+
+ formWindow()->setDirty(true);
+ static const QString geometry = QLatin1String("geometry");
+ FormEditorW::instance()->designerEditor()->propertyEditor()->setPropertyValue(geometry, QRect(0,0,w,h) );
+ emit changed();
+}
diff --git a/src/plugins/designer/formwindowhost.h b/src/plugins/designer/formwindowhost.h
new file mode 100644
index 0000000000..e74cd12e43
--- /dev/null
+++ b/src/plugins/designer/formwindowhost.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMWINDOWHOST_H
+#define FORMWINDOWHOST_H
+
+
+#include "widgethost.h"
+
+class QDesignerFormWindowInterface;
+
+namespace Designer {
+namespace Internal {
+
+class FormWindowHost : public SharedTools::WidgetHost
+{
+ Q_OBJECT
+public:
+ FormWindowHost(QDesignerFormWindowInterface *form, QWidget *parent = 0);
+ ~FormWindowHost();
+
+signals:
+ void changed();
+
+private slots:
+ void formSizeChanged(int w, int h);
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //FORMWINDOWHOST_H
diff --git a/src/plugins/designer/formwizard.cpp b/src/plugins/designer/formwizard.cpp
new file mode 100644
index 0000000000..b17657520b
--- /dev/null
+++ b/src/plugins/designer/formwizard.cpp
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formwizard.h"
+#include "formwizarddialog.h"
+#include "formwindoweditor.h"
+#include "designerconstants.h"
+
+#include <coreplugin/icore.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+
+enum { debugFormWizard = 0 };
+
+using namespace Designer;
+using namespace Designer::Internal;
+
+FormWizard::FormWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent) :
+ Core::BaseFileWizard(parameters, core, parent)
+{
+}
+
+QWizard *FormWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ FormFileWizardDialog *wizardDialog = new FormFileWizardDialog(core(), extensionPages, parent);
+ wizardDialog->setPath(defaultPath);
+ return wizardDialog;
+}
+
+Core::GeneratedFiles FormWizard::generateFiles(const QWizard *w,
+ QString *errorMessage) const
+{
+ const FormFileWizardDialog *wizard = qobject_cast<const FormFileWizardDialog *>(w);
+ const QString fileName = Core::BaseFileWizard::buildFileName(wizard->path(), wizard->name(),
+ preferredSuffix(QLatin1String(Constants::FORM_MIMETYPE)));
+
+ const QString formTemplate = wizard->templateContents();
+ if (formTemplate.isEmpty()) {
+ *errorMessage = QLatin1String("Internal error: FormWizard::generateFiles: empty template contents");
+ return Core::GeneratedFiles();
+ }
+
+ Core::GeneratedFile file(fileName);
+ file.setContents(formTemplate);
+ file.setEditorKind(QLatin1String(Constants::C_FORMEDITOR));
+ return Core::GeneratedFiles() << file;
+}
diff --git a/src/plugins/designer/formwizard.h b/src/plugins/designer/formwizard.h
new file mode 100644
index 0000000000..fe20de2ac6
--- /dev/null
+++ b/src/plugins/designer/formwizard.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMWIZARD_H
+#define FORMWIZARD_H
+
+#include <coreplugin/basefilewizard.h>
+
+QT_BEGIN_NAMESPACE
+class QWizard;
+QT_END_NAMESPACE
+
+namespace Designer {
+namespace Internal {
+
+class FormFileWizardDialog;
+
+class FormWizard : public Core::BaseFileWizard
+{
+ Q_DISABLE_COPY(FormWizard)
+ Q_OBJECT
+
+public:
+ typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
+
+ explicit FormWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent);
+
+protected:
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+
+ virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // FORMWIZARD_H
diff --git a/src/plugins/designer/formwizarddialog.cpp b/src/plugins/designer/formwizarddialog.cpp
new file mode 100644
index 0000000000..e673385298
--- /dev/null
+++ b/src/plugins/designer/formwizarddialog.cpp
@@ -0,0 +1,127 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formwizarddialog.h"
+#include "formtemplatewizardpage.h"
+#include "formeditorw.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/basefilewizard.h>
+
+#include <utils/filewizardpage.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QAbstractButton>
+
+// Make sure there is a gap before the extension pages
+enum { FormPageId, FilePageId, FirstExtensionPageId = 10 };
+
+namespace Designer {
+namespace Internal {
+
+// ----------------- FormWizardDialog
+FormWizardDialog::FormWizardDialog(Core::ICore *core,
+ const WizardPageList &extensionPages,
+ QWidget *parent) :
+ QWizard(parent),
+ m_formPage(new FormTemplateWizardPagePage),
+ m_core(core)
+{
+ init(extensionPages);
+}
+
+void FormWizardDialog::init(const WizardPageList &extensionPages)
+{
+ Core::BaseFileWizard::setupWizard(this);
+ setWindowTitle(tr("Qt Designer Form"));
+ setPage(FormPageId, m_formPage);
+
+ if (!extensionPages.empty()) {
+ int id = FirstExtensionPageId;
+ foreach (QWizardPage *p, extensionPages)
+ setPage(id++, p);
+ }
+}
+
+QString FormWizardDialog::templateContents() const
+{
+ // Template is expensive, cache
+ if (m_templateContents.isEmpty())
+ m_templateContents = m_formPage->templateContents();
+ return m_templateContents;
+}
+
+// ----------------- FormFileWizardDialog
+FormFileWizardDialog::FormFileWizardDialog(Core::ICore *core,
+ const WizardPageList &extensionPages,
+ QWidget *parent) :
+ FormWizardDialog(core, extensionPages, parent),
+ m_filePage(new Core::Utils::FileWizardPage)
+{
+ setPage(FilePageId, m_filePage);
+ connect(m_filePage, SIGNAL(activated()),
+ button(QWizard::FinishButton), SLOT(animateClick()));
+
+ connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentIdChanged(int)));
+}
+
+QString FormFileWizardDialog::path() const
+{
+ return m_filePage->path();
+}
+
+void FormFileWizardDialog::setPath(const QString &path)
+{
+ m_filePage->setPath(path);
+}
+
+QString FormFileWizardDialog::name() const
+{
+ return m_filePage->name();
+}
+
+void FormFileWizardDialog::slotCurrentIdChanged(int id)
+{
+ if (id == FilePageId) {
+ // Change from form to file: Store template and Suggest a name based on
+ // the ui class
+ QString formBaseClass;
+ QString uiClassName;
+ if (FormTemplateWizardPagePage::getUIXmlData(templateContents(), &formBaseClass, &uiClassName)) {
+ QString fileName = FormTemplateWizardPagePage::stripNamespaces(uiClassName).toLower();
+ fileName += QLatin1String(".ui");
+ m_filePage->setName(fileName);
+ }
+ }
+}
+} // namespace Internal
+} // namespace Designer
diff --git a/src/plugins/designer/formwizarddialog.h b/src/plugins/designer/formwizarddialog.h
new file mode 100644
index 0000000000..fd1155e00b
--- /dev/null
+++ b/src/plugins/designer/formwizarddialog.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMWIZARDDIALOG_H
+#define FORMWIZARDDIALOG_H
+
+#include <QtGui/QWizard>
+
+namespace Core {
+ class ICore;
+ namespace Utils {
+ class FileWizardPage;
+ }
+}
+
+namespace Designer {
+namespace Internal {
+
+class FormTemplateWizardPagePage;
+
+// Single-Page Wizard for new forms offering all types known to Qt Designer.
+// To be used for Mode "CreateNewEditor" [not currently used]
+
+class FormWizardDialog : public QWizard
+{
+ Q_DISABLE_COPY(FormWizardDialog)
+ Q_OBJECT
+
+public:
+ typedef QList<QWizardPage *> WizardPageList;
+ explicit FormWizardDialog(Core::ICore *core,
+ const WizardPageList &extensionPages,
+ QWidget *parent = 0);
+
+ QString templateContents() const;
+
+private:
+ void init(const WizardPageList &extensionPages);
+
+ FormTemplateWizardPagePage *m_formPage;
+ Core::ICore *m_core;
+ mutable QString m_templateContents;
+};
+
+// Two-Page Wizard for new forms for mode "CreateNewFile". Gives
+// FormWizardDialog an additional page with file and path fields,
+// initially determined from the UI class chosen on page one.
+
+class FormFileWizardDialog : public FormWizardDialog
+{
+ Q_DISABLE_COPY(FormFileWizardDialog)
+ Q_OBJECT
+
+public:
+ explicit FormFileWizardDialog(Core::ICore *core,
+ const WizardPageList &extensionPages,
+ QWidget *parent = 0);
+
+ QString path() const;
+ QString name() const;
+
+public slots:
+ void setPath(const QString &path);
+
+private slots:
+ void slotCurrentIdChanged(int id);
+
+private:
+ Core::Utils::FileWizardPage *m_filePage;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //FORMWIZARDDIALOG_H
diff --git a/src/plugins/designer/images/qt_ui.png b/src/plugins/designer/images/qt_ui.png
new file mode 100644
index 0000000000..8fb61ee27f
--- /dev/null
+++ b/src/plugins/designer/images/qt_ui.png
Binary files differ
diff --git a/src/plugins/designer/settingsmanager.cpp b/src/plugins/designer/settingsmanager.cpp
new file mode 100644
index 0000000000..9a737e8b0a
--- /dev/null
+++ b/src/plugins/designer/settingsmanager.cpp
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <settingsmanager.h>
+#include <QtCore/QDebug>
+
+using namespace Designer::Internal;
+
+namespace {
+ bool debug = false;
+}
+
+void SettingsManager::beginGroup(const QString &prefix)
+{
+ if (debug)
+ qDebug() << "Designer - beginning group " << addPrefix(prefix);
+ m_settings.beginGroup(addPrefix(prefix));
+}
+
+void SettingsManager::endGroup()
+{
+ if (debug)
+ qDebug() << "Designer - end group";
+ m_settings.endGroup();
+}
+
+bool SettingsManager::contains(const QString &key) const
+{
+ return m_settings.contains(addPrefix(key));
+}
+
+void SettingsManager::setValue(const QString &key, const QVariant &value)
+{
+ if (debug)
+ qDebug() << "Designer - storing " << addPrefix(key) << ": " << value;
+ m_settings.setValue(addPrefix(key), value);
+}
+
+QVariant SettingsManager::value(const QString &key, const QVariant &defaultValue) const
+{
+ QVariant result = m_settings.value(addPrefix(key), defaultValue);
+ if (debug)
+ qDebug() << "Designer - retrieving " << addPrefix(key) << ": " << result;
+ return result;
+}
+
+void SettingsManager::remove(const QString &key)
+{
+ m_settings.remove(addPrefix(key));
+}
+
+QString SettingsManager::addPrefix(const QString &name) const
+{
+ QString result = name;
+ if (m_settings.group().isEmpty())
+ result.insert(0, QLatin1String("Designer"));
+ return result;
+}
diff --git a/src/plugins/designer/settingsmanager.h b/src/plugins/designer/settingsmanager.h
new file mode 100644
index 0000000000..92783e4510
--- /dev/null
+++ b/src/plugins/designer/settingsmanager.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSMANAGER_H
+#define SETTINGSMANAGER_H
+
+#include <QtDesigner/private/abstractsettings_p.h>
+#include <QtCore/QSettings>
+
+namespace Designer {
+namespace Internal {
+
+/* Prepends "Designer" to every value stored/retrieved by designer plugins,
+ to avoid namespace polution. We cannot use a group because groups cannot be nested,
+ and designer uses groups internally. */
+class SettingsManager : public QDesignerSettingsInterface
+{
+public:
+ virtual void beginGroup(const QString &prefix);
+ virtual void endGroup();
+
+ virtual bool contains(const QString &key) const;
+ virtual void setValue(const QString &key, const QVariant &value);
+ virtual QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const ;
+ virtual void remove(const QString &key);
+
+private:
+ QString addPrefix(const QString &name) const;
+ QSettings m_settings;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif //SETTINGSMANAGER_H
diff --git a/src/plugins/designer/settingspage.cpp b/src/plugins/designer/settingspage.cpp
new file mode 100644
index 0000000000..c09c3a0849
--- /dev/null
+++ b/src/plugins/designer/settingspage.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <QtDesigner/private/abstractoptionspage_p.h>
+
+using namespace Designer::Internal;
+
+SettingsPage::SettingsPage(QDesignerOptionsPageInterface *designerPage) :
+ m_designerPage(designerPage)
+{
+}
+
+SettingsPage::~SettingsPage()
+{
+}
+
+QString SettingsPage::name() const
+{
+ return m_designerPage->name();
+}
+
+QString SettingsPage::category() const
+{
+ return QLatin1String("Designer");
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("Designer");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ return m_designerPage->createPage(parent);
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ m_designerPage->finish(accepted);
+}
diff --git a/src/plugins/designer/settingspage.h b/src/plugins/designer/settingspage.h
new file mode 100644
index 0000000000..30da61814b
--- /dev/null
+++ b/src/plugins/designer/settingspage.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DESIGNER_SETTINGSPAGE_H
+#define DESIGNER_SETTINGSPAGE_H
+
+#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+QT_BEGIN_NAMESPACE
+class QDesignerOptionsPageInterface;
+QT_END_NAMESPACE
+
+namespace Designer {
+namespace Internal {
+
+class SettingsPageWidget;
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ explicit SettingsPage(QDesignerOptionsPageInterface *designerPage);
+ virtual ~SettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+private:
+ QDesignerOptionsPageInterface *m_designerPage;
+};
+
+} //namespace Internal
+} //namespace QuickOpen
+
+#endif // DESIGNER_SETTINGSPAGE_H
diff --git a/src/plugins/designer/workbenchintegration.cpp b/src/plugins/designer/workbenchintegration.cpp
new file mode 100644
index 0000000000..42e55d0265
--- /dev/null
+++ b/src/plugins/designer/workbenchintegration.cpp
@@ -0,0 +1,352 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "formeditorplugin.h"
+#include "workbenchintegration.h"
+#include "formeditorw.h"
+#include "formwindoweditor.h"
+
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <cplusplus/Symbols.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/CoreTypes.h>
+#include <cplusplus/Name.h>
+#include <cplusplus/Names.h>
+#include <cplusplus/Literals.h>
+#include <cplusplus/Scope.h>
+#include <cplusplus/Control.h>
+#include <cplusplus/LookupContext.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/basetexteditor.h>
+#include <texteditor/itexteditable.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtCore/QFileInfo>
+
+#include <QtCore/QDebug>
+
+using namespace Designer::Internal;
+using namespace CPlusPlus;
+using namespace TextEditor;
+
+WorkbenchIntegration::WorkbenchIntegration(QDesignerFormEditorInterface *core, FormEditorW *parent) :
+ qdesigner_internal::QDesignerIntegration(core, ::qobject_cast<QObject*>(parent)),
+ m_few(parent)
+{
+ setResourceFileWatcherBehaviour(QDesignerIntegration::ReloadSilently);
+ setResourceEditingEnabled(false);
+ setSlotNavigationEnabled(true);
+ connect(this, SIGNAL(navigateToSlot(QString, QString)),
+ this, SLOT(slotNavigateToSlot(QString, QString)));
+}
+
+void WorkbenchIntegration::updateSelection()
+{
+ if (FormWindowEditor *afww = m_few->activeFormWindow())
+ afww->updateFormWindowSelectionHandles(true);
+ qdesigner_internal::QDesignerIntegration::updateSelection();
+}
+
+QWidget *WorkbenchIntegration::containerWindow(QWidget * /*widget*/) const
+{
+ FormWindowEditor *fw = m_few->activeFormWindow();
+ if (!fw)
+ return 0;
+ return fw->integrationContainer();
+}
+
+QList<Document::Ptr> WorkbenchIntegration::findDocuments(const QString &uiFileName) const
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ CppTools::CppModelManagerInterface *cppModelManager =
+ core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
+
+ QList<Document::Ptr> docList;
+ // take all docs
+ CppTools::CppModelManagerInterface::DocumentTable docTable = cppModelManager->documents();
+ foreach (Document::Ptr doc, docTable) { // we go through all documents
+ QStringList includes = doc->includedFiles();
+ foreach (QString include, includes) {
+ const QFileInfo fi(include); // TODO: we should match an absolute path. Currently uiFileName is a file name only.
+ if (fi.fileName() == uiFileName) { // we are only interested in docs which includes our ui file
+ docList.append(doc);
+ }
+ }
+ }
+ return docList;
+}
+
+
+
+Class *WorkbenchIntegration::findClass(Namespace *parentNameSpace, const QString &uiClassName) const
+{
+ for (unsigned i = 0; i < parentNameSpace->memberCount(); i++) { // we go through all namespace members
+ if (Class *cl = parentNameSpace->memberAt(i)->asClass()) { // we have found a class - we are interested in classes only
+ Overview o;
+ QString className = o.prettyName(cl->name());
+ for (unsigned j = 0; j < cl->memberCount(); j++) { // we go through class members
+ const Declaration *decl = cl->memberAt(j)->asDeclaration();
+ if (decl) { // we want to know if the class contains a member (so we look into a declaration) of uiClassName type
+ const QString v1 = QLatin1String("Ui::") + uiClassName; // TODO: handle also the case of namespaced class name
+ const QString v2 = QLatin1String("Ui_") + uiClassName;
+
+ NamedType *nt = decl->type()->asNamedType();
+
+ // handle pointers to member variables
+ if (PointerType *pt = decl->type()->asPointerType())
+ nt = pt->elementType()->asNamedType();
+
+ if (nt) {
+ Overview typeOverview;
+ const QString memberClass = typeOverview.prettyName(nt->name());
+ if (memberClass == v1 || memberClass == v2) // simple match here
+ return cl;
+ }
+ }
+ }
+ } else if (Namespace *ns = parentNameSpace->memberAt(i)->asNamespace()) {
+ return findClass(ns, uiClassName);
+ }
+ }
+ return 0;
+}
+
+Function *WorkbenchIntegration::findFunction(Class *cl, const QString &functionName) const
+{
+ // TODO: match properly function name and argument list, for now we match only function name
+ // (Roberto's suggestion: use QtMethodAST for that, enclosing function with SIGNAL(<fun>)
+ // then it becames an expression). Robetro's also proposed he can add public methods to parse declarations
+
+ // Quick implementation start
+ QString funName = functionName.left(functionName.indexOf(QLatin1Char('(')));
+ // Quick implementation end
+ for (unsigned j = 0; j < cl->memberCount(); j++) { // go through all members
+ const Declaration *decl = cl->memberAt(j)->asDeclaration();
+ if (decl) { // we are interested only in declarations (can be decl of method or of a field)
+ Function *fun = decl->type()->asFunction();
+ if (fun) { // we are only interested in declarations of methods
+ Overview typeOverview;
+ const QString memberFunction = typeOverview.prettyName(fun->name());
+ if (memberFunction == funName) // simple match (we match only fun name, we should match also arguments)
+ return fun;
+ }
+ }
+ }
+ return 0;
+}
+
+// TODO: remove me, see below
+static bool isCompatible(Name *name, Name *otherName)
+{
+ if (NameId *nameId = name->asNameId()) {
+ if (TemplateNameId *otherTemplId = otherName->asTemplateNameId())
+ return nameId->identifier()->isEqualTo(otherTemplId->identifier());
+ } else if (TemplateNameId *templId = name->asTemplateNameId()) {
+ if (NameId *otherNameId = otherName->asNameId())
+ return templId->identifier()->isEqualTo(otherNameId->identifier());
+ }
+
+ return name->isEqualTo(otherName);
+}
+
+// TODO: remove me, see below
+static bool isCompatible(Function *definition, Symbol *declaration, QualifiedNameId *declarationName)
+{
+ Function *declTy = declaration->type()->asFunction();
+ if (! declTy)
+ return false;
+
+ Name *definitionName = definition->name();
+ if (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) {
+ Name *n = q->nameAt(q->nameCount() - i - 1);
+ 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
+Document::Ptr WorkbenchIntegration::findDefinition(Function *functionDeclaration, int *line) const
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ CppTools::CppModelManagerInterface *cppModelManager =
+ core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
+ if (!cppModelManager)
+ return Document::Ptr();
+
+ QVector<Name *> qualifiedName;
+ Scope *scope = functionDeclaration->scope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->isClassScope() || scope->isNamespaceScope()) {
+ if (scope->owner() && scope->owner()->name()) {
+ Name *scopeOwnerName = scope->owner()->name();
+ if (QualifiedNameId *q = scopeOwnerName->asQualifiedNameId()) {
+ for (unsigned i = 0; i < q->nameCount(); ++i) {
+ qualifiedName.prepend(q->nameAt(i));
+ }
+ } else {
+ qualifiedName.prepend(scopeOwnerName);
+ }
+ }
+ }
+ }
+
+ qualifiedName.append(functionDeclaration->name());
+
+ Control control;
+ QualifiedNameId *q = control.qualifiedNameId(&qualifiedName[0], qualifiedName.size());
+ LookupContext context(&control);
+
+ const QMap<QString, Document::Ptr> documents = cppModelManager->documents();
+ foreach (Document::Ptr doc, documents) {
+ QList<Scope *> visibleScopes;
+ visibleScopes.append(doc->globalSymbols());
+ visibleScopes = context.expand(visibleScopes);
+ foreach (Scope *visibleScope, visibleScopes) {
+ Symbol *symbol = 0;
+ if (NameId *nameId = q->unqualifiedNameId()->asNameId())
+ symbol = visibleScope->lookat(nameId->identifier());
+ else if (DestructorNameId *dtorId = q->unqualifiedNameId()->asDestructorNameId())
+ symbol = visibleScope->lookat(dtorId->identifier());
+ else if (TemplateNameId *templNameId = q->unqualifiedNameId()->asTemplateNameId())
+ symbol = visibleScope->lookat(templNameId->identifier());
+ else if (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();
+
+}
+
+void WorkbenchIntegration::addDeclaration(const QString &docFileName, Class *cl, const QString &functionName) const
+{
+ // TODO: add argument names (from designer we get only argument types)
+ for (unsigned j = 0; j < cl->memberCount(); j++) { // go through all members
+ const Declaration *decl = cl->memberAt(j)->asDeclaration();
+ if (decl) { // we want to find any method which is a private slot (then we don't need to add "private slots:" statement)
+ Function *fun = decl->type()->asFunction();
+ if (fun) { // we are only interested in declarations of methods
+ if (fun->isSlot() && fun->isPrivate()) {
+ ITextEditable *editable = qobject_cast<ITextEditable *>(
+ TextEditor::BaseTextEditor::openEditorAt(docFileName, fun->line()/*, fun->column()*/)); // TODO: fun->column() gives me weird number...
+ if (editable) {
+ editable->insert(QLatin1String("void ") + functionName + QLatin1String(";\n "));
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ // TODO: we didn't find "private slots:", let's add it
+
+ return;
+}
+
+void WorkbenchIntegration::slotNavigateToSlot(const QString &objectName, const QString &signalSignature)
+{
+ const QString currentUiFile = m_few->activeFormWindow()->file()->fileName();
+
+ // TODO: we should pass to findDocuments an absolute path to generated .h file from ui.
+ // Currently we are guessing the name of ui_<>.h file and pass the file name only to the findDocuments().
+ // The idea is that the .pro file knows if the .ui files is inside, and the .pro file knows it will
+ // be generating the ui_<>.h file for it, and the .pro file knows what the generated file's name and its absolute path will be.
+ // So we should somehow get that info from project manager (?)
+ const QFileInfo fi(currentUiFile);
+ const QString uicedName = QLatin1String("ui_") + fi.baseName() + QLatin1String(".h");
+
+ QList<Document::Ptr> docList = findDocuments(uicedName);
+ if (docList.isEmpty())
+ return;
+
+ QDesignerFormWindowInterface *fwi = m_few->activeFormWindow()->formWindow();
+
+ const QString uiClassName = fwi->mainContainer()->objectName();
+
+ foreach (Document::Ptr doc, docList) {
+ Class *cl = findClass(doc->globalNamespace(), uiClassName);
+ if (cl) {
+ QString functionName = QLatin1String("on_") + objectName + QLatin1Char('_') + signalSignature;
+ Function *fun = findFunction(cl, functionName);
+ int line = 0;
+ if (!fun) {
+ // add function declaration to cl
+ addDeclaration(doc->fileName(), cl, functionName);
+ // TODO: add function definition to cpp file
+
+ } else {
+ doc = findDefinition(fun, &line);
+ }
+ if (doc) {
+ // jump to function definition
+ TextEditor::BaseTextEditor::openEditorAt(doc->fileName(), line);
+ }
+ return;
+ }
+ }
+}
+
diff --git a/src/plugins/designer/workbenchintegration.h b/src/plugins/designer/workbenchintegration.h
new file mode 100644
index 0000000000..21aee510aa
--- /dev/null
+++ b/src/plugins/designer/workbenchintegration.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WORKBENCHINTEGRATION_H
+#define WORKBENCHINTEGRATION_H
+
+#include <cpptools/cppmodelmanagerinterface.h>
+
+#include <QtDesigner/private/qdesigner_integration_p.h>
+
+namespace Designer {
+namespace Internal {
+
+class FormEditorW;
+
+class WorkbenchIntegration : public qdesigner_internal::QDesignerIntegration {
+ Q_OBJECT
+public:
+ WorkbenchIntegration(QDesignerFormEditorInterface *core, FormEditorW *parent = 0);
+
+ QWidget *containerWindow(QWidget *widget) const;
+
+ bool supportsToSlotNavigation() { return true; };
+
+public slots:
+ void updateSelection();
+private slots:
+ void slotNavigateToSlot(const QString &objectName, const QString &signalSignature);
+private:
+ QList<CPlusPlus::Document::Ptr> findDocuments(const QString &uiFileName) const;
+ CPlusPlus::Class *findClass(CPlusPlus::Namespace *parentNameSpace, const QString &uiClassName) const;
+ CPlusPlus::Function *findFunction(CPlusPlus::Class *cl, const QString &functionName) const;
+ CPlusPlus::Document::Ptr findDefinition(CPlusPlus::Function *functionDeclaration, int *line) const;
+ void addDeclaration(const QString &docFileName, CPlusPlus::Class *cl, const QString &functionName) const;
+
+ FormEditorW *m_few;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // WORKBENCHINTEGRATION_H
diff --git a/src/plugins/find/Find.pluginspec b/src/plugins/find/Find.pluginspec
new file mode 100644
index 0000000000..13f712235b
--- /dev/null
+++ b/src/plugins/find/Find.pluginspec
@@ -0,0 +1,10 @@
+<plugin name="Find" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Provides the find widget and the hooks for find implementations.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/find/basetextfind.cpp b/src/plugins/find/basetextfind.cpp
new file mode 100644
index 0000000000..37787596d9
--- /dev/null
+++ b/src/plugins/find/basetextfind.cpp
@@ -0,0 +1,246 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basetextfind.h"
+#include <QtGui/QTextBlock>
+
+using namespace Find;
+
+BaseTextFind::BaseTextFind(QTextEdit *editor)
+ : m_editor(editor), m_incrementalStartPos(-1)
+{
+}
+
+BaseTextFind::BaseTextFind(QPlainTextEdit *editor)
+ : m_plaineditor(editor), m_incrementalStartPos(-1)
+{
+}
+
+QTextCursor BaseTextFind::textCursor() const
+{
+ Q_ASSERT(m_editor || m_plaineditor);
+ return m_editor ? m_editor->textCursor() : m_plaineditor->textCursor();
+
+}
+
+void BaseTextFind::setTextCursor(const QTextCursor& cursor)
+{
+ Q_ASSERT(m_editor || m_plaineditor);
+ m_editor ? m_editor->setTextCursor(cursor) : m_plaineditor->setTextCursor(cursor);
+}
+
+QTextDocument *BaseTextFind::document() const
+{
+ Q_ASSERT(m_editor || m_plaineditor);
+ return m_editor ? m_editor->document() : m_plaineditor->document();
+}
+
+bool BaseTextFind::isReadOnly() const
+{
+ Q_ASSERT(m_editor || m_plaineditor);
+ return m_editor ? m_editor->isReadOnly() : m_plaineditor->isReadOnly();
+}
+
+bool BaseTextFind::supportsReplace() const
+{
+ return !isReadOnly();
+}
+
+void BaseTextFind::resetIncrementalSearch()
+{
+ m_incrementalStartPos = -1;
+}
+
+void BaseTextFind::clearResults()
+{
+ emit highlightAll(QString(), 0);
+}
+
+QString BaseTextFind::currentFindString() const
+{
+ QTextCursor cursor = textCursor();
+ if (cursor.hasSelection() && cursor.block() != cursor.document()->findBlock(cursor.anchor())) {
+ return QString(); // multi block selection
+ }
+
+ if (cursor.hasSelection())
+ return cursor.selectedText();
+
+ if (!cursor.atBlockEnd() && !cursor.hasSelection()) {
+ cursor.movePosition(QTextCursor::StartOfWord);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ QString s = cursor.selectedText();
+ foreach(QChar c, s) {
+ if (!c.isLetterOrNumber() && c != QLatin1Char('_')) {
+ s.clear();
+ break;
+ }
+ }
+ return s;
+ }
+
+ return QString();
+}
+
+QString BaseTextFind::completedFindString() const
+{
+ QTextCursor cursor = textCursor();
+ cursor.setPosition(textCursor().selectionStart());
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ return cursor.selectedText();
+}
+
+bool BaseTextFind::findIncremental(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ QTextCursor cursor = textCursor();
+ if (m_incrementalStartPos < 0)
+ m_incrementalStartPos = cursor.selectionStart();
+ cursor.setPosition(m_incrementalStartPos);
+ findFlags &= ~QTextDocument::FindBackward;
+ bool found = find(txt, findFlags, cursor);
+ if (found)
+ emit highlightAll(txt, findFlags);
+ else
+ emit highlightAll(QString(), 0);
+ return found;
+}
+
+bool BaseTextFind::findStep(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ bool found = find(txt, findFlags, textCursor());
+ if (found)
+ m_incrementalStartPos = textCursor().selectionStart();
+ return found;
+}
+
+bool BaseTextFind::replaceStep(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags)
+{
+ QTextCursor cursor = textCursor();
+ if (cursor.selectedText().compare(before,
+ ((findFlags&QTextDocument::FindCaseSensitively)!=0) ? Qt::CaseSensitive : Qt::CaseInsensitive) == 0) {
+ int start = cursor.selectionStart();
+ cursor.insertText(after);
+ if ((findFlags&QTextDocument::FindBackward) != 0)
+ cursor.setPosition(start);
+ }
+ return find(before, findFlags, cursor);
+}
+
+int BaseTextFind::replaceAll(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags)
+{
+ QTextCursor editCursor = textCursor();
+ editCursor.movePosition(QTextCursor::Start);
+ editCursor.beginEditBlock();
+ int count = 0;
+ QTextCursor found;
+ found = document()->find(before, editCursor, findFlags);
+ while (!found.isNull() && inScope(found.selectionStart(), found.selectionEnd())) {
+ ++count;
+ editCursor.setPosition(found.selectionStart());
+ editCursor.setPosition(found.selectionEnd(), QTextCursor::KeepAnchor);
+ editCursor.insertText(after);
+ found = document()->find(before, editCursor, findFlags);
+ }
+ editCursor.endEditBlock();
+ return count;
+}
+
+bool BaseTextFind::find(const QString &txt,
+ QTextDocument::FindFlags findFlags,
+ QTextCursor start)
+{
+ if (txt.isEmpty()) {
+ setTextCursor(start);
+ return true;
+ }
+ QTextCursor found = document()->find(txt, start, findFlags);
+
+ if (!m_findScope.isNull()) {
+
+ // scoped
+ if (found.isNull() || !inScope(found.selectionStart(), found.selectionEnd())) {
+ if ((findFlags&QTextDocument::FindBackward) == 0)
+ start.setPosition(m_findScope.selectionStart());
+ else
+ start.setPosition(m_findScope.selectionEnd());
+ found = document()->find(txt, start, findFlags);
+ if (found.isNull() || !inScope(found.selectionStart(), found.selectionEnd()))
+ return false;
+ }
+ } else {
+
+ // entire document
+ if (found.isNull()) {
+ if ((findFlags&QTextDocument::FindBackward) == 0)
+ start.movePosition(QTextCursor::Start);
+ else
+ start.movePosition(QTextCursor::End);
+ found = document()->find(txt, start, findFlags);
+ if (found.isNull()) {
+ return false;
+ }
+ }
+ }
+ if (!found.isNull()) {
+ setTextCursor(found);
+ }
+ return true;
+}
+
+bool BaseTextFind::inScope(int startPosition, int endPosition) const
+{
+ if (m_findScope.isNull())
+ return true;
+ return (m_findScope.selectionStart() <= startPosition
+ && m_findScope.selectionEnd() >= endPosition);
+}
+
+void BaseTextFind::defineFindScope()
+{
+ QTextCursor cursor = textCursor();
+ if (cursor.hasSelection() && cursor.block() != cursor.document()->findBlock(cursor.anchor())) {
+ m_findScope = cursor;
+ emit findScopeChanged(m_findScope);
+ cursor.setPosition(cursor.selectionStart());
+ setTextCursor(cursor);
+ } else {
+ clearFindScope();
+ }
+}
+
+void BaseTextFind::clearFindScope()
+{
+ m_findScope = QTextCursor();
+ emit findScopeChanged(m_findScope);
+}
diff --git a/src/plugins/find/basetextfind.h b/src/plugins/find/basetextfind.h
new file mode 100644
index 0000000000..0647c8dccd
--- /dev/null
+++ b/src/plugins/find/basetextfind.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTFIND_H
+#define BASETEXTFIND_H
+
+#include "find_global.h"
+#include "ifindsupport.h"
+
+#include <QtCore/QPointer>
+#include <QtGui/QPlainTextEdit>
+
+namespace Find {
+
+class FIND_EXPORT BaseTextFind : public Find::IFindSupport
+{
+ Q_OBJECT
+
+public:
+ BaseTextFind(QPlainTextEdit *editor);
+ BaseTextFind(QTextEdit *editor);
+
+ bool supportsReplace() const;
+ void resetIncrementalSearch();
+ void clearResults();
+ QString currentFindString() const;
+ QString completedFindString() const;
+
+ bool findIncremental(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool findStep(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool replaceStep(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags);
+ int replaceAll(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags);
+
+ void defineFindScope();
+ void clearFindScope();
+
+signals:
+ void highlightAll(const QString &txt, QTextDocument::FindFlags findFlags);
+ void findScopeChanged(const QTextCursor &);
+
+private:
+ bool find(const QString &txt,
+ QTextDocument::FindFlags findFlags,
+ QTextCursor start);
+
+ QTextCursor textCursor() const;
+ void setTextCursor(const QTextCursor&);
+ QTextDocument *document() const;
+ bool isReadOnly() const;
+ QPointer<QTextEdit> m_editor;
+ QPointer<QPlainTextEdit> m_plaineditor;
+ QTextCursor m_findScope;
+ bool inScope(int startPosition, int endPosition) const;
+ int m_incrementalStartPos;
+};
+
+} // namespace Find
+
+#endif // BASETEXTFIND_H
diff --git a/src/plugins/find/currentdocumentfind.cpp b/src/plugins/find/currentdocumentfind.cpp
new file mode 100644
index 0000000000..1a4999cd13
--- /dev/null
+++ b/src/plugins/find/currentdocumentfind.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "currentdocumentfind.h"
+#include <aggregation/aggregate.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/modemanager.h>
+
+#include <QtGui/QApplication>
+#include <QtDebug>
+
+using namespace Core;
+using namespace Find;
+using namespace Find::Internal;
+
+CurrentDocumentFind::CurrentDocumentFind(ICore *core)
+ : m_core(core), m_currentFind(0)
+{
+ connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
+ this, SLOT(updateCurrentFindFilter(QWidget*,QWidget*)));
+}
+
+void CurrentDocumentFind::removeConnections()
+{
+ disconnect(qApp, 0, this, 0);
+ removeFindSupportConnections();
+}
+
+void CurrentDocumentFind::resetIncrementalSearch()
+{
+ Q_ASSERT(m_currentFind);
+ if (m_currentFind)
+ m_currentFind->resetIncrementalSearch();
+}
+
+void CurrentDocumentFind::clearResults()
+{
+ Q_ASSERT(m_currentFind);
+ if (m_currentFind)
+ m_currentFind->clearResults();
+}
+
+bool CurrentDocumentFind::isEnabled() const
+{
+ return m_currentFind && (!m_currentWidget || m_currentWidget->isVisible());
+}
+
+bool CurrentDocumentFind::supportsReplace() const
+{
+ Q_ASSERT(m_currentFind);
+ return m_currentFind ? m_currentFind->supportsReplace() : false;
+}
+
+QString CurrentDocumentFind::currentFindString() const
+{
+ Q_ASSERT(m_currentFind);
+ return m_currentFind ? m_currentFind->currentFindString() : QString();
+}
+
+QString CurrentDocumentFind::completedFindString() const
+{
+ Q_ASSERT(m_currentFind);
+ return m_currentFind ? m_currentFind->completedFindString() : QString();
+}
+
+void CurrentDocumentFind::highlightAll(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_currentFind);
+ if (m_currentFind)
+ m_currentFind->highlightAll(txt, findFlags);
+}
+
+bool CurrentDocumentFind::findIncremental(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_currentFind);
+ return (m_currentFind? m_currentFind->findIncremental(txt, findFlags) : false);
+}
+
+bool CurrentDocumentFind::findStep(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_currentFind);
+ return (m_currentFind? m_currentFind->findStep(txt, findFlags) : false);
+}
+
+bool CurrentDocumentFind::replaceStep(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_currentFind);
+ return (m_currentFind? m_currentFind->replaceStep(before, after, findFlags) : false);
+}
+
+int CurrentDocumentFind::replaceAll(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_currentFind);
+ return (m_currentFind? m_currentFind->replaceAll(before, after, findFlags) : 0);
+}
+
+void CurrentDocumentFind::defineFindScope()
+{
+ Q_ASSERT(m_currentFind);
+ if (m_currentFind)
+ m_currentFind->defineFindScope();
+}
+
+void CurrentDocumentFind::clearFindScope()
+{
+ Q_ASSERT(m_currentFind);
+ if (m_currentFind)
+ m_currentFind->clearFindScope();
+}
+
+void CurrentDocumentFind::updateCurrentFindFilter(QWidget *old, QWidget *now)
+{
+ Q_UNUSED(old);
+ QWidget *candidate = now;
+ QPointer<IFindSupport> impl = 0;
+ while (!impl && candidate) {
+ impl = Aggregation::query<IFindSupport>(candidate);
+ if (!impl)
+ candidate = candidate->parentWidget();
+ }
+ if (!impl)
+ return;
+ removeFindSupportConnections();
+ m_currentWidget = candidate;
+ m_currentFind = impl;
+ if (m_currentFind) {
+ connect(m_currentFind, SIGNAL(changed()), this, SIGNAL(changed()));
+ connect(m_currentFind, SIGNAL(destroyed(QObject*)), SLOT(findSupportDestroyed()));
+ }
+ if (m_currentWidget)
+ m_currentWidget->installEventFilter(this);
+ emit changed();
+}
+
+void CurrentDocumentFind::removeFindSupportConnections()
+{
+ if (m_currentFind) {
+ disconnect(m_currentFind, SIGNAL(changed()), this, SIGNAL(changed()));
+ disconnect(m_currentFind, SIGNAL(destroyed(QObject*)), this, SLOT(findSupportDestroyed()));
+ }
+ if (m_currentWidget)
+ m_currentWidget->removeEventFilter(this);
+}
+
+void CurrentDocumentFind::findSupportDestroyed()
+{
+ removeFindSupportConnections();
+ m_currentWidget = 0;
+ m_currentFind = 0;
+ emit changed();
+}
+
+bool CurrentDocumentFind::setFocusToCurrentFindSupport()
+{
+ if (m_currentFind && m_currentWidget) {
+ m_currentWidget->setFocus();
+ return true;
+ }
+ return false;
+}
+
+bool CurrentDocumentFind::eventFilter(QObject *obj, QEvent *event)
+{
+ if (m_currentWidget && obj == m_currentWidget) {
+ if (event->type() == QEvent::Hide || event->type() == QEvent::Show) {
+ emit changed();
+ }
+ }
+ return QObject::eventFilter(obj, event);
+}
diff --git a/src/plugins/find/currentdocumentfind.h b/src/plugins/find/currentdocumentfind.h
new file mode 100644
index 0000000000..d818dab048
--- /dev/null
+++ b/src/plugins/find/currentdocumentfind.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CURRENTDOCUMENTFIND_H
+#define CURRENTDOCUMENTFIND_H
+
+#include "ifindfilter.h"
+
+#include <coreplugin/icore.h>
+
+#include <QtCore/QPointer>
+#include <QtGui/QWidget>
+
+namespace Find {
+namespace Internal {
+
+class CurrentDocumentFind : public QObject
+{
+ Q_OBJECT
+
+public:
+ CurrentDocumentFind(Core::ICore *core);
+
+ void resetIncrementalSearch();
+ void clearResults();
+ bool supportsReplace() const;
+ QString currentFindString() const;
+ QString completedFindString() const;
+
+ bool isEnabled() const;
+ void highlightAll(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool findIncremental(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool findStep(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool replaceStep(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags);
+ int replaceAll(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags);
+ void defineFindScope();
+ void clearFindScope();
+
+ void removeConnections();
+ bool setFocusToCurrentFindSupport();
+
+ bool eventFilter(QObject *obj, QEvent *event);
+
+signals:
+ void changed();
+
+private slots:
+ void updateCurrentFindFilter(QWidget *old, QWidget *now);
+ void findSupportDestroyed();
+
+private:
+ void removeFindSupportConnections();
+
+ Core::ICore *m_core;
+ QPointer<IFindSupport> m_currentFind;
+ QPointer<QWidget> m_currentWidget;
+};
+
+} // namespace Internal
+} // namespace Find
+
+#endif // CURRENTDOCUMENTFIND_H
diff --git a/src/plugins/find/find.pri b/src/plugins/find/find.pri
new file mode 100644
index 0000000000..b28aec122f
--- /dev/null
+++ b/src/plugins/find/find.pri
@@ -0,0 +1,3 @@
+include(find_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(Find)
diff --git a/src/plugins/find/find.pro b/src/plugins/find/find.pro
new file mode 100644
index 0000000000..77a6193801
--- /dev/null
+++ b/src/plugins/find/find.pro
@@ -0,0 +1,33 @@
+TEMPLATE = lib
+TARGET = Find
+include(../../qworkbenchplugin.pri)
+include(find_dependencies.pri)
+DEFINES += FIND_LIBRARY
+HEADERS += findtoolwindow.h \
+ textfindconstants.h \
+ ifindsupport.h \
+ ifindfilter.h \
+ currentdocumentfind.h \
+ basetextfind.h \
+ find_global.h \
+ findtoolbar.h \
+ findplugin.h \
+ searchresulttreeitemdelegate.h \
+ searchresulttreeitemroles.h \
+ searchresulttreeitems.h \
+ searchresulttreemodel.h \
+ searchresulttreeview.h \
+ searchresultwindow.h
+SOURCES += findtoolwindow.cpp \
+ currentdocumentfind.cpp \
+ basetextfind.cpp \
+ findtoolbar.cpp \
+ findplugin.cpp \
+ searchresulttreeitemdelegate.cpp \
+ searchresulttreeitems.cpp \
+ searchresulttreemodel.cpp \
+ searchresulttreeview.cpp \
+ searchresultwindow.cpp
+FORMS += findwidget.ui \
+ finddialog.ui
+RESOURCES += find.qrc
diff --git a/src/plugins/find/find.qrc b/src/plugins/find/find.qrc
new file mode 100644
index 0000000000..db9017c236
--- /dev/null
+++ b/src/plugins/find/find.qrc
@@ -0,0 +1,13 @@
+<RCC>
+ <qresource prefix="/find" >
+ <file>images/all.png</file>
+ <file>images/casesensitively.png</file>
+ <file>images/empty.png</file>
+ <file>images/expand.png</file>
+ <file>images/next.png</file>
+ <file>images/previous.png</file>
+ <file>images/replace_all.png</file>
+ <file>images/wholewords.png</file>
+ <file>images/wordandcase.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/find/find_dependencies.pri b/src/plugins/find/find_dependencies.pri
new file mode 100644
index 0000000000..a64caedc10
--- /dev/null
+++ b/src/plugins/find/find_dependencies.pri
@@ -0,0 +1 @@
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/find/find_global.h b/src/plugins/find/find_global.h
new file mode 100644
index 0000000000..b9872a0945
--- /dev/null
+++ b/src/plugins/find/find_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef FIND_GLOBAL_H
+#define FIND_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(FIND_LIBRARY)
+# define FIND_EXPORT Q_DECL_EXPORT
+#else
+# define FIND_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // FIND_GLOBAL_H
diff --git a/src/plugins/find/finddialog.ui b/src/plugins/find/finddialog.ui
new file mode 100644
index 0000000000..7240551772
--- /dev/null
+++ b/src/plugins/find/finddialog.ui
@@ -0,0 +1,146 @@
+<ui version="4.0" >
+ <class>Find::Internal::FindDialog</class>
+ <widget class="QDialog" name="Find::Internal::FindDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>426</width>
+ <height>168</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle" >
+ <string>Search for...</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Sc&amp;ope:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy" >
+ <cstring>filterList</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="filterList" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QPushButton" name="searchButton" >
+ <property name="text" >
+ <string>&amp;Search</string>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Search &amp;for:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy" >
+ <cstring>searchTerm</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="searchTerm" />
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="closeButton" >
+ <property name="text" >
+ <string>&amp;Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2" >
+ <widget class="QWidget" native="1" name="configWidget" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>10</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QCheckBox" name="matchCase" >
+ <property name="text" >
+ <string>Match &amp;case</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QCheckBox" name="wholeWords" >
+ <property name="text" >
+ <string>&amp;Whole words only</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>filterList</tabstop>
+ <tabstop>searchTerm</tabstop>
+ <tabstop>searchButton</tabstop>
+ <tabstop>closeButton</tabstop>
+ <tabstop>matchCase</tabstop>
+ <tabstop>wholeWords</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/find/findplugin.cpp b/src/plugins/find/findplugin.cpp
new file mode 100644
index 0000000000..92c52212b6
--- /dev/null
+++ b/src/plugins/find/findplugin.cpp
@@ -0,0 +1,272 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "findplugin.h"
+
+#include "textfindconstants.h"
+#include "currentdocumentfind.h"
+#include "findtoolwindow.h"
+#include "searchresultwindow.h"
+
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/iactioncontainer.h>
+#include <coreplugin/actionmanager/icommand.h>
+#include <coreplugin/coreconstants.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QSettings>
+
+Q_DECLARE_METATYPE(Find::IFindFilter*)
+
+namespace {
+ const int MAX_COMPLETIONS = 50;
+}
+
+using namespace Find;
+using namespace Find::Internal;
+
+FindPlugin::FindPlugin()
+ : m_core(0),
+ m_currentDocumentFind(0),
+ m_findToolBar(0),
+ m_findDialog(0),
+ m_findCompletionModel(new QStringListModel(this)),
+ m_replaceCompletionModel(new QStringListModel(this))
+{
+}
+
+FindPlugin::~FindPlugin()
+{
+ delete m_currentDocumentFind;
+ delete m_findToolBar;
+ delete m_findDialog;
+}
+
+bool FindPlugin::initialize(const QStringList &, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ setupMenu();
+
+ m_currentDocumentFind = new CurrentDocumentFind(m_core);
+
+ m_findToolBar = new FindToolBar(this, m_currentDocumentFind);
+ m_findDialog = new FindToolWindow(this);
+ SearchResultWindow *searchResultWindow = new SearchResultWindow(m_core);
+ addAutoReleasedObject(searchResultWindow);
+ return true;
+}
+
+void FindPlugin::extensionsInitialized()
+{
+ setupFilterMenuItems();
+ readSettings();
+}
+
+void FindPlugin::shutdown()
+{
+ m_findToolBar->setParent(0);
+ m_currentDocumentFind->removeConnections();
+ writeSettings();
+}
+
+void FindPlugin::filterChanged()
+{
+ IFindFilter *changedFilter = qobject_cast<IFindFilter *>(sender());
+ QAction *action = m_filterActions.value(changedFilter);
+ Q_ASSERT(changedFilter);
+ Q_ASSERT(action);
+ if (!changedFilter || !action)
+ return;
+ action->setEnabled(changedFilter->isEnabled());
+}
+
+void FindPlugin::openFindFilter()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ Q_ASSERT(action);
+ if (!action)
+ return;
+ IFindFilter *filter = action->data().value<IFindFilter *>();
+ Q_ASSERT(filter);
+ Q_ASSERT(filter->isEnabled());
+ if (!filter || !filter->isEnabled())
+ return;
+ QString currentFindString = (m_currentDocumentFind->isEnabled() ? m_currentDocumentFind->currentFindString() : "");
+ if (!currentFindString.isEmpty())
+ m_findDialog->setFindText(currentFindString);
+ m_findDialog->open(filter);
+}
+
+
+void FindPlugin::setupMenu()
+{
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ Core::IActionContainer *medit = am->actionContainer(Core::Constants::M_EDIT);
+ Core::IActionContainer *mfind = am->createMenu(Constants::M_FIND);
+ medit->addMenu(mfind, Core::Constants::G_EDIT_FIND);
+ mfind->menu()->setTitle(tr("&Find/Replace"));
+ mfind->appendGroup(Constants::G_FIND_FILTERS);
+ mfind->appendGroup(Constants::G_FIND_FLAGS);
+ mfind->appendGroup(Constants::G_FIND_ACTIONS);
+ QList<int> globalcontext = QList<int>() << Core::Constants::C_GLOBAL_ID;
+ Core::ICommand *cmd;
+ QAction *separator;
+ separator = new QAction(this);
+ separator->setSeparator(true);
+ cmd = am->registerAction(separator, QLatin1String("Find.Sep.Flags"), globalcontext);
+ mfind->addAction(cmd, Constants::G_FIND_FLAGS);
+ separator = new QAction(this);
+ separator->setSeparator(true);
+ cmd = am->registerAction(separator, QLatin1String("Find.Sep.Actions"), globalcontext);
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+}
+
+void FindPlugin::setupFilterMenuItems()
+{
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ QList<IFindFilter*> findInterfaces =
+ ExtensionSystem::PluginManager::instance()->getObjects<IFindFilter>();
+ Core::ICommand *cmd;
+ QList<int> globalcontext = QList<int>() << Core::Constants::C_GLOBAL_ID;
+
+ Core::IActionContainer *mfind = am->actionContainer(Constants::M_FIND);
+ m_filterActions.clear();
+ foreach (IFindFilter *filter, findInterfaces) {
+ QAction *action = new QAction(filter->name(), this);
+ action->setEnabled(filter->isEnabled());
+ action->setData(qVariantFromValue(filter));
+ cmd = am->registerAction(action, QLatin1String("FindFilter.")+filter->name(), globalcontext);
+ cmd->setDefaultKeySequence(filter->defaultShortcut());
+ mfind->addAction(cmd, Constants::G_FIND_FILTERS);
+ m_filterActions.insert(filter, action);
+ connect(action, SIGNAL(triggered(bool)), this, SLOT(openFindFilter()));
+ connect(filter, SIGNAL(changed()), this, SLOT(filterChanged()));
+ }
+ m_findDialog->setFindFilters(findInterfaces);
+}
+
+Core::ICore *FindPlugin::core()
+{
+ return m_core;
+}
+
+QTextDocument::FindFlags FindPlugin::findFlags() const
+{
+ return m_findFlags;
+}
+
+void FindPlugin::setCaseSensitive(bool sensitive)
+{
+ setFindFlag(QTextDocument::FindCaseSensitively, sensitive);
+}
+
+void FindPlugin::setWholeWord(bool wholeOnly)
+{
+ setFindFlag(QTextDocument::FindWholeWords, wholeOnly);
+}
+
+void FindPlugin::setBackward(bool backward)
+{
+ setFindFlag(QTextDocument::FindBackward, backward);
+}
+
+void FindPlugin::setFindFlag(QTextDocument::FindFlag flag, bool enabled)
+{
+ bool hasFlag = hasFindFlag(flag);
+ if ((hasFlag && enabled) || (!hasFlag && !enabled))
+ return;
+ if (enabled)
+ m_findFlags |= flag;
+ else
+ m_findFlags &= ~flag;
+ if (flag != QTextDocument::FindBackward)
+ emit findFlagsChanged();
+}
+
+bool FindPlugin::hasFindFlag(QTextDocument::FindFlag flag)
+{
+ return m_findFlags & flag;
+}
+
+void FindPlugin::writeSettings()
+{
+ QSettings *settings = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings();
+ settings->beginGroup("Find");
+ settings->setValue("Backward", QVariant((m_findFlags & QTextDocument::FindBackward) != 0));
+ settings->setValue("CaseSensitively", QVariant((m_findFlags & QTextDocument::FindCaseSensitively) != 0));
+ settings->setValue("WholeWords", QVariant((m_findFlags & QTextDocument::FindWholeWords) != 0));
+ settings->setValue("FindStrings", m_findCompletions);
+ settings->setValue("ReplaceStrings", m_replaceCompletions);
+ settings->endGroup();
+ m_findDialog->writeSettings();
+}
+
+void FindPlugin::readSettings()
+{
+ QSettings *settings = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings();
+ settings->beginGroup("Find");
+ bool block = blockSignals(true);
+ setBackward(settings->value("Backward", false).toBool());
+ setCaseSensitive(settings->value("CaseSensitively", false).toBool());
+ setWholeWord(settings->value("WholeWords", false).toBool());
+ blockSignals(block);
+ m_findCompletions = settings->value("FindStrings").toStringList();
+ m_replaceCompletions = settings->value("ReplaceStrings").toStringList();
+ m_findCompletionModel->setStringList(m_findCompletions);
+ m_replaceCompletionModel->setStringList(m_replaceCompletions);
+ settings->endGroup();
+ m_findDialog->readSettings();
+ emit findFlagsChanged(); // would have been done in the setXXX methods above
+}
+
+void FindPlugin::updateFindCompletion(const QString &text)
+{
+ updateCompletion(text, m_findCompletions, m_findCompletionModel);
+}
+
+void FindPlugin::updateReplaceCompletion(const QString &text)
+{
+ updateCompletion(text, m_replaceCompletions, m_replaceCompletionModel);
+}
+
+void FindPlugin::updateCompletion(const QString &text, QStringList &completions, QStringListModel *model)
+{
+ if (text.isEmpty())
+ return;
+ completions.removeAll(text);
+ completions.prepend(text);
+ while (completions.size() > MAX_COMPLETIONS)
+ completions.removeLast();
+ model->setStringList(completions);
+}
+
+Q_EXPORT_PLUGIN(FindPlugin)
diff --git a/src/plugins/find/findplugin.h b/src/plugins/find/findplugin.h
new file mode 100644
index 0000000000..98659f0003
--- /dev/null
+++ b/src/plugins/find/findplugin.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FINDPLUGIN_H
+#define FINDPLUGIN_H
+
+#include "ui_findwidget.h"
+#include "ifindfilter.h"
+#include "findtoolbar.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtGui/QAction>
+#include <QtGui/QTextDocument>
+
+namespace Find {
+namespace Internal {
+
+class FindToolWindow;
+
+class FindPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ FindPlugin();
+ virtual ~FindPlugin();
+
+ // IPlugin
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ void shutdown();
+
+ Core::ICore *core();
+ QTextDocument::FindFlags findFlags() const;
+ void updateFindCompletion(const QString &text);
+ void updateReplaceCompletion(const QString &text);
+ QStringListModel *findCompletionModel() { return m_findCompletionModel; }
+ QStringListModel *replaceCompletionModel() { return m_replaceCompletionModel; }
+
+public slots:
+ void setCaseSensitive(bool sensitive);
+ void setWholeWord(bool wholeOnly);
+ void setBackward(bool backward);
+
+signals:
+ void findFlagsChanged();
+
+private slots:
+ void filterChanged();
+ void openFindFilter();
+
+private:
+ void setFindFlag(QTextDocument::FindFlag flag, bool enabled);
+ bool hasFindFlag(QTextDocument::FindFlag flag);
+ void updateCompletion(const QString &text, QStringList &completions, QStringListModel *model);
+ void setupMenu();
+ void setupFilterMenuItems();
+ void writeSettings();
+ void readSettings();
+
+ //variables
+ Core::ICore *m_core;
+ QHash<IFindFilter *, QAction *> m_filterActions;
+
+ CurrentDocumentFind *m_currentDocumentFind;
+ FindToolBar *m_findToolBar;
+ FindToolWindow *m_findDialog;
+ QTextDocument::FindFlags m_findFlags;
+ QStringListModel *m_findCompletionModel;
+ QStringListModel *m_replaceCompletionModel;
+ QStringList m_findCompletions;
+ QStringList m_replaceCompletions;
+};
+
+} // namespace Internal
+} // namespace Find
+
+#endif // FINDPLUGIN_H
diff --git a/src/plugins/find/findtoolbar.cpp b/src/plugins/find/findtoolbar.cpp
new file mode 100644
index 0000000000..a6afa56d04
--- /dev/null
+++ b/src/plugins/find/findtoolbar.cpp
@@ -0,0 +1,482 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "findtoolbar.h"
+#include "findplugin.h"
+#include "textfindconstants.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/findplaceholder.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/iactioncontainer.h>
+#include <coreplugin/actionmanager/icommand.h>
+
+#include <QtCore/QSettings>
+#include <QtGui/QPushButton>
+#include <QtGui/QMenu>
+#include <QtGui/QToolButton>
+#include <QtGui/QLineEdit>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+#include <QtGui/QPainter>
+#include <QtGui/QCompleter>
+#include <QDebug>
+
+Q_DECLARE_METATYPE(QStringList)
+Q_DECLARE_METATYPE(Find::IFindFilter*)
+
+using namespace Find;
+using namespace Find::Internal;
+
+FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumentFind)
+ : m_plugin(plugin),
+ m_currentDocumentFind(currentDocumentFind),
+ m_findCompleter(new QCompleter(this)),
+ m_replaceCompleter(new QCompleter(this)),
+ m_enterFindStringAction(0),
+ m_findNextAction(0),
+ m_findPreviousAction(0),
+ m_replaceNextAction(0),
+ m_widget(new QWidget)
+{
+ //setup ui
+ m_ui.setupUi(m_widget);
+ addWidget(m_widget);
+ setFocusProxy(m_ui.findEdit);
+
+ connect(m_ui.findEdit, SIGNAL(editingFinished()), this, SLOT(invokeResetIncrementalSearch()));
+
+ QWidget *spacerItem = new QWidget;
+ spacerItem->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ addWidget(spacerItem);
+ QToolButton *close = new QToolButton;
+ close->setProperty("type", QLatin1String("dockbutton"));
+ close->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+ connect(close, SIGNAL(clicked()), this, SLOT(hideAndResetFocus()));
+ addWidget(close);
+
+ m_ui.findPreviousButton->setProperty("type", QLatin1String("dockbutton"));
+ m_ui.findNextButton->setProperty("type", QLatin1String("dockbutton"));
+ m_ui.replacePreviousButton->setProperty("type", QLatin1String("dockbutton"));
+ m_ui.replaceNextButton->setProperty("type", QLatin1String("dockbutton"));
+ m_ui.replaceAllButton->setProperty("type", QLatin1String("dockbutton"));
+
+ m_findCompleter->setModel(m_plugin->findCompletionModel());
+ m_replaceCompleter->setModel(m_plugin->replaceCompletionModel());
+ m_ui.findEdit->setCompleter(m_findCompleter);
+ m_findCompleter->popup()->installEventFilter(this);
+ m_ui.replaceEdit->setCompleter(m_replaceCompleter);
+
+ m_ui.findEdit->setSide(qApp->layoutDirection() == Qt::LeftToRight ? Core::Utils::FancyLineEdit::Right : Core::Utils::FancyLineEdit::Left);
+ QMenu *lineEditMenu = new QMenu(m_ui.findEdit);
+ m_ui.findEdit->setMenu(lineEditMenu);
+
+ m_ui.findEdit->installEventFilter(this);
+ m_ui.replaceEdit->installEventFilter(this);
+ m_widget->installEventFilter(this);
+
+ connect(m_ui.findEdit, SIGNAL(textChanged(const QString&)), this, SLOT(invokeFindIncremental()));
+ connect(m_ui.findEdit, SIGNAL(returnPressed()), this, SLOT(invokeFindEnter()));
+ connect(m_ui.replaceEdit, SIGNAL(returnPressed()), this, SLOT(invokeReplaceEnter()));
+
+ QAction *shiftEnterAction = new QAction(m_ui.findEdit);
+ shiftEnterAction->setShortcut(QKeySequence("Shift+Enter"));
+ shiftEnterAction->setShortcutContext(Qt::WidgetShortcut);
+ connect(shiftEnterAction, SIGNAL(triggered()), this, SLOT(invokeFindPrevious()));
+ m_ui.findEdit->addAction(shiftEnterAction);
+ QAction *shiftReturnAction = new QAction(m_ui.findEdit);
+ shiftReturnAction->setShortcut(QKeySequence("Shift+Return"));
+ shiftReturnAction->setShortcutContext(Qt::WidgetShortcut);
+ connect(shiftReturnAction, SIGNAL(triggered()), this, SLOT(invokeFindPrevious()));
+ m_ui.findEdit->addAction(shiftReturnAction);
+
+ QAction *shiftEnterReplaceAction = new QAction(m_ui.replaceEdit);
+ shiftEnterReplaceAction->setShortcut(QKeySequence("Shift+Enter"));
+ shiftEnterReplaceAction->setShortcutContext(Qt::WidgetShortcut);
+ connect(shiftEnterReplaceAction, SIGNAL(triggered()), this, SLOT(invokeReplacePrevious()));
+ m_ui.replaceEdit->addAction(shiftEnterReplaceAction);
+ QAction *shiftReturnReplaceAction = new QAction(m_ui.replaceEdit);
+ shiftReturnReplaceAction->setShortcut(QKeySequence("Shift+Return"));
+ shiftReturnReplaceAction->setShortcutContext(Qt::WidgetShortcut);
+ connect(shiftReturnReplaceAction, SIGNAL(triggered()), this, SLOT(invokeReplacePrevious()));
+ m_ui.replaceEdit->addAction(shiftReturnReplaceAction);
+
+ // need to make sure QStringList is registered as metatype
+ QMetaTypeId<QStringList>::qt_metatype_id();
+
+ //register actions
+ QList<int> globalcontext;
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+
+ Core::ActionManagerInterface *am = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->actionManager();
+ Core::IActionContainer *mfind = am->actionContainer(Constants::M_FIND);
+ Core::ICommand *cmd;
+
+ m_findInDocumentAction = new QAction(tr("Current Document"), this);
+ cmd = am->registerAction(m_findInDocumentAction, Constants::FIND_IN_DOCUMENT, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence::Find);
+ mfind->addAction(cmd, Constants::G_FIND_FILTERS);
+ connect(m_findInDocumentAction, SIGNAL(triggered()), this, SLOT(openFind()));
+
+ if (QApplication::clipboard()->supportsFindBuffer()) {
+ m_enterFindStringAction = new QAction(tr("Enter Find String"), this);
+ cmd = am->registerAction(m_enterFindStringAction, tr("Find.EnterFindString"), globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+E")));
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+ connect(m_enterFindStringAction, SIGNAL(triggered()), this, SLOT(putSelectionToFindClipboard()));
+ connect(QApplication::clipboard(), SIGNAL(findBufferChanged()), this, SLOT(updateFromFindClipboard()));
+ }
+
+ m_findNextAction = new QAction(tr("Find Next"), this);
+ cmd = am->registerAction(m_findNextAction, Constants::FIND_NEXT, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence::FindNext);
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+ connect(m_findNextAction, SIGNAL(triggered()), this, SLOT(invokeFindNext()));
+ m_ui.findNextButton->setDefaultAction(cmd->action());
+
+ m_findPreviousAction = new QAction(tr("Find Previous"), this);
+ cmd = am->registerAction(m_findPreviousAction, Constants::FIND_PREVIOUS, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence::FindPrevious);
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+ connect(m_findPreviousAction, SIGNAL(triggered()), this, SLOT(invokeFindPrevious()));
+ m_ui.findPreviousButton->setDefaultAction(cmd->action());
+
+ m_replaceNextAction = new QAction(tr("Replace && Find Next"), this);
+ cmd = am->registerAction(m_replaceNextAction, Constants::REPLACE_NEXT, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+=")));
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+ connect(m_replaceNextAction, SIGNAL(triggered()), this, SLOT(invokeReplaceNext()));
+ m_ui.replaceNextButton->setDefaultAction(cmd->action());
+
+ m_replacePreviousAction = new QAction(tr("Replace && Find Previous"), this);
+ cmd = am->registerAction(m_replacePreviousAction, Constants::REPLACE_PREVIOUS, globalcontext);
+ // shortcut removed, clashes with Ctrl++ on many keyboard layouts
+ //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+=")));
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+ connect(m_replacePreviousAction, SIGNAL(triggered()), this, SLOT(invokeReplacePrevious()));
+ m_ui.replacePreviousButton->setDefaultAction(cmd->action());
+
+ m_replaceAllAction = new QAction(tr("Replace All"), this);
+ cmd = am->registerAction(m_replaceAllAction, Constants::REPLACE_ALL, globalcontext);
+ mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
+ connect(m_replaceAllAction, SIGNAL(triggered()), this, SLOT(invokeReplaceAll()));
+ m_ui.replaceAllButton->setDefaultAction(cmd->action());
+
+ m_caseSensitiveAction = new QAction(tr("Case Sensitive"), this);
+ m_caseSensitiveAction->setIcon(QIcon(":/find/images/casesensitively.png"));
+ m_caseSensitiveAction->setCheckable(true);
+ m_caseSensitiveAction->setChecked(false);
+ cmd = am->registerAction(m_caseSensitiveAction, Constants::CASE_SENSITIVE, globalcontext);
+ mfind->addAction(cmd, Constants::G_FIND_FLAGS);
+ connect(m_caseSensitiveAction, SIGNAL(triggered(bool)), m_plugin, SLOT(setCaseSensitive(bool)));
+ lineEditMenu->addAction(m_caseSensitiveAction);
+
+ m_wholeWordAction = new QAction(tr("Whole Words Only"), this);
+ m_wholeWordAction->setIcon(QIcon(":/find/images/wholewords.png"));
+ m_wholeWordAction->setCheckable(true);
+ m_wholeWordAction->setChecked(false);
+ cmd = am->registerAction(m_wholeWordAction, Constants::WHOLE_WORDS, globalcontext);
+ mfind->addAction(cmd, Constants::G_FIND_FLAGS);
+ connect(m_wholeWordAction, SIGNAL(triggered(bool)), m_plugin, SLOT(setWholeWord(bool)));
+ lineEditMenu->addAction(m_wholeWordAction);
+
+ connect(m_currentDocumentFind, SIGNAL(changed()), this, SLOT(updateActions()));
+ updateActions();
+ updateIcons();
+ connect(m_plugin, SIGNAL(findFlagsChanged()), this, SLOT(findFlagsChanged()));
+}
+
+FindToolBar::~FindToolBar()
+{
+}
+
+bool FindToolBar::eventFilter(QObject *obj, QEvent *event)
+{
+ if ((obj == m_ui.findEdit || obj == m_findCompleter->popup())
+ && event->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+#ifdef Q_OS_MAC
+ if (ke->key() == Qt::Key_Space && (ke->modifiers() & Qt::MetaModifier)) {
+#else
+ if (ke->key() == Qt::Key_Space && (ke->modifiers() & Qt::ControlModifier)) {
+#endif
+ QString completedText = m_currentDocumentFind->completedFindString();
+ if (!completedText.isEmpty()) {
+ setFindText(completedText);
+ ke->accept();
+ return true;
+ }
+ }
+ } else if (obj == m_widget && event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (ke->key() == Qt::Key_Escape && !ke->modifiers()
+ && !m_findCompleter->popup()->isVisible()
+ && !m_replaceCompleter->popup()->isVisible()) {
+ if (setFocusToCurrentFindSupport()) {
+ event->accept();
+ return true;
+ }
+#ifdef Q_OS_MAC
+ } else if (ke->key() == Qt::Key_Space && (ke->modifiers() & Qt::MetaModifier)) {
+#else
+ } else if (ke->key() == Qt::Key_Space && (ke->modifiers() & Qt::ControlModifier)) {
+#endif
+ event->accept();
+ return true;
+ }
+ } else if (obj == m_widget && event->type() == QEvent::Hide) {
+ invokeClearResults();
+ if (m_currentDocumentFind->isEnabled()) {
+ m_currentDocumentFind->clearFindScope();
+ }
+ }
+ return QToolBar::eventFilter(obj, event);
+}
+
+void FindToolBar::updateActions()
+{
+ bool enabled = m_currentDocumentFind->isEnabled();
+ bool replaceEnabled = enabled && m_currentDocumentFind->supportsReplace();
+ m_findInDocumentAction->setEnabled(enabled);
+ m_findNextAction->setEnabled(enabled);
+ m_findPreviousAction->setEnabled(enabled);
+ m_replaceNextAction->setEnabled(replaceEnabled);
+ m_replacePreviousAction->setEnabled(replaceEnabled);
+ m_replaceAllAction->setEnabled(replaceEnabled);
+ m_caseSensitiveAction->setEnabled(enabled);
+ m_wholeWordAction->setEnabled(enabled);
+ if (QApplication::clipboard()->supportsFindBuffer())
+ m_enterFindStringAction->setEnabled(enabled);
+ bool replaceFocus = m_ui.replaceEdit->hasFocus();
+ m_ui.findEdit->setEnabled(enabled);
+ m_ui.findLabel->setEnabled(enabled);
+ m_ui.replaceEdit->setEnabled(replaceEnabled);
+ m_ui.replaceLabel->setEnabled(replaceEnabled);
+ if (!replaceEnabled && enabled && replaceFocus)
+ m_ui.findEdit->setFocus();
+}
+
+void FindToolBar::invokeFindEnter()
+{
+ if (m_currentDocumentFind->isEnabled()) {
+ invokeFindNext();
+ }
+}
+
+void FindToolBar::invokeReplaceEnter()
+{
+ if (m_currentDocumentFind->isEnabled() && m_currentDocumentFind->supportsReplace()) {
+ invokeReplaceNext();
+ }
+}
+
+void FindToolBar::invokeClearResults()
+{
+ if (m_currentDocumentFind->isEnabled()) {
+ m_currentDocumentFind->clearResults();
+ }
+}
+
+
+void FindToolBar::invokeFindNext()
+{
+ m_plugin->setBackward(false);
+ invokeFindStep();
+}
+
+void FindToolBar::invokeFindPrevious()
+{
+ m_plugin->setBackward(true);
+ invokeFindStep();
+}
+
+QString FindToolBar::getFindText()
+{
+ return m_ui.findEdit->text();
+}
+
+QString FindToolBar::getReplaceText()
+{
+ return m_ui.replaceEdit->text();
+}
+
+void FindToolBar::setFindText(const QString &text)
+{
+ disconnect(m_ui.findEdit, SIGNAL(textChanged(const QString&)), this, SLOT(invokeFindIncremental()));
+ m_ui.findEdit->setText(text);
+ connect(m_ui.findEdit, SIGNAL(textChanged(const QString&)), this, SLOT(invokeFindIncremental()));
+}
+
+void FindToolBar::selectFindText()
+{
+ m_ui.findEdit->selectAll();
+}
+
+void FindToolBar::invokeFindStep()
+{
+ if (m_currentDocumentFind->isEnabled()) {
+ m_plugin->updateFindCompletion(getFindText());
+ m_currentDocumentFind->findStep(getFindText(), m_plugin->findFlags());
+ }
+}
+
+void FindToolBar::invokeFindIncremental()
+{
+ if (m_currentDocumentFind->isEnabled()) {
+ QString text = getFindText();
+ m_currentDocumentFind->findIncremental(text, m_plugin->findFlags());
+ if (text.isEmpty())
+ m_currentDocumentFind->clearResults();
+ }
+}
+
+void FindToolBar::invokeReplaceNext()
+{
+ m_plugin->setBackward(false);
+ invokeReplaceStep();
+}
+
+void FindToolBar::invokeReplacePrevious()
+{
+ m_plugin->setBackward(true);
+ invokeReplaceStep();
+}
+
+void FindToolBar::invokeReplaceStep()
+{
+ if (m_currentDocumentFind->isEnabled() && m_currentDocumentFind->supportsReplace()) {
+ m_plugin->updateFindCompletion(getFindText());
+ m_plugin->updateReplaceCompletion(getReplaceText());
+ m_currentDocumentFind->replaceStep(getFindText(), getReplaceText(), m_plugin->findFlags());
+ }
+}
+
+void FindToolBar::invokeReplaceAll()
+{
+ m_plugin->updateFindCompletion(getFindText());
+ m_plugin->updateReplaceCompletion(getReplaceText());
+ if (m_currentDocumentFind->isEnabled() && m_currentDocumentFind->supportsReplace()) {
+ m_currentDocumentFind->replaceAll(getFindText(), getReplaceText(), m_plugin->findFlags());
+ }
+}
+
+void FindToolBar::invokeResetIncrementalSearch()
+{
+ if (m_currentDocumentFind->isEnabled())
+ m_currentDocumentFind->resetIncrementalSearch();
+}
+
+
+void FindToolBar::putSelectionToFindClipboard()
+{
+ const QString text = m_currentDocumentFind->currentFindString();
+ QApplication::clipboard()->setText(text, QClipboard::FindBuffer);
+ setFindText(text);
+}
+
+
+void FindToolBar::updateFromFindClipboard()
+{
+ if (QApplication::clipboard()->supportsFindBuffer()) {
+ const bool blocks = m_ui.findEdit->blockSignals(true);
+ setFindText(QApplication::clipboard()->text(QClipboard::FindBuffer));
+ m_ui.findEdit->blockSignals(blocks);
+ }
+}
+
+void FindToolBar::findFlagsChanged()
+{
+ updateIcons();
+ updateFlagMenus();
+ invokeClearResults();
+}
+
+void FindToolBar::updateIcons()
+{
+ bool casesensitive = m_plugin->findFlags() & QTextDocument::FindCaseSensitively;
+ bool wholewords = m_plugin->findFlags() & QTextDocument::FindWholeWords;
+
+ if (casesensitive && wholewords) {
+ QPixmap image = QPixmap(":/find/images/wordandcase.png");
+ m_ui.findEdit->setPixmap(image);
+ } else if (casesensitive) {
+ QPixmap image = QPixmap(":/find/images/casesensitively.png");
+ m_ui.findEdit->setPixmap(image);
+ } else if (wholewords) {
+ QPixmap image = QPixmap(":/find/images/wholewords.png");
+ m_ui.findEdit->setPixmap(image);
+ } else {
+ m_ui.findEdit->setPixmap(QPixmap(Core::Constants::ICON_MAGNIFIER));
+ }
+}
+
+void FindToolBar::updateFlagMenus()
+{
+ bool wholeOnly = ((m_plugin->findFlags() & QTextDocument::FindWholeWords));
+ bool sensitive = ((m_plugin->findFlags() & QTextDocument::FindCaseSensitively));
+ if (m_wholeWordAction->isChecked() != wholeOnly)
+ m_wholeWordAction->setChecked(wholeOnly);
+ if (m_caseSensitiveAction->isChecked() != sensitive)
+ m_caseSensitiveAction->setChecked(sensitive);
+}
+
+bool FindToolBar::setFocusToCurrentFindSupport()
+{
+ return m_currentDocumentFind->setFocusToCurrentFindSupport();
+}
+
+void FindToolBar::hideAndResetFocus()
+{
+ m_currentDocumentFind->setFocusToCurrentFindSupport();
+ hide();
+}
+
+void FindToolBar::openFind()
+{
+ if (!m_currentDocumentFind->isEnabled())
+ return;
+ Core::FindToolBarPlaceHolder *holder = Core::FindToolBarPlaceHolder::getCurrent();
+ QLayout *findContainerLayout = holder ? holder->layout() : 0;
+
+ if (findContainerLayout) {
+ findContainerLayout->addWidget(this);
+ holder->setVisible(true);
+ setVisible(true);
+ setFocus();
+ }
+ QString text = m_currentDocumentFind->currentFindString();
+ if (!text.isEmpty())
+ setFindText(text);
+ m_currentDocumentFind->defineFindScope();
+ m_currentDocumentFind->highlightAll(getFindText(), m_plugin->findFlags());
+ selectFindText();
+}
diff --git a/src/plugins/find/findtoolbar.h b/src/plugins/find/findtoolbar.h
new file mode 100644
index 0000000000..cb85470f41
--- /dev/null
+++ b/src/plugins/find/findtoolbar.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FINDTOOLBAR_H
+#define FINDTOOLBAR_H
+
+#include "ui_findwidget.h"
+#include "ifindfilter.h"
+#include "currentdocumentfind.h"
+
+#include <QtGui/QStringListModel>
+#include <QtGui/QWidget>
+#include <QtGui/QToolBar>
+#include <QtGui/QLabel>
+
+namespace Find {
+namespace Internal {
+
+class FindPlugin;
+
+class FindToolBar : public QToolBar
+{
+ Q_OBJECT
+
+public:
+ FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumentFind);
+ ~FindToolBar();
+
+ void invokeClearResults();
+
+private slots:
+ void invokeFindNext();
+ void invokeFindPrevious();
+ void invokeFindStep();
+ void invokeReplaceNext();
+ void invokeReplacePrevious();
+ void invokeReplaceStep();
+ void invokeReplaceAll();
+ void invokeResetIncrementalSearch();
+
+ void invokeFindIncremental();
+ void invokeFindEnter();
+ void invokeReplaceEnter();
+ void putSelectionToFindClipboard();
+ void updateFromFindClipboard();
+
+ void hideAndResetFocus();
+ void openFind();
+ void updateActions();
+ void findFlagsChanged();
+
+private:
+ bool setFocusToCurrentFindSupport();
+
+ bool eventFilter(QObject *obj, QEvent *event);
+ void setFindText(const QString &text);
+ QString getFindText();
+ QString getReplaceText();
+ void selectFindText();
+ void updateIcons();
+ void updateFlagMenus();
+
+ FindPlugin *m_plugin;
+ CurrentDocumentFind *m_currentDocumentFind;
+ Ui::FindWidget m_ui;
+ QCompleter *m_findCompleter;
+ QCompleter *m_replaceCompleter;
+ QAction *m_findInDocumentAction;
+ QAction *m_enterFindStringAction;
+ QAction *m_findNextAction;
+ QAction *m_findPreviousAction;
+ QAction *m_replaceNextAction;
+ QAction *m_replacePreviousAction;
+ QAction *m_replaceAllAction;
+ QAction *m_caseSensitiveAction;
+ QAction *m_wholeWordAction;
+ QWidget *m_widget;
+};
+
+} // namespace Internal
+} // namespace Find
+
+#endif // FINDTOOLBAR_H
diff --git a/src/plugins/find/findtoolwindow.cpp b/src/plugins/find/findtoolwindow.cpp
new file mode 100644
index 0000000000..40c476dcff
--- /dev/null
+++ b/src/plugins/find/findtoolwindow.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "findtoolwindow.h"
+#include "findplugin.h"
+
+#include <coreplugin/icore.h>
+
+#include <QtGui/QMainWindow>
+
+using namespace Find;
+using namespace Find::Internal;
+
+FindToolWindow::FindToolWindow(FindPlugin *plugin)
+ : QDialog(plugin->core()->mainWindow()),
+ m_plugin(plugin),
+ m_findCompleter(new QCompleter(this))
+{
+ m_ui.setupUi(this);
+ connect(m_ui.closeButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_ui.searchButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_ui.matchCase, SIGNAL(toggled(bool)), m_plugin, SLOT(setCaseSensitive(bool)));
+ connect(m_ui.wholeWords, SIGNAL(toggled(bool)), m_plugin, SLOT(setWholeWord(bool)));
+ connect(m_ui.filterList, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentFilter(int)));
+ connect(this, SIGNAL(accepted()), this, SLOT(search()));
+ m_findCompleter->setModel(m_plugin->findCompletionModel());
+ m_ui.searchTerm->setCompleter(m_findCompleter);
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ m_ui.configWidget->setLayout(layout);
+}
+
+FindToolWindow::~FindToolWindow()
+{
+ qDeleteAll(m_configWidgets);
+}
+
+void FindToolWindow::setFindFilters(const QList<IFindFilter *> &filters)
+{
+ qDeleteAll(m_configWidgets);
+ m_configWidgets.clear();
+ m_filters = filters;
+ m_ui.filterList->clear();
+ QStringList names;
+ foreach (IFindFilter *filter, filters) {
+ names << filter->name();
+ m_configWidgets.append(filter->createConfigWidget());
+ }
+ m_ui.filterList->addItems(names);
+}
+
+void FindToolWindow::setFindText(const QString &text)
+{
+ m_ui.searchTerm->setText(text);
+}
+
+void FindToolWindow::open(IFindFilter *filter)
+{
+ int index = m_filters.indexOf(filter);
+ if (index >= 0) {
+ m_ui.filterList->setCurrentIndex(index);
+ }
+ m_ui.matchCase->setChecked(m_plugin->findFlags() & QTextDocument::FindCaseSensitively);
+ m_ui.wholeWords->setChecked(m_plugin->findFlags() & QTextDocument::FindWholeWords);
+ m_ui.searchTerm->setFocus();
+ m_ui.searchTerm->selectAll();
+ exec();
+}
+
+void FindToolWindow::setCurrentFilter(int index)
+{
+ for (int i = 0; i < m_configWidgets.size(); ++i) {
+ QWidget *configWidget = m_configWidgets.at(i);
+ if (!configWidget)
+ continue;
+ if (i == index)
+ m_ui.configWidget->layout()->addWidget(configWidget);
+ else
+ configWidget->setParent(0);
+ }
+}
+
+void FindToolWindow::search()
+{
+ m_plugin->updateFindCompletion(m_ui.searchTerm->text());
+ int index = m_ui.filterList->currentIndex();
+ QString term = m_ui.searchTerm->text();
+ if (term.isEmpty() || index < 0)
+ return;
+ IFindFilter *filter = m_filters.at(index);
+ filter->findAll(term, m_plugin->findFlags());
+}
+
+void FindToolWindow::writeSettings()
+{
+ QSettings *settings = m_plugin->core()->settings();
+ settings->beginGroup("Find");
+ foreach (IFindFilter *filter, m_filters)
+ filter->writeSettings(settings);
+ settings->endGroup();
+}
+
+void FindToolWindow::readSettings()
+{
+ QSettings *settings = m_plugin->core()->settings();
+ settings->beginGroup("Find");
+ foreach (IFindFilter *filter, m_filters)
+ filter->readSettings(settings);
+ settings->endGroup();
+}
diff --git a/src/plugins/find/findtoolwindow.h b/src/plugins/find/findtoolwindow.h
new file mode 100644
index 0000000000..558b8198ab
--- /dev/null
+++ b/src/plugins/find/findtoolwindow.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FINDTOOLWINDOW_H
+#define FINDTOOLWINDOW_H
+
+#include "ui_finddialog.h"
+#include "ifindfilter.h"
+
+#include <QtCore/QList>
+#include <QtGui/QCompleter>
+#include <QtGui/QWidget>
+
+namespace Find {
+namespace Internal {
+
+class FindPlugin;
+
+class FindToolWindow : public QDialog
+{
+ Q_OBJECT
+
+public:
+ FindToolWindow(FindPlugin *plugin);
+ ~FindToolWindow();
+
+ void setFindFilters(const QList<IFindFilter *> &filters);
+
+ void setFindText(const QString &text);
+ void open(IFindFilter *filter);
+ void readSettings();
+ void writeSettings();
+
+private slots:
+ void search();
+ void setCurrentFilter(int index);
+
+private:
+ Ui::FindDialog m_ui;
+ FindPlugin *m_plugin;
+ QList<IFindFilter *> m_filters;
+ QCompleter *m_findCompleter;
+ QList<QWidget *> m_configWidgets;
+};
+
+} // namespace Internal
+} // namespace Find
+
+#endif // FINDTOOLWINDOW_H
diff --git a/src/plugins/find/findwidget.ui b/src/plugins/find/findwidget.ui
new file mode 100644
index 0000000000..c85f336299
--- /dev/null
+++ b/src/plugins/find/findwidget.ui
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Find::Internal::FindWidget</class>
+ <widget class="QWidget" name="Find::Internal::FindWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>71</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>600</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Find</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>15</number>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="findLabel">
+ <property name="text">
+ <string>Find:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Core::Utils::FancyLineEdit" name="findEdit">
+ <property name="minimumSize">
+ <size>
+ <width>160</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>160</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="findPreviousButton">
+ <property name="arrowType">
+ <enum>Qt::LeftArrow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="findNextButton">
+ <property name="font">
+ <font/>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::RightArrow</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="replaceLabel">
+ <property name="text">
+ <string>Replace with:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="replaceEdit">
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="replacePreviousButton">
+ <property name="arrowType">
+ <enum>Qt::LeftArrow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="replaceNextButton">
+ <property name="font">
+ <font/>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::RightArrow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="replaceAllButton">
+ <property name="font">
+ <font/>
+ </property>
+ <property name="text">
+ <string>All</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::FancyLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header location="global">utils/fancylineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/find/ifindfilter.h b/src/plugins/find/ifindfilter.h
new file mode 100644
index 0000000000..356c293b28
--- /dev/null
+++ b/src/plugins/find/ifindfilter.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IFINDFILTER_H
+#define IFINDFILTER_H
+
+#include "ifindsupport.h"
+#include <QtCore/QSettings>
+#include <QtGui/QIcon>
+#include <QtGui/QKeySequence>
+#include <QtGui/QWidget>
+
+namespace Find {
+
+class FIND_EXPORT IFindFilter : public QObject
+{
+ Q_OBJECT
+public:
+
+ virtual ~IFindFilter() {}
+
+ virtual QString name() const = 0;
+ virtual bool isEnabled() const = 0;
+ virtual QKeySequence defaultShortcut() const = 0;
+ virtual void findAll(const QString &txt, QTextDocument::FindFlags findFlags) = 0;
+
+ virtual QWidget *createConfigWidget() { return 0; }
+ virtual void writeSettings(QSettings *settings) { Q_UNUSED(settings); }
+ virtual void readSettings(QSettings *settings) { Q_UNUSED(settings); }
+
+signals:
+ void changed();
+};
+
+} // namespace Find
+
+#endif // IFINDFILTER_H
diff --git a/src/plugins/find/ifindsupport.h b/src/plugins/find/ifindsupport.h
new file mode 100644
index 0000000000..14786ed922
--- /dev/null
+++ b/src/plugins/find/ifindsupport.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IFINDSUPPORT_H
+#define IFINDSUPPORT_H
+
+#include "find_global.h"
+#include <QtGui/QTextDocument>
+
+namespace Find {
+
+class FIND_EXPORT IFindSupport : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ IFindSupport() : QObject(0) {}
+ virtual ~IFindSupport() {}
+
+ virtual bool supportsReplace() const = 0;
+ virtual void resetIncrementalSearch() = 0;
+ virtual void clearResults() = 0;
+ virtual QString currentFindString() const = 0;
+ virtual QString completedFindString() const = 0;
+
+ virtual void highlightAll(const QString &txt, QTextDocument::FindFlags findFlags);
+ virtual bool findIncremental(const QString &txt, QTextDocument::FindFlags findFlags) = 0;
+ virtual bool findStep(const QString &txt, QTextDocument::FindFlags findFlags) = 0;
+ virtual bool replaceStep(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags) = 0;
+ virtual int replaceAll(const QString &before, const QString &after,
+ QTextDocument::FindFlags findFlags) = 0;
+
+ virtual void defineFindScope(){}
+ virtual void clearFindScope(){}
+
+signals:
+ void changed();
+};
+
+
+inline void IFindSupport::highlightAll(const QString &, QTextDocument::FindFlags){}
+
+} // namespace Find
+
+#endif // IFINDSUPPORT_H
diff --git a/src/plugins/find/images/all.png b/src/plugins/find/images/all.png
new file mode 100644
index 0000000000..f5c1c1f767
--- /dev/null
+++ b/src/plugins/find/images/all.png
Binary files differ
diff --git a/src/plugins/find/images/casesensitively.png b/src/plugins/find/images/casesensitively.png
new file mode 100644
index 0000000000..93038c0523
--- /dev/null
+++ b/src/plugins/find/images/casesensitively.png
Binary files differ
diff --git a/src/plugins/find/images/empty.png b/src/plugins/find/images/empty.png
new file mode 100644
index 0000000000..f02154247c
--- /dev/null
+++ b/src/plugins/find/images/empty.png
Binary files differ
diff --git a/src/plugins/find/images/expand.png b/src/plugins/find/images/expand.png
new file mode 100644
index 0000000000..48fcb9b703
--- /dev/null
+++ b/src/plugins/find/images/expand.png
Binary files differ
diff --git a/src/plugins/find/images/next.png b/src/plugins/find/images/next.png
new file mode 100644
index 0000000000..1844929119
--- /dev/null
+++ b/src/plugins/find/images/next.png
Binary files differ
diff --git a/src/plugins/find/images/previous.png b/src/plugins/find/images/previous.png
new file mode 100644
index 0000000000..4fe50af9a8
--- /dev/null
+++ b/src/plugins/find/images/previous.png
Binary files differ
diff --git a/src/plugins/find/images/replace_all.png b/src/plugins/find/images/replace_all.png
new file mode 100644
index 0000000000..d2298a8aad
--- /dev/null
+++ b/src/plugins/find/images/replace_all.png
Binary files differ
diff --git a/src/plugins/find/images/wholewords.png b/src/plugins/find/images/wholewords.png
new file mode 100644
index 0000000000..0187023ada
--- /dev/null
+++ b/src/plugins/find/images/wholewords.png
Binary files differ
diff --git a/src/plugins/find/images/wordandcase.png b/src/plugins/find/images/wordandcase.png
new file mode 100644
index 0000000000..3a34cbea83
--- /dev/null
+++ b/src/plugins/find/images/wordandcase.png
Binary files differ
diff --git a/src/plugins/find/searchresulttreeitemdelegate.cpp b/src/plugins/find/searchresulttreeitemdelegate.cpp
new file mode 100644
index 0000000000..a69d4357fe
--- /dev/null
+++ b/src/plugins/find/searchresulttreeitemdelegate.cpp
@@ -0,0 +1,121 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "searchresulttreeitemdelegate.h"
+#include "searchresulttreeitemroles.h"
+
+#include <math.h>
+
+#include <QModelIndex>
+#include <QTextDocument>
+#include <QPainter>
+#include <QAbstractTextDocumentLayout>
+#include <QApplication>
+
+using namespace Find::Internal;
+
+SearchResultTreeItemDelegate::SearchResultTreeItemDelegate(QObject *parent)
+: QItemDelegate(parent)
+{
+}
+
+void SearchResultTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ if (index.model()->data(index, ItemDataRoles::TypeRole).toString().compare("file") == 0)
+ {
+ QItemDelegate::paint(painter, option, index);
+ }
+ else
+ {
+ painter->save();
+
+ QStyleOptionViewItemV3 opt = setOptions(index, option);
+ painter->setFont(opt.font);
+
+ QItemDelegate::drawBackground(painter, opt, index);
+
+ int lineNumberAreaWidth = drawLineNumber(painter, opt, index);
+
+ QRect resultRowRect(opt.rect.adjusted(lineNumberAreaWidth, 0, 0, 0));
+ QString displayString = index.model()->data(index, Qt::DisplayRole).toString();
+ drawMarker(painter, index, displayString, resultRowRect);
+
+ // Draw the text and focus/selection
+ QItemDelegate::drawDisplay(painter, opt, resultRowRect, displayString);
+ QItemDelegate::drawFocus(painter, opt, opt.rect);
+
+ painter->restore();
+ }
+}
+
+int SearchResultTreeItemDelegate::drawLineNumber(QPainter *painter, const QStyleOptionViewItemV3 &option,
+ const QModelIndex &index) const
+{
+ static const int lineNumberAreaHorizontalPadding = 4;
+ const bool isSelected = option.state & QStyle::State_Selected;
+ int lineNumber = index.model()->data(index, ItemDataRoles::ResultLineNumberRole).toInt();
+ int lineNumberDigits = (int)floor(log10((double)lineNumber)) + 1;
+ int minimumLineNumberDigits = qMax((int)m_minimumLineNumberDigits, lineNumberDigits);
+ int fontWidth = painter->fontMetrics().width(QString(minimumLineNumberDigits, '0'));
+ int lineNumberAreaWidth = lineNumberAreaHorizontalPadding + fontWidth + lineNumberAreaHorizontalPadding;
+ QRect lineNumberAreaRect(option.rect);
+ lineNumberAreaRect.setWidth(lineNumberAreaWidth);
+
+ QPalette::ColorGroup cg = QPalette::Normal;
+ if (!(option.state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+ else if (!(option.state & QStyle::State_Enabled))
+ cg = QPalette::Disabled;
+
+ painter->fillRect(lineNumberAreaRect, QBrush(isSelected?
+ option.palette.brush(cg, QPalette::Highlight):QBrush(qRgb(230, 230, 230))));
+ painter->setPen(isSelected?
+ option.palette.color(cg, QPalette::HighlightedText):Qt::darkGray);
+ painter->drawText(lineNumberAreaRect.adjusted(0, 0, -lineNumberAreaHorizontalPadding, 0),
+ Qt::AlignRight, QString::number(lineNumber));
+
+ return lineNumberAreaWidth;
+}
+
+void SearchResultTreeItemDelegate::drawMarker(QPainter *painter, const QModelIndex &index, const QString text,
+ const QRect &rect) const
+{
+ const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
+ int searchTermStart = index.model()->data(index, ItemDataRoles::SearchTermStartRole).toInt();
+ int searchTermStartPixels = painter->fontMetrics().width(text.left(searchTermStart));
+ int searchTermLength = index.model()->data(index, ItemDataRoles::SearchTermLengthRole).toInt();
+ int searchTermLengthPixels = painter->fontMetrics().width(text.mid(searchTermStart, searchTermLength));
+ QRect resultHighlightRect(rect);
+ resultHighlightRect.setLeft(resultHighlightRect.left() + searchTermStartPixels + textMargin - 1); // -1: Cosmetics
+ resultHighlightRect.setRight(resultHighlightRect.left() + searchTermLengthPixels + 1); // +1: Cosmetics
+ painter->fillRect(resultHighlightRect, QBrush(qRgb(255, 240, 120)));
+}
diff --git a/src/plugins/find/searchresulttreeitemdelegate.h b/src/plugins/find/searchresulttreeitemdelegate.h
new file mode 100644
index 0000000000..ede85741df
--- /dev/null
+++ b/src/plugins/find/searchresulttreeitemdelegate.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SEARCHRESULTTREEITEMDELEGATE_H
+#define SEARCHRESULTTREEITEMDELEGATE_H
+
+#include <QtGui/QItemDelegate>
+
+namespace Find {
+namespace Internal {
+
+class SearchResultTreeItemDelegate: public QItemDelegate
+{
+public:
+ SearchResultTreeItemDelegate(QObject *parent = 0);
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+private:
+ int drawLineNumber(QPainter *painter, const QStyleOptionViewItemV3 &option, const QModelIndex &index) const;
+ void drawMarker(QPainter *painter, const QModelIndex &index, const QString text, const QRect &rect) const;
+
+ static const int m_minimumLineNumberDigits = 6;
+};
+
+} //Internal
+} //Find
+
+#endif
diff --git a/src/plugins/find/searchresulttreeitemroles.h b/src/plugins/find/searchresulttreeitemroles.h
new file mode 100644
index 0000000000..2b838a44ec
--- /dev/null
+++ b/src/plugins/find/searchresulttreeitemroles.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SEARCHRESULTTREEITEMROLES_H
+#define SEARCHRESULTTREEITEMROLES_H
+
+namespace Find {
+namespace Internal {
+namespace ItemDataRoles {
+
+enum roles
+{
+ TypeRole = Qt::UserRole,
+ FileNameRole,
+ ResultLinesCountRole,
+ ResultIndexRole,
+ ResultLineRole,
+ ResultLineNumberRole,
+ SearchTermStartRole,
+ SearchTermLengthRole,
+ RowOfItem // The ?-th child of its parent is this this item
+};
+
+} //Internal
+} //Find
+} //itemDataRoles
+
+#endif
diff --git a/src/plugins/find/searchresulttreeitems.cpp b/src/plugins/find/searchresulttreeitems.cpp
new file mode 100644
index 0000000000..4620016559
--- /dev/null
+++ b/src/plugins/find/searchresulttreeitems.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "searchresulttreeitems.h"
+
+using namespace Find::Internal;
+
+SearchResultTreeItem::SearchResultTreeItem(SearchResultTreeItem::itemType type, const SearchResultTreeItem *parent)
+: m_type(type)
+, m_parent(parent)
+{
+}
+
+SearchResultTreeItem::~SearchResultTreeItem()
+{
+ clearChildren();
+}
+
+void SearchResultTreeItem::clearChildren(void)
+{
+ qDeleteAll(m_children);
+ m_children.clear();
+}
+
+SearchResultTreeItem::itemType SearchResultTreeItem::getItemType(void) const
+{
+ return m_type;
+}
+
+int SearchResultTreeItem::getChildrenCount(void) const
+{
+ return m_children.count();
+}
+
+int SearchResultTreeItem::getRowOfItem(void) const
+{
+ return (m_parent?m_parent->m_children.indexOf(const_cast<SearchResultTreeItem*>(this)):0);
+}
+
+const SearchResultTreeItem* SearchResultTreeItem::getChild(int index) const
+{
+ return m_children.at(index);
+}
+
+const SearchResultTreeItem *SearchResultTreeItem::getParent(void) const
+{
+ return m_parent;
+}
+
+void SearchResultTreeItem::appendChild(SearchResultTreeItem *child)
+{
+ m_children.append(child);
+}
+
+SearchResultTextRow::SearchResultTextRow(int index, int lineNumber,
+ const QString &rowText, int searchTermStart, int searchTermLength, const SearchResultTreeItem *parent)
+: SearchResultTreeItem(resultRow, parent),
+ m_index(index),
+ m_lineNumber(lineNumber),
+ m_rowText(rowText),
+ m_searchTermStart(searchTermStart),
+ m_searchTermLength(searchTermLength)
+{
+}
+
+int SearchResultTextRow::index() const
+{
+ return m_index;
+}
+
+QString SearchResultTextRow::rowText() const
+{
+ return m_rowText;
+}
+
+int SearchResultTextRow::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+int SearchResultTextRow::searchTermStart() const
+{
+ return m_searchTermStart;
+}
+
+int SearchResultTextRow::searchTermLength() const
+{
+ return m_searchTermLength;
+}
+
+SearchResultFile::SearchResultFile(const QString &fileName, const SearchResultTreeItem *parent)
+: SearchResultTreeItem(resultFile, parent)
+, m_fileName(fileName)
+{
+}
+
+QString SearchResultFile::getFileName(void) const
+{
+ return m_fileName;
+}
+
+void SearchResultFile::appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart,
+ int searchTermLength)
+{
+ SearchResultTreeItem *child = new SearchResultTextRow(index, lineNumber, rowText, searchTermStart, searchTermLength, this);
+ appendChild(child);
+}
diff --git a/src/plugins/find/searchresulttreeitems.h b/src/plugins/find/searchresulttreeitems.h
new file mode 100644
index 0000000000..62be73942b
--- /dev/null
+++ b/src/plugins/find/searchresulttreeitems.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SEARCHRESULTTREEITEMS_H
+#define SEARCHRESULTTREEITEMS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+namespace Find {
+namespace Internal {
+
+class SearchResultTreeItem;
+
+class SearchResultTreeItem
+{
+public:
+ enum itemType
+ {
+ root,
+ resultRow,
+ resultFile
+ };
+
+ SearchResultTreeItem(itemType type = root, const SearchResultTreeItem *parent = NULL);
+ virtual ~SearchResultTreeItem();
+
+ itemType getItemType(void) const;
+ const SearchResultTreeItem *getParent(void) const;
+ const SearchResultTreeItem *getChild(int index) const;
+ void appendChild(SearchResultTreeItem *child);
+ int getChildrenCount(void) const;
+ int getRowOfItem(void) const;
+ void clearChildren(void);
+
+private:
+ itemType m_type;
+ const SearchResultTreeItem *m_parent;
+ QList<SearchResultTreeItem *> m_children;
+};
+
+class SearchResultTextRow: public SearchResultTreeItem
+{
+public:
+ SearchResultTextRow(int index, int lineNumber, const QString &rowText, int searchTermStart,
+ int searchTermLength, const SearchResultTreeItem *parent);
+ int index() const;
+ QString rowText() const;
+ int lineNumber() const;
+ int searchTermStart() const;
+ int searchTermLength() const;
+
+private:
+ int m_index;
+ int m_lineNumber;
+ QString m_rowText;
+ int m_searchTermStart;
+ int m_searchTermLength;
+};
+
+class SearchResultFile: public SearchResultTreeItem
+{
+public:
+ SearchResultFile(const QString &fileName, const SearchResultTreeItem *parent);
+ QString getFileName(void) const;
+ void appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart,
+ int searchTermLength);
+
+private:
+ QString m_fileName;
+};
+
+} //Internal
+} //Find
+
+#endif
diff --git a/src/plugins/find/searchresulttreemodel.cpp b/src/plugins/find/searchresulttreemodel.cpp
new file mode 100644
index 0000000000..17a81e852d
--- /dev/null
+++ b/src/plugins/find/searchresulttreemodel.cpp
@@ -0,0 +1,260 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "searchresulttreemodel.h"
+#include "searchresulttreeitems.h"
+#include "searchresulttreeitemroles.h"
+#include <QtGui/QFont>
+#include <QtGui/QColor>
+
+using namespace Find::Internal;
+
+SearchResultTreeModel::SearchResultTreeModel(QObject *parent)
+: QAbstractItemModel(parent)
+, m_lastAppendedResultFile(NULL)
+{
+ m_rootItem = new SearchResultTreeItem();
+}
+
+SearchResultTreeModel::~SearchResultTreeModel()
+{
+ delete m_rootItem;
+}
+
+QModelIndex SearchResultTreeModel::index(int row, int column,
+ const QModelIndex &parent) const
+{
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ const SearchResultTreeItem *parentItem;
+
+ if (!parent.isValid())
+ parentItem = m_rootItem;
+ else
+ parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer());
+
+ const SearchResultTreeItem *childItem = parentItem->getChild(row);
+ if (childItem)
+ return createIndex(row, column, (void *)childItem);
+ else
+ return QModelIndex();
+}
+
+QModelIndex SearchResultTreeModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ const SearchResultTreeItem *childItem = static_cast<const SearchResultTreeItem*>(index.internalPointer());
+ const SearchResultTreeItem *parentItem = childItem->getParent();
+
+ if (parentItem == m_rootItem)
+ return QModelIndex();
+
+ return createIndex(parentItem->getRowOfItem(), 0, (void *)parentItem);
+}
+
+int SearchResultTreeModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ const SearchResultTreeItem *parentItem;
+
+ if (!parent.isValid())
+ parentItem = m_rootItem;
+ else
+ parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer());
+
+ return parentItem->getChildrenCount();
+}
+
+int SearchResultTreeModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 1;
+}
+
+QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer());
+
+ QVariant result;
+
+ if (item->getItemType() == SearchResultTreeItem::resultRow)
+ {
+ const SearchResultTextRow *row = static_cast<const SearchResultTextRow *>(item);
+ result = data(row, role);
+ }
+ else if (item->getItemType() == SearchResultTreeItem::resultFile)
+ {
+ const SearchResultFile *file = static_cast<const SearchResultFile *>(item);
+ result = data(file, role);
+ }
+
+ return result;
+}
+
+QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) const
+{
+ QVariant result;
+
+ switch (role)
+ {
+ case Qt::ToolTipRole:
+ result = row->rowText().trimmed();
+ break;
+ case Qt::FontRole:
+ result = QFont("courier");
+ break;
+ case ItemDataRoles::ResultLineRole:
+ case Qt::DisplayRole:
+ result = row->rowText();
+ break;
+ case ItemDataRoles::ResultIndexRole:
+ result = row->index();
+ break;
+ case ItemDataRoles::ResultLineNumberRole:
+ result = row->lineNumber();
+ break;
+ case ItemDataRoles::SearchTermStartRole:
+ result = row->searchTermStart();
+ break;
+ case ItemDataRoles::SearchTermLengthRole:
+ result = row->searchTermLength();
+ break;
+ case ItemDataRoles::TypeRole:
+ result = "row";
+ break;
+ case ItemDataRoles::FileNameRole:
+ {
+ const SearchResultFile *file = dynamic_cast<const SearchResultFile *>(row->getParent());
+ result = file->getFileName();
+ break;
+ }
+ default:
+ result = QVariant();
+ break;
+ }
+
+ return result;
+}
+
+QVariant SearchResultTreeModel::data(const SearchResultFile *file, int role) const
+{
+ QVariant result;
+
+ switch (role)
+ {
+ case Qt::BackgroundRole:
+ result = QColor(qRgb(245, 245, 245));
+ break;
+ case Qt::FontRole:
+ {
+ QFont font;
+ font.setPointSize(font.pointSize() + 1);
+ result = font;
+ break;
+ }
+ case Qt::DisplayRole:
+ result = file->getFileName() + " (" + QString::number(file->getChildrenCount()) + ")";
+ break;
+ case ItemDataRoles::FileNameRole:
+ case Qt::ToolTipRole:
+ result = file->getFileName();
+ break;
+ case ItemDataRoles::ResultLinesCountRole:
+ result = file->getChildrenCount();
+ break;
+ case ItemDataRoles::TypeRole:
+ result = "file";
+ break;
+ default:
+ result = QVariant();
+ break;
+ }
+
+ return result;
+}
+
+QVariant SearchResultTreeModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ Q_UNUSED(section);
+ Q_UNUSED(orientation);
+ Q_UNUSED(role);
+ return QVariant();
+}
+
+void SearchResultTreeModel::appendResultFile(const QString &fileName)
+{
+ m_lastAppendedResultFile = new SearchResultFile(fileName, m_rootItem);
+
+ beginInsertRows(QModelIndex(), m_rootItem->getChildrenCount(), m_rootItem->getChildrenCount());
+ m_rootItem->appendChild(m_lastAppendedResultFile);
+ endInsertRows();
+}
+
+void SearchResultTreeModel::appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart,
+ int searchTermLength)
+{
+ if (!m_lastAppendedResultFile)
+ return;
+
+ QModelIndex lastFile(createIndex(m_lastAppendedResultFile->getRowOfItem(), 0, m_lastAppendedResultFile));
+
+ beginInsertRows(lastFile, m_lastAppendedResultFile->getChildrenCount(), m_lastAppendedResultFile->getChildrenCount());
+ m_lastAppendedResultFile->appendResultLine(index, lineNumber, rowText, searchTermStart, searchTermLength);
+ endInsertRows();
+
+ dataChanged(lastFile, lastFile); // Make sure that the number after the file name gets updated
+}
+
+void SearchResultTreeModel::appendResultLine(int index, const QString &fileName, int lineNumber, const QString &rowText,
+ int searchTermStart, int searchTermLength)
+{
+ if (!m_lastAppendedResultFile || (m_lastAppendedResultFile->getFileName() != fileName))
+ appendResultFile(fileName);
+
+ appendResultLine(index, lineNumber, rowText, searchTermStart, searchTermLength);
+}
+
+void SearchResultTreeModel::clear(void)
+{
+ m_lastAppendedResultFile = NULL;
+ m_rootItem->clearChildren();
+ reset();
+}
diff --git a/src/plugins/find/searchresulttreemodel.h b/src/plugins/find/searchresulttreemodel.h
new file mode 100644
index 0000000000..5a55920fa4
--- /dev/null
+++ b/src/plugins/find/searchresulttreemodel.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SEARCHRESULTTREEMODEL_H
+#define SEARCHRESULTTREEMODEL_H
+
+#include <QtCore/QAbstractItemModel>
+
+namespace Find{
+namespace Internal {
+
+class SearchResultTreeItem;
+class SearchResultTextRow;
+class SearchResultFile;
+
+class SearchResultTreeModel: public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ SearchResultTreeModel(QObject *parent = 0);
+ ~SearchResultTreeModel();
+
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ 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) const;
+
+signals:
+ void jumpToSearchResult(const QString &fileName, int lineNumber,
+ int searchTermStart, int searchTermLength);
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+
+public slots:
+ void clear();
+ void appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart,
+ int searchTermLength);
+ void appendResultLine(int index, const QString &fileName, int lineNumber, const QString &rowText, int searchTermStart,
+ int searchTermLength);
+
+private:
+ void appendResultFile(const QString &fileName);
+ QVariant data(const SearchResultTextRow *row, int role) const;
+ QVariant data(const SearchResultFile *file, int role) const;
+ void initializeData(void);
+ void disposeData(void);
+
+ SearchResultTreeItem *m_rootItem;
+ SearchResultFile *m_lastAppendedResultFile;
+};
+
+} //Internal
+} //Find
+
+#endif
diff --git a/src/plugins/find/searchresulttreeview.cpp b/src/plugins/find/searchresulttreeview.cpp
new file mode 100644
index 0000000000..c7bee6febb
--- /dev/null
+++ b/src/plugins/find/searchresulttreeview.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "searchresulttreeview.h"
+#include "searchresulttreeitemroles.h"
+#include "searchresulttreemodel.h"
+#include "searchresulttreeitemdelegate.h"
+
+#include <QtGui/QHeaderView>
+
+using namespace Find::Internal;
+
+SearchResultTreeView::SearchResultTreeView(QWidget *parent)
+: QTreeView(parent)
+, m_autoExpandResults(false)
+{
+ m_model = new SearchResultTreeModel(this);
+ setModel(m_model);
+ setItemDelegate(new SearchResultTreeItemDelegate(this));
+
+ setIndentation(14);
+ header()->hide();
+
+ connect (this, SIGNAL(activated(const QModelIndex&)), this, SLOT(emitJumpToSearchResult(const QModelIndex&)));
+}
+
+void SearchResultTreeView::setAutoExpandResults(bool expand)
+{
+ m_autoExpandResults = expand;
+}
+
+void SearchResultTreeView::clear(void)
+{
+ m_model->clear();
+}
+
+void SearchResultTreeView::appendResultLine(int index, const QString &fileName, int lineNumber, const QString &rowText,
+ int searchTermStart, int searchTermLength)
+{
+ int rowsBefore = m_model->rowCount();
+ m_model->appendResultLine(index, fileName, lineNumber, rowText, searchTermStart, searchTermLength);
+ int rowsAfter = m_model->rowCount();
+
+ if (m_autoExpandResults && (rowsAfter > rowsBefore))
+ setExpanded(model()->index(model()->rowCount()-1, 0), true);
+}
+
+void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index)
+{
+ if (model()->data(index, ItemDataRoles::TypeRole).toString().compare("row") != 0)
+ return;
+
+ QString fileName(model()->data(index, ItemDataRoles::FileNameRole).toString());
+ int position = model()->data(index, ItemDataRoles::ResultIndexRole).toInt();
+ int lineNumber = model()->data(index, ItemDataRoles::ResultLineNumberRole).toInt();
+ int searchTermStart = model()->data(index, ItemDataRoles::SearchTermStartRole).toInt();
+ int searchTermLength = model()->data(index, ItemDataRoles::SearchTermLengthRole).toInt();
+
+ emit jumpToSearchResult(position, fileName, lineNumber, searchTermStart, searchTermLength);
+}
+
+void SearchResultTreeView::keyPressEvent(QKeyEvent *e)
+{
+ if (!e->modifiers() && e->key() == Qt::Key_Return) {
+ emit activated(currentIndex());
+ e->accept();
+ return;
+ }
+ QTreeView::keyPressEvent(e);
+}
diff --git a/src/plugins/find/searchresulttreeview.h b/src/plugins/find/searchresulttreeview.h
new file mode 100644
index 0000000000..e5491cc0ce
--- /dev/null
+++ b/src/plugins/find/searchresulttreeview.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SEARCHRESULTTREEVIEW_H
+#define SEARCHRESULTTREEVIEW_H
+
+#include <QtGui/QTreeView>
+#include <QtGui/QKeyEvent>
+
+namespace Find {
+namespace Internal {
+
+class SearchResultTreeModel;
+
+class SearchResultTreeView: public QTreeView
+{
+ Q_OBJECT
+
+public:
+ SearchResultTreeView(QWidget *parent = 0);
+ void setAutoExpandResults(bool expand);
+
+signals:
+ void jumpToSearchResult(int index, const QString &fileName, int lineNumber,
+ int searchTermStart, int searchTermLength);
+
+public slots:
+ void clear();
+ void appendResultLine(int index, const QString &fileName, int lineNumber, const QString &lineText,
+ int searchTermStart, int searchTermLength);
+
+private slots:
+ void emitJumpToSearchResult(const QModelIndex &index);
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+
+ SearchResultTreeModel *m_model;
+ bool m_autoExpandResults;
+};
+
+} // namespace Internal
+} // namespace Find
+
+#endif // SEARCHRESULTTREEVIEW_H
diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp
new file mode 100644
index 0000000000..a113d439f8
--- /dev/null
+++ b/src/plugins/find/searchresultwindow.cpp
@@ -0,0 +1,196 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "searchresultwindow.h"
+#include "searchresulttreemodel.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtCore/QSettings>
+#include <QtGui/QListWidget>
+#include <QtGui/QToolButton>
+
+using namespace Find;
+using namespace Find::Internal;
+
+static const QString SETTINGSKEYSECTIONNAME("SearchResults");
+static const QString SETTINGSKEYEXPANDRESULTS("ExpandResults");
+
+SearchResultWindow::SearchResultWindow(Core::ICore *core):
+ m_core(core),
+ m_widget(new QStackedWidget())
+{
+ m_widget->setWindowTitle(name());
+
+ m_searchResultTreeView = new SearchResultTreeView(m_widget);
+ m_searchResultTreeView->setUniformRowHeights(true);
+ m_searchResultTreeView->setFrameStyle(QFrame::NoFrame);
+ m_widget->addWidget(m_searchResultTreeView);
+
+ m_noMatchesFoundDisplay = new QListWidget(m_widget);
+ m_noMatchesFoundDisplay->addItem(tr("No matches found!"));
+ m_noMatchesFoundDisplay->setFrameStyle(QFrame::NoFrame);
+ m_widget->addWidget(m_noMatchesFoundDisplay);
+
+ m_expandCollapseToolButton = new QToolButton(m_widget);
+ m_expandCollapseToolButton->setAutoRaise(true);
+ m_expandCollapseToolButton->setCheckable(true);
+ m_expandCollapseToolButton->setIcon(QIcon(":/find/images/expand.png"));
+ m_expandCollapseToolButton->setToolTip(tr("Expand All"));
+
+ connect(m_searchResultTreeView, SIGNAL(jumpToSearchResult(int,const QString&,int,int,int)),
+ this, SLOT(handleJumpToSearchResult(int,const QString&,int,int,int)));
+ connect(m_expandCollapseToolButton, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool)));
+
+ readSettings();
+}
+
+SearchResultWindow::~SearchResultWindow()
+{
+ writeSettings();
+ delete m_widget;
+ m_widget = 0;
+ qDeleteAll(m_items);
+ m_items.clear();
+}
+
+bool SearchResultWindow::hasFocus()
+{
+ return m_searchResultTreeView->hasFocus();
+}
+
+bool SearchResultWindow::canFocus()
+{
+ return !m_items.isEmpty();
+}
+
+void SearchResultWindow::setFocus()
+{
+ if (!m_items.isEmpty())
+ m_searchResultTreeView->setFocus();
+}
+
+void SearchResultWindow::visibilityChanged(bool /*visible*/)
+{
+}
+
+QWidget *SearchResultWindow::outputWidget(QWidget *)
+{
+ return m_widget;
+}
+
+QList<QWidget*> SearchResultWindow::toolBarWidgets(void) const
+{
+ return QList<QWidget*>() << m_expandCollapseToolButton;
+}
+
+void SearchResultWindow::clearContents()
+{
+ m_widget->setCurrentWidget(m_searchResultTreeView);
+ m_searchResultTreeView->clear();
+ qDeleteAll(m_items);
+ m_items.clear();
+}
+
+void SearchResultWindow::showNoMatchesFound(void)
+{
+ m_widget->setCurrentWidget(m_noMatchesFoundDisplay);
+}
+
+bool SearchResultWindow::isEmpty() const
+{
+ return (m_searchResultTreeView->model()->rowCount() < 1);
+}
+
+int SearchResultWindow::numberOfResults() const
+{
+ return m_searchResultTreeView->model()->rowCount();
+}
+
+void SearchResultWindow::handleJumpToSearchResult(int index, const QString &fileName, int lineNumber,
+ int searchTermStart, int searchTermLength)
+{
+ Q_UNUSED(searchTermLength);
+ ResultWindowItem *item = m_items.at(index);
+ emit item->activated(fileName, lineNumber, searchTermStart);
+}
+
+ResultWindowItem *SearchResultWindow::addResult(const QString &fileName, int lineNumber, const QString &rowText,
+ int searchTermStart, int searchTermLength)
+{
+ m_widget->setCurrentWidget(m_searchResultTreeView);
+ int index = m_items.size();
+ ResultWindowItem *item = new ResultWindowItem;
+ m_items.append(item);
+ m_searchResultTreeView->appendResultLine(index, fileName, lineNumber, rowText, searchTermStart, searchTermLength);
+ if (index == 0) {
+ // We didn't have an item before, set the focus to the m_searchResultTreeView
+ m_searchResultTreeView->setFocus();
+ m_searchResultTreeView->selectionModel()->select(m_searchResultTreeView->model()->index(0, 0, QModelIndex()), QItemSelectionModel::Select);
+ }
+
+ return item;
+}
+
+void SearchResultWindow::handleExpandCollapseToolButton(bool checked)
+{
+ m_searchResultTreeView->setAutoExpandResults(checked);
+ if (checked)
+ m_searchResultTreeView->expandAll();
+ else
+ m_searchResultTreeView->collapseAll();
+}
+
+void SearchResultWindow::readSettings(void)
+{
+ if (m_core && m_core->settings()) {
+ QSettings *s = m_core->settings();
+ s->beginGroup(SETTINGSKEYSECTIONNAME);
+ m_expandCollapseToolButton->setChecked(s->value(SETTINGSKEYEXPANDRESULTS, m_initiallyExpand).toBool());
+ s->endGroup();
+ }
+}
+
+void SearchResultWindow::writeSettings(void)
+{
+ if (m_core && m_core->settings()) {
+ QSettings *s = m_core->settings();
+ s->beginGroup(SETTINGSKEYSECTIONNAME);
+ s->setValue(SETTINGSKEYEXPANDRESULTS, m_expandCollapseToolButton->isChecked());
+ s->endGroup();
+ }
+}
+
+int SearchResultWindow::priorityInStatusBar() const
+{
+ return 80;
+}
diff --git a/src/plugins/find/searchresultwindow.h b/src/plugins/find/searchresultwindow.h
new file mode 100644
index 0000000000..463b66a106
--- /dev/null
+++ b/src/plugins/find/searchresultwindow.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SEARCHRESULTWINDOW_H
+#define SEARCHRESULTWINDOW_H
+
+#include "find_global.h"
+#include "searchresulttreeview.h"
+
+#include <coreplugin/ioutputpane.h>
+#include <coreplugin/icore.h>
+
+#include <QtCore/QThread>
+#include <QtCore/QStringList>
+#include <QtGui/QStackedWidget>
+#include <QtGui/QListWidget>
+#include <QtGui/QToolButton>
+
+namespace Find {
+
+class SearchResultWindow;
+
+class FIND_EXPORT ResultWindowItem : public QObject
+{
+ Q_OBJECT
+
+signals:
+ void activated(const QString &fileName, int lineNumber, int column);
+
+ friend class SearchResultWindow;
+};
+
+class FIND_EXPORT SearchResultWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ SearchResultWindow(Core::ICore *core);
+ ~SearchResultWindow();
+
+ QWidget *outputWidget(QWidget *);
+ QList<QWidget*> toolBarWidgets(void) const;
+
+ QString name() const { return tr("Search Results"); }
+ int priorityInStatusBar() const;
+ void visibilityChanged(bool visible);
+ bool isEmpty() const;
+ int numberOfResults() const;
+ bool hasFocus();
+ bool canFocus();
+ void setFocus();
+
+public slots:
+ void clearContents();
+ void showNoMatchesFound();
+ ResultWindowItem *addResult(const QString &fileName, int lineNumber, const QString &lineText,
+ int searchTermStart, int searchTermLength);
+
+private slots:
+ void handleExpandCollapseToolButton(bool checked);
+ void handleJumpToSearchResult(int index, const QString &fileName, int lineNumber,
+ int searchTermStart, int searchTermLength);
+
+private:
+ void readSettings(void);
+ void writeSettings(void);
+
+ Internal::SearchResultTreeView *m_searchResultTreeView;
+ QListWidget *m_noMatchesFoundDisplay;
+ Core::ICore *m_core;
+ QToolButton *m_expandCollapseToolButton;
+ static const bool m_initiallyExpand = false;
+ QStackedWidget *m_widget;
+ QList<ResultWindowItem *> m_items;
+};
+
+} // namespace Find
+
+#endif // SEARCHRESULTWINDOW_H
diff --git a/src/plugins/find/textfindconstants.h b/src/plugins/find/textfindconstants.h
new file mode 100644
index 0000000000..73c92ed441
--- /dev/null
+++ b/src/plugins/find/textfindconstants.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTFINDCONSTANTS_H
+#define TEXTFINDCONSTANTS_H
+
+ namespace Find {
+ namespace Constants {
+ const char * const M_FIND = "Find.FindMenu";
+ const char * const G_FIND_FILTERS = "Find.FindMenu.Filters";
+ const char * const G_FIND_FLAGS = "Find.FindMenu.Flags";
+ const char * const G_FIND_ACTIONS = "Find.FindMenu.Actions";
+
+ const char * const FIND = "Find.FindReplace";
+ const char * const FIND_IN_DOCUMENT = "Find.FindInCurrentDocument";
+ const char * const FIND_NEXT = "Find.FindNext";
+ const char * const FIND_PREVIOUS = "Find.FindPrevious";
+ const char * const FIND_ALL = "Find.FindAll";
+ const char * const REPLACE_NEXT = "Find.ReplaceNext";
+ const char * const REPLACE_PREVIOUS = "Find.ReplacePrevious";
+ const char * const REPLACE_ALL = "Find.ReplaceAll";
+ const char * const CASE_SENSITIVE = "Find.CaseSensitive";
+ const char * const WHOLE_WORDS = "Find.WholeWords";
+ const char * const TASK_SEARCH = "Find.Task.Search";
+ }
+ } //Find
+
+#endif //TEXTFINDCONSTANTS_H
diff --git a/src/plugins/git/ScmGit.pluginspec b/src/plugins/git/ScmGit.pluginspec
new file mode 100644
index 0000000000..689cc30a57
--- /dev/null
+++ b/src/plugins/git/ScmGit.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="ScmGit" version="0.1" compatVersion="0.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Git integration.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="VCSBase" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/git/TODO.txt b/src/plugins/git/TODO.txt
new file mode 100644
index 0000000000..2913ba5f46
--- /dev/null
+++ b/src/plugins/git/TODO.txt
@@ -0,0 +1,26 @@
+- Make texts translateable
+- Do not use QErrorMessage, Creator standard error instead?
+Commands:
+ - P2:
+ - branch [list, create, delete]
+ - checkout [with/without creation]
+ - combine both above to a single dialog?
+ - P3:
+ - stash [creating, listing, applying]
+ - allow to use external viewer instead of greenhouse one
+ as these have more functionality usually
+
+GUI:
+ - Better diff view
+ - Commit view View (reuse diff view?)
+ - Commit action View
+ - Able to add further files to commit (list of modified/untracked files)
+ - use List for Log (and allow 10+ entries)
+ - Have commits clickable for 'git show'
+Backend:
+ - Don't use forked processes, instead find a library connection like libgit-thin
+ - http://repo.or.cz/w/git/libgit-gsoc.git
+ - apply to SCM Manager in Greenhouse, currently it's mostly independent
+
+Suggestions:
+ - Bjorn: Use a "Summary" Lineedit in the commit dialog to make commits look nicer on gitweb or such.
diff --git a/src/plugins/git/annotationhighlighter.cpp b/src/plugins/git/annotationhighlighter.cpp
new file mode 100644
index 0000000000..534c45395b
--- /dev/null
+++ b/src/plugins/git/annotationhighlighter.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "annotationhighlighter.h"
+#include <QtCore/QDebug>
+
+namespace Git {
+namespace Internal {
+
+GitAnnotationHighlighter::GitAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ VCSBase::BaseAnnotationHighlighter(changeNumbers, document),
+ m_blank(QLatin1Char(' '))
+{
+}
+
+QString GitAnnotationHighlighter::changeNumber(const QString &block) const
+{
+ const int pos = block.indexOf(m_blank, 4);
+ return pos > 1 ? block.left(pos) : QString();
+}
+
+}
+}
diff --git a/src/plugins/git/annotationhighlighter.h b/src/plugins/git/annotationhighlighter.h
new file mode 100644
index 0000000000..3368e4dc9f
--- /dev/null
+++ b/src/plugins/git/annotationhighlighter.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ANNOTATIONHIGHLIGHTER_H
+#define ANNOTATIONHIGHLIGHTER_H
+
+#include <vcsbase/baseannotationhighlighter.h>
+
+namespace Git {
+namespace Internal {
+
+// Annotation highlighter for p4 triggering on 'changenumber:'
+class GitAnnotationHighlighter : public VCSBase::BaseAnnotationHighlighter
+{
+ Q_OBJECT
+public:
+ explicit GitAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = 0);
+
+private:
+ virtual QString changeNumber(const QString &block) const;
+
+ const QChar m_blank;
+};
+
+} //namespace Git
+} //namespace Internal
+
+#endif
diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp
new file mode 100644
index 0000000000..6491614b5f
--- /dev/null
+++ b/src/plugins/git/changeselectiondialog.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "changeselectiondialog.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+using namespace Git::Internal;
+
+ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.repositoryButton, SIGNAL(clicked()), this, SLOT(selectWorkingDirectory()));
+}
+
+void ChangeSelectionDialog::selectWorkingDirectory()
+{
+ static QString location = QString();
+ location = QFileDialog::getExistingDirectory(this,
+ QLatin1String("Select Git repository"),
+ location);
+ if (location.isEmpty())
+ return;
+
+ // Verify that the location is a repository
+ // We are polite, we also allow to specify a directory, which is not
+ // the head directory of the repository.
+ QDir repository(location);
+ do {
+ if (repository.entryList(QDir::AllDirs).contains(QLatin1String(".git"))) {
+ m_ui.repositoryEdit->setText(repository.absolutePath());
+ return;
+ }
+ } while (repository.cdUp());
+
+ // Did not find a repo
+ QMessageBox::critical(this, QLatin1String("Error"),
+ QLatin1String("Selected directory is not a Git repository"));
+
+}
diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h
new file mode 100644
index 0000000000..02d0aa76d3
--- /dev/null
+++ b/src/plugins/git/changeselectiondialog.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CHANGESELECTIONDIALOG_H
+#define CHANGESELECTIONDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_changeselectiondialog.h"
+
+namespace Git {
+namespace Internal {
+
+ class GitPlugin;
+
+class ChangeSelectionDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ChangeSelectionDialog(QWidget *parent = 0);
+
+public slots:
+ void selectWorkingDirectory();
+
+private:
+ friend class GitPlugin;
+ Ui_ChangeSelectionDialog m_ui;
+
+};
+
+} //namespace Internal
+} //namespace Git
+
+#endif // CHANGESELECTIONDIALOG_H
diff --git a/src/plugins/git/changeselectiondialog.ui b/src/plugins/git/changeselectiondialog.ui
new file mode 100644
index 0000000000..34f2718ec8
--- /dev/null
+++ b/src/plugins/git/changeselectiondialog.ui
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChangeSelectionDialog</class>
+ <widget class="QDialog" name="ChangeSelectionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>401</width>
+ <height>142</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Repository Location:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="repositoryEdit"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="repositoryButton">
+ <property name="text">
+ <string>Select</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Change:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="changeNumberEdit"/>
+ </item>
+ <item row="2" column="0" colspan="3">
+ <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>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ChangeSelectionDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ChangeSelectionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp
new file mode 100644
index 0000000000..aafafe1566
--- /dev/null
+++ b/src/plugins/git/commitdata.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "commitdata.h"
+
+#include <QtCore/QDebug>
+
+namespace Git {
+namespace Internal {
+
+void GitSubmitEditorPanelInfo::clear()
+{
+ repository.clear();
+ description.clear();
+ branch.clear();
+}
+
+QDebug operator<<(QDebug d, const GitSubmitEditorPanelInfo &data)
+{
+ d.nospace() << "Rep: " << data.repository << " Descr: " << data.description
+ << " branch: " << data.branch;
+ return d;
+}
+
+void GitSubmitEditorPanelData::clear()
+{
+ author.clear();
+ email.clear();
+}
+
+QString GitSubmitEditorPanelData::authorString() const
+{
+ QString rc;
+ rc += QLatin1Char('"');
+ rc += author;
+ rc += QLatin1String(" <");
+ rc += email;
+ rc += QLatin1String(">\"");
+ return rc;
+}
+
+QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &data)
+{
+ d.nospace() << " author:" << data.author << " email: " << data.email;
+ return d;
+}
+
+void CommitData::clear()
+{
+ panelInfo.clear();
+ panelData.clear();
+
+ commitFiles.clear();
+ notUpdatedFiles.clear();
+ untrackedFiles.clear();
+}
+
+QDebug operator<<(QDebug d, const CommitData &data)
+{
+ d << data.panelInfo << data.panelData;
+ d.nospace() << "Commit: " << data.commitFiles << " Not updated: "
+ << data.notUpdatedFiles << " Untracked: " << data.untrackedFiles;
+ return d;
+}
+
+}
+}
diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h
new file mode 100644
index 0000000000..94a82005ae
--- /dev/null
+++ b/src/plugins/git/commitdata.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMMITDATA_H
+#define COMMITDATA_H
+
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
+namespace Git {
+namespace Internal {
+
+ // Read-only
+ struct GitSubmitEditorPanelInfo {
+ void clear();
+ QString repository;
+ QString description;
+ QString branch;
+ };
+
+ QDebug operator<<(QDebug d, const GitSubmitEditorPanelInfo &);
+
+ struct GitSubmitEditorPanelData {
+ void clear();
+ // Format as "John Doe <jdoe@foobar.com>"
+ QString authorString() const;
+
+ QString author;
+ QString email;
+ };
+
+ QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &);
+
+ struct CommitData {
+ void clear();
+ GitSubmitEditorPanelInfo panelInfo;
+ GitSubmitEditorPanelData panelData;
+ QStringList commitFiles;
+ QStringList notUpdatedFiles;
+ QStringList untrackedFiles;
+ };
+
+ QDebug operator<<(QDebug d, const CommitData &);
+
+
+}
+}
+
+#endif
diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro
new file mode 100644
index 0000000000..258639dcbe
--- /dev/null
+++ b/src/plugins/git/git.pro
@@ -0,0 +1,35 @@
+TEMPLATE = lib
+TARGET = ScmGit
+include(../../qworkbenchplugin.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/vcsbase/vcsbase.pri)
+include(../../libs/utils/utils.pri)
+
+HEADERS += gitplugin.h \
+ gitconstants.h \
+ gitoutputwindow.h \
+ gitclient.h \
+ changeselectiondialog.h \
+ commitdata.h \
+ settingspage.h \
+ giteditor.h \
+ annotationhighlighter.h \
+ gitsubmiteditorwidget.h \
+ gitsubmiteditor.h
+
+SOURCES += gitplugin.cpp \
+ gitoutputwindow.cpp \
+ gitclient.cpp \
+ changeselectiondialog.cpp \
+ commitdata.cpp \
+ settingspage.cpp \
+ giteditor.cpp \
+ annotationhighlighter.cpp \
+ gitsubmiteditorwidget.cpp \
+ gitsubmiteditor.cpp
+
+FORMS += changeselectiondialog.ui \
+ settingspage.ui \
+ gitsubmitpanel.ui
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
new file mode 100644
index 0000000000..b3f7107861
--- /dev/null
+++ b/src/plugins/git/gitclient.cpp
@@ -0,0 +1,635 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitclient.h"
+#include "gitplugin.h"
+#include "gitconstants.h"
+#include "commitdata.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <texteditor/itexteditor.h>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QFuture>
+
+#include <QtGui/QErrorMessage>
+
+using namespace Git;
+using namespace Git::Internal;
+
+const char* const kGitCommand = "git";
+const char* const kGitDirectoryC = ".git";
+const char* const kBranchIndicatorC = "# On branch";
+
+static inline QString msgServerFailure()
+{
+ return GitClient::tr(
+"Note that the git plugin for QtCreator is not able to interact with the server "
+"so far. Thus, manual ssh-identification etc. will not work.");
+}
+
+inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property, const QString &entry)
+{
+ foreach (Core::IEditor *ed, core->editorManager()->openedEditors())
+ if (ed->property(property).toString() == entry)
+ return ed;
+ return 0;
+}
+
+GitClient::GitClient(GitPlugin* plugin, Core::ICore *core) :
+ m_msgWait(tr("Waiting for data...")),
+ m_plugin(plugin),
+ m_core(core)
+{
+}
+
+GitClient::~GitClient()
+{
+}
+
+bool GitClient::vcsOpen(const QString &fileName)
+{
+ return m_plugin->vcsOpen(fileName);
+}
+
+QString GitClient::findRepositoryForFile(const QString &fileName)
+{
+ const QString gitDirectory = QLatin1String(kGitDirectoryC);
+ const QFileInfo info(fileName);
+ QDir dir = info.absoluteDir();
+ do {
+ if (dir.entryList(QDir::AllDirs|QDir::Hidden).contains(gitDirectory))
+ return dir.absolutePath();
+ } while (dir.cdUp());
+
+ return QString();
+}
+
+QString GitClient::findRepositoryForDirectory(const QString &dir)
+{
+ const QString gitDirectory = QLatin1String(kGitDirectoryC);
+ QDir directory(dir);
+ do {
+ if (directory.entryList(QDir::AllDirs|QDir::Hidden).contains(gitDirectory))
+ return directory.absolutePath();
+ } while (directory.cdUp());
+
+ return QString();
+}
+
+// Return source file or directory string depending on parameters
+// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file').
+static QString source(const QString &workingDirectory, const QString &fileName)
+{
+ if (fileName.isEmpty())
+ return workingDirectory;
+ QString rc = workingDirectory;
+ if (!rc.isEmpty() && !rc.endsWith(QDir::separator()))
+ rc += QDir::separator();
+ rc += fileName;
+ return rc;
+}
+
+/* Create an editor associated to VCS output of a source file/directory
+ * (using the file's codec). Makes use of a dynamic property to find an
+ * existing instance and to reuse it (in case, say, 'git diff foo' is
+ * already open). */
+VCSBase::VCSBaseEditor
+ *GitClient::createVCSEditor(const QString &kind,
+ QString title,
+ // Source file or directory
+ const QString &source,
+ bool setSourceCodec,
+ // Dynamic property and value to identify that editor
+ const char *registerDynamicProperty,
+ const QString &dynamicPropertyValue) const
+{
+ VCSBase::VCSBaseEditor *rc = 0;
+ Core::IEditor* outputEditor = locateEditor(m_core, registerDynamicProperty, dynamicPropertyValue);
+ if (outputEditor) {
+ // Exists already
+ outputEditor->createNew(m_msgWait);
+ rc = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
+ Q_ASSERT(rc);
+ m_core->editorManager()->setCurrentEditor(outputEditor);
+ } else {
+ // Create new, set wait message, set up with source and codec
+ outputEditor = m_core->editorManager()->newFile(kind, &title, m_msgWait);
+ outputEditor->setProperty(registerDynamicProperty, dynamicPropertyValue);
+ rc = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
+ Q_ASSERT(rc);
+ rc->setSource(source);
+ if (setSourceCodec)
+ rc->setCodec(VCSBase::VCSBaseEditor::getCodec(m_core, source));
+ }
+ return rc;
+}
+
+void GitClient::diff(const QString &workingDirectory, const QStringList &fileNames)
+{
+ if (Git::Constants::debug)
+ qDebug() << "diff" << workingDirectory << fileNames;
+ QStringList arguments;
+ arguments << QLatin1String("diff") << fileNames;
+
+ const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
+ const QString title = tr("Git Diff");
+
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDirectory, true, "originalFileName", workingDirectory);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+
+}
+
+void GitClient::diff(const QString &workingDirectory, const QString &fileName)
+{
+ if (Git::Constants::debug)
+ qDebug() << "diff" << workingDirectory << fileName;
+ QStringList arguments;
+ arguments << QLatin1String("diff");
+ if (!fileName.isEmpty())
+ arguments << fileName;
+
+ const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
+ const QString title = tr("Git Diff %1").arg(fileName);
+ const QString sourceFile = source(workingDirectory, fileName);
+
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "originalFileName", sourceFile);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::status(const QString &workingDirectory)
+{
+ executeGit(workingDirectory, QStringList(QLatin1String("status")), m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::log(const QString &workingDirectory, const QString &fileName)
+{
+ if (Git::Constants::debug)
+ qDebug() << "log" << workingDirectory << fileName;
+ QStringList arguments;
+ int logCount = 10;
+ if (m_plugin->m_settingsPage && m_plugin->m_settingsPage->logCount() > 0)
+ logCount = m_plugin->m_settingsPage->logCount();
+
+ arguments << QLatin1String("log") << QLatin1String("-n")
+ << QString::number(logCount);
+ if (!fileName.isEmpty())
+ arguments << fileName;
+
+ const QString title = tr("Git Log %1").arg(fileName);
+ const QString kind = QLatin1String(Git::Constants::GIT_LOG_EDITOR_KIND);
+ const QString sourceFile = source(workingDirectory, fileName);
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, false, "logFileName", sourceFile);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::show(const QString &source, const QString &id)
+{
+ if (Git::Constants::debug)
+ qDebug() << "show" << source << id;
+ QStringList arguments(QLatin1String("show"));
+ arguments << id;
+
+ const QString title = tr("Git Show %1").arg(id);
+ const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true, "show", id);
+
+ const QFileInfo sourceFi(source);
+ const QString workDir = sourceFi.isDir() ? sourceFi.absoluteFilePath() : sourceFi.absolutePath();
+ executeGit(workDir, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::blame(const QString &workingDirectory, const QString &fileName)
+{
+ if (Git::Constants::debug)
+ qDebug() << "blame" << workingDirectory << fileName;
+ QStringList arguments(QLatin1String("blame"));
+ arguments << fileName;
+
+ const QString kind = QLatin1String(Git::Constants::GIT_BLAME_EDITOR_KIND);
+ const QString title = tr("Git Blame %1").arg(fileName);
+ const QString sourceFile = source(workingDirectory, fileName);
+
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "blameFileName", sourceFile);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::checkout(const QString &workingDirectory, const QString &fileName)
+{
+ // Passing an empty argument as the file name is very dangereous, since this makes
+ // git checkout apply to all files. Almost looks like a bug in git.
+ if (fileName.isEmpty())
+ return;
+
+ QStringList arguments;
+ arguments << QLatin1String("checkout") << QLatin1String("HEAD") << QLatin1String("--")
+ << fileName;
+
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::hardReset(const QString &workingDirectory, const QString &commit)
+{
+ QStringList arguments;
+ arguments << QLatin1String("reset") << QLatin1String("--hard");
+ if (!commit.isEmpty())
+ arguments << commit;
+
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::addFile(const QString &workingDirectory, const QString &fileName)
+{
+ QStringList arguments;
+ arguments << QLatin1String("add") << fileName;
+
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true);
+}
+
+bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files)
+{
+ QByteArray outputText;
+ QByteArray errorText;
+ QStringList arguments;
+ arguments << "add" << files;
+ const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ if (!rc) {
+ const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()).
+ arg(workingDirectory, QString::fromLocal8Bit(errorText));
+ m_plugin->m_outputWindow->append(errorMessage);
+ m_plugin->m_outputWindow->popup(false);
+ }
+ return rc;
+}
+
+void GitClient::executeGit(const QString &workingDirectory, const QStringList &arguments,
+ GitOutputWindow *outputWindow, VCSBase::VCSBaseEditor* editor,
+ bool outputToWindow)
+{
+ if (Git::Constants::debug)
+ qDebug() << "executeGit" << workingDirectory << arguments << editor;
+ outputWindow->clearContents();
+
+ QProcess process;
+ ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
+
+ if (m_plugin->m_settingsPage && !m_plugin->m_settingsPage->adoptEnvironment())
+ environment.set(QLatin1String("PATH"), m_plugin->m_settingsPage->path());
+
+ GitCommand* command = new GitCommand();
+ if (outputToWindow) {
+ Q_ASSERT(outputWindow);
+ connect(command, SIGNAL(outputText(QString)), outputWindow, SLOT(append(QString)));
+ connect(command, SIGNAL(outputData(QByteArray)), outputWindow, SLOT(appendData(QByteArray)));
+ } else {
+ Q_ASSERT(editor);
+ connect(command, SIGNAL(outputText(QString)), editor, SLOT(setPlainText(QString)));
+ connect(command, SIGNAL(outputData(QByteArray)), editor, SLOT(setPlainTextData(QByteArray)));
+ }
+
+ if (outputWindow)
+ connect(command, SIGNAL(errorText(QString)), outputWindow, SLOT(append(QString)));
+
+ command->execute(arguments, workingDirectory, environment);
+}
+
+bool GitClient::synchronousGit(const QString &workingDirectory
+ , const QStringList &arguments
+ , QByteArray* outputText
+ , QByteArray* errorText)
+{
+ if (Git::Constants::debug)
+ qDebug() << "synchronousGit" << workingDirectory << arguments;
+ QProcess process;
+
+ process.setWorkingDirectory(workingDirectory);
+
+ ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
+ if (m_plugin->m_settingsPage && !m_plugin->m_settingsPage->adoptEnvironment())
+ environment.set(QLatin1String("PATH"), m_plugin->m_settingsPage->path());
+ process.setEnvironment(environment.toStringList());
+
+ process.start(QLatin1String(kGitCommand), arguments);
+ if (!process.waitForFinished()) {
+ if (errorText)
+ *errorText = "Error: Git timed out";
+ return false;
+ }
+
+ if (outputText)
+ *outputText = process.readAllStandardOutput();
+
+ if (errorText)
+ *errorText = process.readAllStandardError();
+
+ if (Git::Constants::debug)
+ qDebug() << "synchronousGit ex=" << process.exitCode();
+ return process.exitCode() == 0;
+}
+
+/* Parse a git status file list:
+ * \code
+ # Changes to be committed:
+ #<tab>modified:<blanks>git.pro
+ # Changed but not updated:
+ #<tab>modified:<blanks>git.pro
+ # Untracked files:
+ #<tab>modified:<blanks>git.pro
+ \endcode
+*/
+static bool parseFiles(const QStringList &lines, CommitData *d)
+{
+ enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles };
+
+ const QString branchIndicator = QLatin1String(kBranchIndicatorC);
+ const QString commitIndicator = QLatin1String("# Changes to be committed:");
+ const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:");
+ const QString untrackedIndicator = QLatin1String("# Untracked files:");
+
+ State s = None;
+
+ const QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+[^ ]+"));
+ Q_ASSERT(filesPattern.isValid());
+
+ const QStringList::const_iterator cend = lines.constEnd();
+ for (QStringList::const_iterator it = lines.constBegin(); it != cend; ++it) {
+ const QString line = *it;
+ if (line.startsWith(branchIndicator)) {
+ d->panelInfo.branch = line.mid(branchIndicator.size() + 1);
+ } else {
+ if (line.startsWith(commitIndicator)) {
+ s = CommitFiles;
+ } else {
+ if (line.startsWith(notUpdatedIndicator)) {
+ s = NotUpdatedFiles;
+ } else {
+ if (line.startsWith(untrackedIndicator)) {
+ s = UntrackedFiles;
+ } else {
+ if (filesPattern.exactMatch(line)) {
+ const QString fileSpec = line.mid(2).simplified();
+ switch (s) {
+ case CommitFiles:
+ d->commitFiles.push_back(fileSpec);
+ break;
+ case NotUpdatedFiles:
+ d->notUpdatedFiles.push_back(fileSpec);
+ break;
+ case UntrackedFiles:
+ d->untrackedFiles.push_back(fileSpec);
+ break;
+ case None:
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return !d->commitFiles.empty() || !d->notUpdatedFiles.empty() || !d->untrackedFiles.empty();
+}
+
+bool GitClient::getCommitData(const QString &workingDirectory,
+ QString *commitTemplate,
+ CommitData *d,
+ QString *errorMessage)
+{
+ d->clear();
+
+ // Find repo
+ const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory);
+ if (repoDirectory.isEmpty()) {
+ *errorMessage = tr("Unable to determine the repository for %1.").arg(workingDirectory);
+ return false;
+ }
+
+ d->panelInfo.repository = repoDirectory;
+
+ QDir gitDir(repoDirectory);
+ if (!gitDir.cd(QLatin1String(kGitDirectoryC))) {
+ *errorMessage = tr("The repository %1 is not initialized yet.").arg(repoDirectory);
+ return false;
+ }
+
+ // Read description
+ const QString descriptionFile = gitDir.absoluteFilePath(QLatin1String("description"));
+ if (QFileInfo(descriptionFile).isFile()) {
+ QFile file(descriptionFile);
+ if (file.open(QIODevice::ReadOnly|QIODevice::Text))
+ d->panelInfo.description = QString::fromLocal8Bit(file.readAll()).trimmed();
+ }
+
+ // Run status. Note that it has exitcode 1 if there are no added files.
+ QByteArray outputText;
+ QByteArray errorText;
+ const bool statusRc = synchronousGit(workingDirectory, QStringList(QLatin1String("status")), &outputText, &errorText);
+ if (!statusRc) {
+ // Something fatal
+ if (!outputText.contains(kBranchIndicatorC)) {
+ *errorMessage = tr("Unable to obtain the project status: %1").arg(QString::fromLocal8Bit(errorText));
+ return false;
+ }
+ // All unchanged
+ if (outputText.contains("nothing to commit")) {
+ *errorMessage = tr("There are no modified files.");
+ return false;
+ }
+ }
+
+ // Output looks like:
+ // # On branch [branchname]
+ // # Changes to be committed:
+ // # (use "git reset HEAD <file>..." to unstage)
+ // #
+ // # modified: somefile.cpp
+ // # new File: somenew.h
+ // #
+ // # Changed but not updated:
+ // # (use "git add <file>..." to update what will be committed)
+ // #
+ // # modified: someother.cpp
+ // #
+ // # Untracked files:
+ // # (use "git add <file>..." to include in what will be committed)
+ // #
+ // # list of files...
+
+ const QStringList lines = QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r')).split(QLatin1Char('\n'));
+ if (!parseFiles(lines, d)) {
+ *errorMessage = tr("Unable to parse the file output.");
+ return false;
+ }
+
+ d->panelData.author = readConfigValue(workingDirectory, QLatin1String("user.name"));
+ d->panelData.email = readConfigValue(workingDirectory, QLatin1String("user.email"));
+
+ // Get the commit template
+ const QString templateFilename = readConfigValue(workingDirectory, QLatin1String("commit.template"));
+ if (!templateFilename.isEmpty()) {
+ QFile templateFile(templateFilename);
+ if (templateFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ *commitTemplate = QString::fromLocal8Bit(templateFile.readAll());
+ } else {
+ qWarning("Unable to read commit template %s: %s",
+ qPrintable(templateFilename),
+ qPrintable(templateFile.errorString()));
+ }
+ }
+ return true;
+}
+
+bool GitClient::addAndCommit(const QString &workingDirectory,
+ const GitSubmitEditorPanelData &data,
+ const QString &messageFile,
+ const QStringList &files)
+{
+ // Re-add all to make sure we have the latest changes
+ if (!synchronousAdd(workingDirectory, files))
+ return false;
+
+ // Do the final commit
+ QStringList args;
+ args << QLatin1String("commit")
+ << QLatin1String("-F") << QDir::toNativeSeparators(messageFile)
+ << QLatin1String("--author") << data.authorString();
+
+ QByteArray outputText;
+ QByteArray errorText;
+ const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
+ const QString message = rc ?
+ tr("Committed %n file(s).", 0, files.size()) :
+ tr("Unable to commit %n file(s): %1", 0, files.size()).arg(QString::fromLocal8Bit(errorText));
+
+ m_plugin->m_outputWindow->append(message);
+ m_plugin->m_outputWindow->popup(false);
+ return rc;
+}
+
+void GitClient::pull(const QString &workingDirectory)
+{
+ executeGit(workingDirectory, QStringList(QLatin1String("pull")), m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::push(const QString &workingDirectory)
+{
+ executeGit(workingDirectory, QStringList(QLatin1String("push")), m_plugin->m_outputWindow, 0,true);
+}
+
+QString GitClient::readConfig(const QString &workingDirectory, const QStringList &configVar)
+{
+ QStringList arguments;
+ arguments << QLatin1String("config") << configVar;
+
+ QByteArray outputText;
+ if (synchronousGit(workingDirectory, arguments, &outputText))
+ return outputText;
+ return QString();
+}
+
+// Read a single-line config value, return trimmed
+QString GitClient::readConfigValue(const QString &workingDirectory, const QString &configVar)
+{
+ return readConfig(workingDirectory, QStringList(configVar)).remove(QLatin1Char('\n'));
+}
+
+GitCommand::GitCommand()
+{
+}
+
+GitCommand::~GitCommand()
+{
+}
+
+void GitCommand::execute(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment)
+{
+ if (Git::Constants::debug)
+ qDebug() << "GitCommand::execute" << workingDirectory << arguments;
+
+ // For some reason QtConcurrent::run() only works on this
+ QFuture<void> task = QtConcurrent::run(this, &GitCommand::run
+ , arguments
+ , workingDirectory
+ , environment);
+ QString taskName = QLatin1String("Git ") + arguments[0];
+
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ core->progressManager()->addTask(task, taskName
+ , QLatin1String("Git.action")
+ , Core::ProgressManagerInterface::CloseOnSuccess);
+}
+
+void GitCommand::run(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment)
+{
+ if (Git::Constants::debug)
+ qDebug() << "GitCommand::run" << workingDirectory << arguments;
+ QProcess process;
+ if (!workingDirectory.isEmpty())
+ process.setWorkingDirectory(workingDirectory);
+
+ ProjectExplorer::Environment env = environment;
+ if (env.toStringList().isEmpty())
+ env = ProjectExplorer::Environment::systemEnvironment();
+ process.setEnvironment(env.toStringList());
+
+ process.start(QLatin1String(kGitCommand), arguments);
+ if (!process.waitForFinished()) {
+ emit errorText(QLatin1String("Error: Git timed out"));
+ return;
+ }
+
+ const QByteArray output = process.readAllStandardOutput();
+ if (output.isEmpty()) {
+ if (arguments.at(0) == QLatin1String("diff"))
+ emit outputText(tr("The file does not differ from HEAD"));
+ } else {
+ emit outputData(output);
+ }
+ const QByteArray error = process.readAllStandardError();
+ if (!error.isEmpty())
+ emit errorText(QString::fromLocal8Bit(error));
+
+ // As it is used asynchronously, we need to delete ourselves
+ this->deleteLater();
+}
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
new file mode 100644
index 0000000000..f91eefda66
--- /dev/null
+++ b/src/plugins/git/gitclient.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITCLIENT_H
+#define GITCLIENT_H
+
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <projectexplorer/environment.h>
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QErrorMessage;
+QT_END_NAMESPACE
+
+namespace Core {
+ class ICore;
+}
+
+namespace VCSBase {
+ class VCSBaseEditor;
+}
+
+namespace Git {
+namespace Internal {
+
+class GitPlugin;
+class GitOutputWindow;
+class GitCommand;
+struct CommitData;
+struct GitSubmitEditorPanelData;
+
+class GitClient : public Core::IVersionControl
+{
+ Q_OBJECT
+public:
+ explicit GitClient(GitPlugin *plugin, Core::ICore *core);
+ ~GitClient();
+ bool vcsOpen(const QString &fileName);
+ bool vcsAdd(const QString&) {return false;}
+ bool vcsDelete(const QString&) {return false;}
+ bool managesDirectory(const QString&) const {return false;}
+ QString findTopLevelForDirectory(const QString&) const {return QString();}
+
+ static QString findRepositoryForFile(const QString &fileName);
+ static QString findRepositoryForDirectory(const QString &dir);
+
+ void diff(const QString &workingDirectory,
+ const QString &fileName);
+ void diff(const QString &workingDirectory,
+ const QStringList &fileNames);
+
+ void status(const QString &workingDirectory);
+ void log(const QString &workingDirectory
+ , const QString &fileName);
+ void blame(const QString &workingDirectory
+ , const QString &fileName);
+ void showCommit(const QString &workingDirectory
+ , const QString &commit);
+ void checkout(const QString &workingDirectory
+ , const QString &file);
+ void hardReset(const QString &workingDirectory
+ , const QString &commit);
+ void addFile(const QString &workingDirectory
+ , const QString &fileName);
+ bool synchronousAdd(const QString &workingDirectory,
+ const QStringList &files);
+ void pull(const QString &workingDirectory);
+ void push(const QString &workingDirectory);
+
+ QString readConfig(const QString &workingDirectory
+ , const QStringList &configVar);
+
+ QString readConfigValue(const QString &workingDirectory,
+ const QString &configVar);
+
+ bool getCommitData(const QString &workingDirectory,
+ QString *commitTemplate,
+ CommitData *d,
+ QString *errorMessage);
+
+ bool addAndCommit(const QString &workingDirectory,
+ const GitSubmitEditorPanelData &data,
+ const QString &messageFile,
+ const QStringList &files);
+
+public slots:
+ void show(const QString &source, const QString &id);
+
+private:
+ VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind,
+ QString title,
+ const QString &source,
+ bool setSourceCodec,
+ const char *registerDynamicProperty,
+ const QString &dynamicPropertyValue) const;
+
+
+ void executeGit(const QString &workingDirectory
+ , const QStringList &arguments
+ , GitOutputWindow *outputWindow
+ , VCSBase::VCSBaseEditor* editor = 0
+ , bool outputToWindow = false);
+
+ bool synchronousGit(const QString &workingDirectory
+ , const QStringList &arguments
+ , QByteArray* outputText = 0
+ , QByteArray* errorText = 0);
+
+ const QString m_msgWait;
+ GitPlugin *m_plugin;
+ Core::ICore *m_core;
+};
+
+class GitCommand : public QObject
+{
+ Q_OBJECT
+public:
+ GitCommand();
+ ~GitCommand();
+ void execute(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment);
+ void run(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment);
+
+Q_SIGNALS:
+ void outputData(const QByteArray&);
+ void outputText(const QString&);
+ void errorText(const QString&);
+};
+
+ }
+}
+
+#endif // GITCLIENT_H
diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h
new file mode 100644
index 0000000000..a74c903031
--- /dev/null
+++ b/src/plugins/git/gitconstants.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GIT_CONSTANTS_H
+#define GIT_CONSTANTS_H
+
+namespace Git {
+ namespace Constants {
+ const char * const GIT_COMMAND_LOG_EDITOR_KIND = "Git Command Log Editor";
+ const char * const GIT_LOG_EDITOR_KIND = "Git File Log Editor";
+ const char * const GIT_BLAME_EDITOR_KIND = "Git Annotation Editor";
+ const char * const GIT_DIFF_EDITOR_KIND = "Git Diff Editor";
+
+ const char * const C_GITSUBMITEDITOR = "Git Submit Editor";
+ const char * const GITSUBMITEDITOR_KIND = "Git Submit Editor";
+ const char * const SUBMIT_CURRENT = "Nokia.Git.SubmitCurrentLog";
+ const char * const DIFF_SELECTED = "Nokia.Git.DiffSelectedFilesInLog";
+ const char * const SUBMIT_MIMETYPE = "application/vnd.nokia.text.git.submit";
+
+ // TODO: For the moment, trust p4 is loaded...
+ const char * const ICON_SUBMIT = ":/trolltech.perforce/images/submit.png";
+ const char * const ICON_DIFF = ":/trolltech.perforce/images/diff.png";
+
+ const char * const DIFF_FILE_INDICATOR = "--- ";
+ enum { debug = 0 };
+ }
+}
+
+#endif // GIT_CONSTANTS_H
diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp
new file mode 100644
index 0000000000..3bf31da698
--- /dev/null
+++ b/src/plugins/git/giteditor.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "giteditor.h"
+#include "annotationhighlighter.h"
+#include "gitconstants.h"
+#include "gitplugin.h"
+#include "gitclient.h"
+
+#include <vcsbase/diffhighlighter.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QSet>
+#include <QtCore/QRegExp>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtGui/QTextEdit>
+#include <QtGui/QTextCursor>
+
+#define CHANGE_PATTERN_8C "[a-f0-9]{8,8}"
+#define CHANGE_PATTERN_40C "[a-f0-9]{40,40}"
+
+namespace Git {
+namespace Internal {
+
+// ------------ GitEditor
+GitEditor::GitEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent) :
+ VCSBase::VCSBaseEditor(type, parent),
+ m_changeNumberPattern8(QLatin1String(CHANGE_PATTERN_8C)),
+ m_changeNumberPattern40(QLatin1String(CHANGE_PATTERN_40C))
+{
+ Q_ASSERT(m_changeNumberPattern8.isValid());
+ Q_ASSERT(m_changeNumberPattern40.isValid());
+ if (Git::Constants::debug)
+ qDebug() << "GitEditor::GitEditor" << type->type << type->kind;
+}
+
+QSet<QString> GitEditor::annotationChanges() const
+{
+ QSet<QString> changes;
+ const QString txt = toPlainText();
+ if (txt.isEmpty())
+ return changes;
+ // Hunt for first change number in annotation: "<change>:"
+ QRegExp r(QLatin1String("^("CHANGE_PATTERN_8C") "));
+ Q_ASSERT(r.isValid());
+ if (r.indexIn(txt) != -1) {
+ changes.insert(r.cap(1));
+ r.setPattern(QLatin1String("\n("CHANGE_PATTERN_8C") "));
+ Q_ASSERT(r.isValid());
+ int pos = 0;
+ while ((pos = r.indexIn(txt, pos)) != -1) {
+ pos += r.matchedLength();
+ changes.insert(r.cap(1));
+ }
+ }
+ if (Git::Constants::debug)
+ qDebug() << "GitEditor::annotationChanges() returns #" << changes.size();
+ return changes;
+}
+
+QString GitEditor::changeUnderCursor(const QTextCursor &c) const
+{
+ QTextCursor cursor = c;
+ // Any number is regarded as change number.
+ cursor.select(QTextCursor::WordUnderCursor);
+ if (!cursor.hasSelection())
+ return QString();
+ const QString change = cursor.selectedText();
+ if (Git::Constants::debug > 1)
+ qDebug() << "GitEditor:::changeUnderCursor:" << change;
+ if (m_changeNumberPattern8.exactMatch(change))
+ return change;
+ if (m_changeNumberPattern40.exactMatch(change))
+ return change;
+ return QString();
+}
+
+VCSBase::DiffHighlighter *GitEditor::createDiffHighlighter() const
+{
+ const QRegExp filePattern(QLatin1String("^[-+][-+][-+] [ab].*"));
+ return new VCSBase::DiffHighlighter(filePattern);
+}
+
+VCSBase::BaseAnnotationHighlighter *GitEditor::createAnnotationHighlighter(const QSet<QString> &changes) const
+{
+ return new GitAnnotationHighlighter(changes);
+}
+
+QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
+{
+ QString errorMessage;
+ // Check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff)
+ // Go back chunks.
+ const QString newFileIndicator = QLatin1String("+++ b/");
+ for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) {
+ QString diffFileName = block.text();
+ if (diffFileName.startsWith(newFileIndicator)) {
+ diffFileName.remove(0, newFileIndicator.size());
+ const QString fileOrDir = source();
+ const QString repo = QFileInfo(fileOrDir).isDir() ?
+ GitClient::findRepositoryForDirectory(fileOrDir) : GitClient::findRepositoryForFile(fileOrDir);
+ const QString absPath = QDir(repo).absoluteFilePath(diffFileName);
+ if (Git::Constants::debug)
+ qDebug() << "fileNameFromDiffSpecification" << repo << diffFileName << absPath;
+ return absPath;
+ }
+ }
+ return QString();
+}
+
+}
+}
diff --git a/src/plugins/git/giteditor.h b/src/plugins/git/giteditor.h
new file mode 100644
index 0000000000..87e71597dd
--- /dev/null
+++ b/src/plugins/git/giteditor.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITEDITOR_H
+#define GITEDITOR_H
+
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/QRegExp>
+
+namespace Git {
+namespace Internal {
+
+class GitPlugin;
+
+class GitEditor : public VCSBase::VCSBaseEditor
+{
+ Q_OBJECT
+
+public:
+ explicit GitEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent);
+
+private:
+ virtual QSet<QString> annotationChanges() const;
+ virtual QString changeUnderCursor(const QTextCursor &) const;
+ virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
+ virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const;
+ virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const;
+
+ const QRegExp m_changeNumberPattern8;
+ const QRegExp m_changeNumberPattern40;
+ GitPlugin *m_plugin;
+};
+
+} // namespace Git
+} // namespace Internal
+
+#endif // GITEDITOR_H
diff --git a/src/plugins/git/gitoutputwindow.cpp b/src/plugins/git/gitoutputwindow.cpp
new file mode 100644
index 0000000000..e8210ed035
--- /dev/null
+++ b/src/plugins/git/gitoutputwindow.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitoutputwindow.h"
+
+#include <QtCore/QTextCodec>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+
+using namespace Git::Internal;
+
+GitOutputWindow::GitOutputWindow()
+ : Core::IOutputPane()
+{
+ m_outputListWidget = new QListWidget;
+ m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_outputListWidget->setFrameStyle(QFrame::NoFrame);
+
+ m_outputListWidget->setWindowTitle(tr("Git Output"));
+}
+
+GitOutputWindow::~GitOutputWindow()
+{
+ delete m_outputListWidget;
+}
+
+QWidget *GitOutputWindow::outputWidget(QWidget *parent)
+{
+ m_outputListWidget->setParent(parent);
+ return m_outputListWidget;
+}
+
+QString GitOutputWindow::name() const
+{
+ return tr("Git");
+}
+
+void GitOutputWindow::clearContents()
+{
+ m_outputListWidget->clear();
+}
+
+void GitOutputWindow::visibilityChanged(bool b)
+{
+ if (b)
+ m_outputListWidget->setFocus();
+}
+
+bool GitOutputWindow::hasFocus()
+{
+ return m_outputListWidget->hasFocus();
+}
+
+bool GitOutputWindow::canFocus()
+{
+ return false;
+}
+
+void GitOutputWindow::setFocus()
+{
+}
+
+void GitOutputWindow::setText(const QString &text)
+{
+ clearContents();
+ append(text);
+}
+
+void GitOutputWindow::append(const QString &text)
+{
+ const QStringList lines = text.split(QLatin1Char('\n'));
+ foreach (const QString &s, lines)
+ m_outputListWidget->addItem(s);
+ popup();
+}
+
+void GitOutputWindow::setData(const QByteArray &data)
+{
+ setText(QTextCodec::codecForLocale()->toUnicode(data));
+}
+
+void GitOutputWindow::appendData(const QByteArray &data)
+{
+ append(QTextCodec::codecForLocale()->toUnicode(data));
+}
+
+int GitOutputWindow::priorityInStatusBar() const
+{
+ return -1;
+}
diff --git a/src/plugins/git/gitoutputwindow.h b/src/plugins/git/gitoutputwindow.h
new file mode 100644
index 0000000000..ed776c5df4
--- /dev/null
+++ b/src/plugins/git/gitoutputwindow.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITOUTPUTWINDOW_H
+#define GITOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+#include <QtGui/QListWidgetItem>
+
+namespace Git {
+namespace Internal {
+
+
+class GitOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ GitOutputWindow();
+ ~GitOutputWindow();
+
+ QWidget *outputWidget(QWidget *parent);
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+
+ QString name() const;
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool visible);
+
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+public slots:
+ void setText(const QString &text);
+ void append(const QString &text);
+ void setData(const QByteArray &data);
+ void appendData(const QByteArray &data);
+
+private:
+ QListWidget *m_outputListWidget;
+};
+
+} // namespace Internal
+} // namespace Git
+
+#endif
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
new file mode 100644
index 0000000000..cbb08cc05a
--- /dev/null
+++ b/src/plugins/git/gitplugin.cpp
@@ -0,0 +1,717 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitplugin.h"
+#include "gitclient.h"
+#include "giteditor.h"
+#include "gitconstants.h"
+#include "changeselectiondialog.h"
+#include "gitsubmiteditor.h"
+#include "commitdata.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/basevcssubmiteditorfactory.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDir>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtGui/QFileDialog>
+
+static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
+{
+ VCSBase::RegularCommandOutput,
+ Git::Constants::GIT_COMMAND_LOG_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_git_commandlog",
+ "gitlog"},
+{ VCSBase::LogOutput,
+ Git::Constants::GIT_LOG_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_git_filelog",
+ "gitfilelog"},
+{ VCSBase::AnnotateOutput,
+ Git::Constants::GIT_BLAME_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_git_annotation",
+ "gitsannotate"},
+{ VCSBase::DiffOutput,
+ Git::Constants::GIT_DIFF_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "text/x-patch","diff"}
+};
+
+// Utility to find a parameter set by type
+static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
+{
+ const VCSBase::EditorContentType et = static_cast<VCSBase::EditorContentType>(ie);
+ return VCSBase::VCSBaseEditor::findType(editorParameters, sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters), et);
+}
+
+using namespace Git;
+using namespace Git::Internal;
+
+// CoreListener
+
+bool CoreListener::editorAboutToClose(Core::IEditor *editor)
+{
+ return m_plugin->editorAboutToClose(editor);
+}
+
+// GitPlugin
+
+GitPlugin *GitPlugin::m_instance = 0;
+
+GitPlugin::GitPlugin() :
+ m_core(0),
+ m_diffAction(0),
+ m_diffProjectAction(0),
+ m_statusAction(0),
+ m_statusProjectAction(0),
+ m_logAction(0),
+ m_blameAction(0),
+ m_logProjectAction(0),
+ m_undoFileAction(0),
+ m_undoProjectAction(0),
+ m_showAction(0),
+ m_addAction(0),
+ m_commitAction(0),
+ m_pullAction(0),
+ m_pushAction(0),
+ m_submitCurrentAction(0),
+ m_diffSelectedFilesAction(0),
+ m_undoAction(0),
+ m_redoAction(0),
+ m_projectExplorer(0),
+ m_gitClient(0),
+ m_outputWindow(0),
+ m_changeSelectionDialog(0),
+ m_settingsPage(0),
+ m_coreListener(0),
+ m_submitEditorFactory(0),
+ m_changeTmpFile(0)
+{
+ Q_ASSERT(m_instance == 0);
+ m_instance = this;
+}
+
+GitPlugin::~GitPlugin()
+{
+ if (m_outputWindow) {
+ removeObject(m_outputWindow);
+ delete m_outputWindow;
+ m_outputWindow = 0;
+ }
+
+ if (m_settingsPage) {
+ removeObject(m_settingsPage);
+ delete m_settingsPage;
+ m_settingsPage = 0;
+ }
+
+ if (!m_editorFactories.empty()) {
+ foreach(Core::IEditorFactory* pf, m_editorFactories)
+ removeObject(pf);
+ qDeleteAll(m_editorFactories);
+ }
+
+ if (m_coreListener) {
+ removeObject(m_coreListener);
+ delete m_coreListener;
+ m_coreListener = 0;
+ }
+
+ if (m_submitEditorFactory) {
+ removeObject(m_submitEditorFactory);
+ m_submitEditorFactory = 0;
+ }
+
+ cleanChangeTmpFile();
+ delete m_gitClient;
+ m_instance = 0;
+}
+
+void GitPlugin::cleanChangeTmpFile()
+{
+ if (m_changeTmpFile) {
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ }
+}
+
+GitPlugin *GitPlugin::instance()
+{
+ return m_instance;
+}
+
+static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
+ Git::Constants::SUBMIT_MIMETYPE,
+ Git::Constants::GITSUBMITEDITOR_KIND,
+ Git::Constants::C_GITSUBMITEDITOR,
+ Core::Constants::UNDO,
+ Core::Constants::REDO,
+ Git::Constants::SUBMIT_CURRENT,
+ Git::Constants::DIFF_SELECTED
+};
+
+
+bool GitPlugin::initialize(const QStringList &arguments, QString *error_message)
+{
+ typedef VCSBase::VCSEditorFactory<GitEditor> GitEditorFactory;
+ typedef VCSBase::VCSSubmitEditorFactory<GitSubmitEditor> GitSubmitEditorFactory;
+
+ Q_UNUSED(arguments);
+ Q_UNUSED(error_message);
+
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ m_gitClient = new GitClient(this, m_core);
+ // Create the globalcontext list to register actions accordingly
+ QList<int> globalcontext;
+ globalcontext << m_core->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::C_GLOBAL);
+
+ // Create the output Window
+ m_outputWindow = new GitOutputWindow();
+ addObject(m_outputWindow);
+
+ // Create the settings Page
+ m_settingsPage = new SettingsPage();
+ addObject(m_settingsPage);
+
+ static const char *describeSlot = SLOT(show(QString,QString));
+ const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
+ for (int i = 0; i < editorCount; i++) {
+ m_editorFactories.push_back(new GitEditorFactory(editorParameters + i, m_core, m_gitClient, describeSlot));
+ addObject(m_editorFactories.back());
+ }
+
+ m_coreListener = new CoreListener(this);
+ addObject(m_coreListener);
+
+ m_submitEditorFactory = new GitSubmitEditorFactory(&submitParameters);
+ addObject(m_submitEditorFactory);
+
+ //register actions
+ Core::ActionManagerInterface *actionManager = m_core->actionManager();
+
+ Core::IActionContainer *toolsContainer =
+ actionManager->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *gitContainer =
+ actionManager->createMenu(QLatin1String("Git"));
+ gitContainer->menu()->setTitle(tr("&Git"));
+ toolsContainer->addMenu(gitContainer);
+
+ Core::ICommand *command;
+ QAction *tmpaction;
+
+ m_diffAction = new QAction(tr("Diff current file"), this);
+ command = actionManager->registerAction(m_diffAction, "Git.Diff", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+D")));
+ connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
+ gitContainer->addAction(command);
+
+ m_statusAction = new QAction(tr("File Status"), this);
+ command = actionManager->registerAction(m_statusAction, "Git.Status", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+S")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_statusAction, SIGNAL(triggered()), this, SLOT(statusFile()));
+ gitContainer->addAction(command);
+
+ m_logAction = new QAction(tr("Log File"), this);
+ command = actionManager->registerAction(m_logAction, "Git.Log", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+L")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_logAction, SIGNAL(triggered()), this, SLOT(logFile()));
+ gitContainer->addAction(command);
+
+ m_blameAction = new QAction(tr("Blame"), this);
+ command = actionManager->registerAction(m_blameAction, "Git.Blame", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+B")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_blameAction, SIGNAL(triggered()), this, SLOT(blameFile()));
+ gitContainer->addAction(command);
+
+ m_undoFileAction = new QAction(tr("Undo Changes"), this);
+ command = actionManager->registerAction(m_undoFileAction, "Git.Undo", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+U")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_undoFileAction, SIGNAL(triggered()), this, SLOT(undoFileChanges()));
+ gitContainer->addAction(command);
+
+ m_addAction = new QAction(tr("Add File"), this);
+ command = actionManager->registerAction(m_addAction, "Git.Add", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+A")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_addAction, SIGNAL(triggered()), this, SLOT(addFile()));
+ gitContainer->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = actionManager->registerAction(tmpaction, QLatin1String("Git.Sep.Project"), globalcontext);
+ gitContainer->addAction(command);
+
+ m_diffProjectAction = new QAction(tr("Diff current project"), this);
+ command = actionManager->registerAction(m_diffProjectAction, "Git.DiffProject", globalcontext);
+ command->setDefaultKeySequence(QKeySequence("Alt+G,Alt+Shift+D"));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject()));
+ gitContainer->addAction(command);
+
+ m_statusProjectAction = new QAction(tr("Project status"), this);
+ command = actionManager->registerAction(m_statusProjectAction, "Git.StatusProject", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(statusProject()));
+ gitContainer->addAction(command);
+
+ m_logProjectAction = new QAction(tr("Log project"), this);
+ command = actionManager->registerAction(m_logProjectAction, "Git.LogProject", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+K")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_logProjectAction, SIGNAL(triggered()), this, SLOT(logProject()));
+ gitContainer->addAction(command);
+
+ m_undoProjectAction = new QAction(tr("Undo Project Changes"), this);
+ command = actionManager->registerAction(m_undoProjectAction, "Git.UndoProject", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_undoProjectAction, SIGNAL(triggered()), this, SLOT(undoProjectChanges()));
+ gitContainer->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = actionManager->registerAction(tmpaction, QLatin1String("Git.Sep.Global"), globalcontext);
+ gitContainer->addAction(command);
+
+ m_showAction = new QAction(tr("Show commit..."), this);
+ command = actionManager->registerAction(m_showAction, "Git.ShowCommit", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_showAction, SIGNAL(triggered()), this, SLOT(showCommit()));
+ gitContainer->addAction(command);
+
+ m_commitAction = new QAction(tr("Commit..."), this);
+ command = actionManager->registerAction(m_commitAction, "Git.Commit", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+C")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_commitAction, SIGNAL(triggered()), this, SLOT(startCommit()));
+ gitContainer->addAction(command);
+
+ m_pullAction = new QAction(tr("Pull"), this);
+ command = actionManager->registerAction(m_pullAction, "Git.Pull", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_pullAction, SIGNAL(triggered()), this, SLOT(pull()));
+ gitContainer->addAction(command);
+
+ m_pushAction = new QAction(tr("Push"), this);
+ command = actionManager->registerAction(m_pushAction, "Git.Push", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_pushAction, SIGNAL(triggered()), this, SLOT(push()));
+ gitContainer->addAction(command);
+
+ // Submit editor
+ QList<int> submitContext;
+ submitContext.push_back(m_core->uniqueIDManager()->uniqueIdentifier(QLatin1String(Constants::C_GITSUBMITEDITOR)));
+ m_submitCurrentAction = new QAction(QIcon(Constants::ICON_SUBMIT), tr("Commit"), this);
+ command = actionManager->registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext);
+ // TODO
+ connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
+
+ m_diffSelectedFilesAction = new QAction(QIcon(Constants::ICON_DIFF), tr("Diff Selected Files"), this);
+ command = actionManager->registerAction(m_diffSelectedFilesAction, Constants::DIFF_SELECTED, submitContext);
+
+ m_undoAction = new QAction(tr("&Undo"), this);
+ command = actionManager->registerAction(m_undoAction, Core::Constants::UNDO, submitContext);
+
+ m_redoAction = new QAction(tr("&Redo"), this);
+ command = actionManager->registerAction(m_redoAction, Core::Constants::REDO, submitContext);
+
+ // Ask for updates of our actions, in case context switches
+ connect(m_core, SIGNAL(contextChanged(Core::IContext *)),
+ this, SLOT(updateActions()));
+ connect(m_core->fileManager(), SIGNAL(currentFileChanged(const QString &)),
+ this, SLOT(updateActions()));
+
+ return true;
+}
+
+void GitPlugin::extensionsInitialized()
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+}
+
+bool GitPlugin::vcsOpen(const QString &fileName)
+{
+ Q_UNUSED(fileName);
+ return false;
+}
+
+void GitPlugin::submitEditorDiff(const QStringList &files)
+{
+ if (files.empty())
+ return;
+ m_gitClient->diff(m_submitRepository, files);
+}
+
+void GitPlugin::diffCurrentFile()
+{
+ QFileInfo fileInfo = currentFile();
+ QString fileName = fileInfo.fileName();
+ QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->diff(workingDirectory, fileName);
+}
+
+void GitPlugin::diffCurrentProject()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->diff(workingDirectory, QString());
+}
+
+QFileInfo GitPlugin::currentFile()
+{
+ QString fileName = m_core->fileManager()->currentFile();
+ QFileInfo fileInfo(fileName);
+ return fileInfo;
+}
+
+QString GitPlugin::getWorkingDirectory()
+{
+ QString workingDirectory;
+ if (m_projectExplorer && m_projectExplorer->currentNode()) {
+ workingDirectory = QFileInfo(m_projectExplorer->currentNode()->path()).absolutePath();
+ }
+ if (Git::Constants::debug > 1)
+ qDebug() << Q_FUNC_INFO << "Project" << workingDirectory;
+
+ if (workingDirectory.isEmpty())
+ workingDirectory = QFileInfo(m_core->fileManager()->currentFile()).absolutePath();
+ if (Git::Constants::debug > 1)
+ qDebug() << Q_FUNC_INFO << "file" << workingDirectory;
+
+ if (workingDirectory.isEmpty()) {
+ m_outputWindow->clearContents();
+ m_outputWindow->append(tr("Could not find working directory"));
+ m_outputWindow->popup();
+ return QString();
+ }
+ return workingDirectory;
+}
+
+void GitPlugin::statusProject()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->status(workingDirectory);
+}
+
+void GitPlugin::statusFile()
+{
+ m_gitClient->status(currentFile().absolutePath());
+}
+
+void GitPlugin::logFile()
+{
+ const QFileInfo fileInfo = currentFile();
+ const QString fileName = fileInfo.fileName();
+ const QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->log(workingDirectory, fileName);
+}
+
+void GitPlugin::blameFile()
+{
+ const QFileInfo fileInfo = currentFile();
+ const QString fileName = fileInfo.fileName();
+ const QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->blame(workingDirectory, fileName);
+}
+
+void GitPlugin::logProject()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->log(workingDirectory, QString());
+}
+
+void GitPlugin::undoFileChanges()
+{
+ QFileInfo fileInfo = currentFile();
+ QString fileName = fileInfo.fileName();
+ QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->checkout(workingDirectory, fileName);
+}
+
+void GitPlugin::undoProjectChanges()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->hardReset(workingDirectory, QString());
+}
+
+void GitPlugin::addFile()
+{
+ QFileInfo fileInfo = currentFile();
+ QString fileName = fileInfo.fileName();
+ QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->addFile(workingDirectory, fileName);
+}
+
+void GitPlugin::startCommit()
+{
+ if (m_changeTmpFile) {
+ m_outputWindow->append(tr("Another submit is currently beeing executed."));
+ m_outputWindow->popup(false);
+ return;
+ }
+
+ // Find repository and get commit data
+ const QFileInfo currentFileInfo = currentFile();
+ if (!currentFileInfo.exists())
+ return;
+
+ const QString workingDirectory = currentFileInfo.absolutePath();
+ QString errorMessage, commitTemplate;
+ CommitData data;
+ if (!m_gitClient->getCommitData(workingDirectory, &commitTemplate, &data, &errorMessage)) {
+ m_outputWindow->append(errorMessage);
+ m_outputWindow->popup(false);
+ return;
+ }
+
+ m_submitRepository = data.panelInfo.repository;
+
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << data << commitTemplate;
+
+ // Start new temp file with message template
+ QTemporaryFile *changeTmpFile = new QTemporaryFile(this);
+ changeTmpFile->setAutoRemove(true);
+ if (!changeTmpFile->open()) {
+ m_outputWindow->append(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
+ delete changeTmpFile;
+ return;
+ }
+ m_changeTmpFile = changeTmpFile;
+ m_changeTmpFile->write(commitTemplate.toLocal8Bit());
+ m_changeTmpFile->flush();
+ // Keep the file alive, else it removes self and forgets
+ // its name
+ m_changeTmpFile->seek(0);
+ openSubmitEditor(m_changeTmpFile->fileName(), data);
+}
+
+Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const CommitData &cd)
+{
+ Core::IEditor *editor = m_core->editorManager()->openEditor(fileName, QLatin1String(Constants::GITSUBMITEDITOR_KIND));
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << fileName << editor;
+ m_core->editorManager()->ensureEditorManagerVisible();
+ GitSubmitEditor *submitEditor = qobject_cast<GitSubmitEditor*>(editor);
+ Q_ASSERT(submitEditor);
+ // The actions are for some reason enabled by the context switching
+ // mechanism. Disable them correctly.
+ m_submitCurrentAction->setEnabled(!cd.commitFiles.empty());
+ m_diffSelectedFilesAction->setEnabled(false);
+ m_undoAction->setEnabled(false);
+ m_redoAction->setEnabled(false);
+ submitEditor->setCommitData(cd);
+ connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(submitEditorDiff(QStringList)));
+ return editor;
+}
+
+void GitPlugin::submitCurrentLog()
+{
+ // Close the submit editor
+ QList<Core::IEditor*> editors;
+ editors.push_back(m_core->editorManager()->currentEditor());
+ m_core->editorManager()->closeEditors(editors);
+}
+
+bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor)
+{
+ // Closing a submit editor?
+ if (!m_changeTmpFile || !iEditor || qstrcmp(iEditor->kind(), Constants::GITSUBMITEDITOR_KIND))
+ return true;
+ Core::IFile *fileIFace = iEditor->file();
+ const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(iEditor);
+ if (!fileIFace || !editor)
+ return true;
+ // Submit editor closing. Make it write out the commit message
+ // and retrieve files
+ const QFileInfo editorFile(fileIFace->fileName());
+ const QFileInfo changeFile(m_changeTmpFile->fileName());
+ // Paranoia!
+ if (editorFile.absoluteFilePath() != changeFile.absoluteFilePath())
+ return true;
+ // Prompt user.
+ const QMessageBox::StandardButton answer = QMessageBox::question(m_core->mainWindow(), tr("Closing git editor"), tr("Do you want to commit the change?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ switch (answer) {
+ case QMessageBox::Cancel:
+ return false; // Keep editing and change file
+ case QMessageBox::No:
+ cleanChangeTmpFile();
+ return true; // Cancel all
+ default:
+ break;
+ }
+ // Go ahead!
+ const QStringList fileList = editor->checkedFiles();
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << fileList;
+ if (!fileList.empty()) {
+ // get message & commit
+ m_core->fileManager()->blockFileChange(fileIFace);
+ fileIFace->save();
+ m_core->fileManager()->unblockFileChange(fileIFace);
+
+ m_gitClient->addAndCommit(m_submitRepository,
+ editor->panelData(),
+ m_changeTmpFile->fileName(),
+ fileList);
+ }
+ cleanChangeTmpFile();
+ return true;
+}
+
+void GitPlugin::pull()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->pull(workingDirectory);
+}
+
+void GitPlugin::push()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->push(workingDirectory);
+}
+
+void GitPlugin::updateActions()
+{
+ QFileInfo current = currentFile();
+ const QString fileName = current.fileName();
+ const QString currentDirectory = getWorkingDirectory();
+ QString repository = m_gitClient->findRepositoryForFile(current.absoluteFilePath());
+ // First check for file commands and if the current file is inside
+ // a Git-repository
+ m_diffAction->setText(tr("Diff %1").arg(fileName));
+ m_statusAction->setText(tr("Status related to %1").arg(fileName));
+ m_logAction->setText(tr("Log %1").arg(fileName));
+ m_blameAction->setText(tr("Blame %1").arg(fileName));
+ m_undoFileAction->setText(tr("Undo changes for %1").arg(fileName));
+ m_addAction->setText(tr("Add %1").arg(fileName));
+ if (repository.isEmpty()) {
+ // If the file is not in a repository, the corresponding project will
+ // be neither and we can disable everything and return
+ m_diffAction->setEnabled(false);
+ m_statusAction->setEnabled(false);
+ m_logAction->setEnabled(false);
+ m_blameAction->setEnabled(false);
+ m_undoFileAction->setEnabled(false);
+ m_addAction->setEnabled(false);
+ m_diffProjectAction->setEnabled(false);
+ m_diffProjectAction->setText(tr("Diff Project"));
+ m_statusProjectAction->setText(tr("Status Project"));
+ m_statusProjectAction->setEnabled(false);
+ m_logProjectAction->setText(tr("Log Project"));
+ m_logProjectAction->setEnabled(false);
+ return;
+ } else {
+ // We only know the file is in some repository, we do not know
+ // anything about any project so far.
+ m_diffAction->setEnabled(true);
+ m_statusAction->setEnabled(true);
+ m_logAction->setEnabled(true);
+ m_blameAction->setEnabled(true);
+ m_undoFileAction->setEnabled(true);
+ m_addAction->setEnabled(true);
+ }
+
+ if (m_projectExplorer && m_projectExplorer->currentNode()
+ && m_projectExplorer->currentNode()->projectNode()) {
+ QString name = QFileInfo(m_projectExplorer->currentNode()->projectNode()->path()).baseName();
+ m_diffProjectAction->setEnabled(true);
+ m_diffProjectAction->setText(tr("Diff Project %1").arg(name));
+ m_statusProjectAction->setEnabled(true);
+ m_statusProjectAction->setText(tr("Status Project %1").arg(name));
+ m_logProjectAction->setEnabled(true);
+ m_logProjectAction->setText(tr("Log Project %1").arg(name));
+ } else {
+ m_diffProjectAction->setEnabled(false);
+ m_diffProjectAction->setText(tr("Diff Project"));
+ m_statusProjectAction->setEnabled(false);
+ m_statusProjectAction->setText(tr("Status Project"));
+ m_logProjectAction->setEnabled(false);
+ m_logProjectAction->setText(tr("Log Project"));
+ }
+}
+
+void GitPlugin::showCommit()
+{
+ if (!m_changeSelectionDialog)
+ m_changeSelectionDialog = new ChangeSelectionDialog();
+
+ const QFileInfo currentInfo = currentFile();
+ QString repositoryLocation = m_gitClient->findRepositoryForFile(currentInfo.absoluteFilePath());
+ if (!repositoryLocation.isEmpty())
+ m_changeSelectionDialog->m_ui.repositoryEdit->setText(repositoryLocation);
+
+ if (m_changeSelectionDialog->exec() != QDialog::Accepted)
+ return;
+ const QString change = m_changeSelectionDialog->m_ui.changeNumberEdit->text();
+ if (change .isEmpty())
+ return;
+
+ m_gitClient->show(m_changeSelectionDialog->m_ui.repositoryEdit->text(), change);
+}
+
+Q_EXPORT_PLUGIN(GitPlugin)
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
new file mode 100644
index 0000000000..c57c380fcf
--- /dev/null
+++ b/src/plugins/git/gitplugin.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITPLUGIN_H
+#define GITPLUGIN_H
+
+#include "gitoutputwindow.h"
+#include "settingspage.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/icorelistener.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QAction;
+class QTemporaryFile;
+QT_END_NAMESPACE
+
+namespace Core {
+ class IEditorFactory;
+ class ICore;
+}
+
+namespace Git {
+namespace Internal {
+
+ class GitPlugin;
+ class GitClient;
+ class ChangeSelectionDialog;
+ class GitSubmitEditor;
+ struct CommitData;
+
+// Just a proxy for GitPlugin
+class CoreListener : public Core::ICoreListener
+{
+ Q_OBJECT
+public:
+ CoreListener(GitPlugin *plugin) : m_plugin(plugin) { }
+ bool editorAboutToClose(Core::IEditor *editor);
+ bool coreAboutToClose() { return true; }
+private:
+ GitPlugin *m_plugin;
+};
+
+class GitPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ GitPlugin();
+ ~GitPlugin();
+ static GitPlugin *instance();
+
+ bool vcsOpen(const QString &fileName);
+
+ bool initialize(const QStringList &arguments
+ , QString *error_message);
+ void extensionsInitialized();
+
+ QString getWorkingDirectory();
+
+public slots:
+ void updateActions();
+ bool editorAboutToClose(Core::IEditor *editor);
+
+private slots:
+ void diffCurrentFile();
+ void diffCurrentProject();
+ void submitEditorDiff(const QStringList &);
+ void submitCurrentLog();
+ void statusFile();
+ void statusProject();
+ void logFile();
+ void blameFile();
+ void logProject();
+ void undoFileChanges();
+ void undoProjectChanges();
+ void addFile();
+
+ void showCommit();
+ void startCommit();
+ void pull();
+ void push();
+
+private:
+ friend class GitClient;
+ QFileInfo currentFile();
+ Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd);
+ void cleanChangeTmpFile();
+
+ static GitPlugin *m_instance;
+ Core::ICore *m_core;
+ QAction *m_diffAction;
+ QAction *m_diffProjectAction;
+ QAction *m_statusAction;
+ QAction *m_statusProjectAction;
+ QAction *m_logAction;
+ QAction *m_blameAction;
+ QAction *m_logProjectAction;
+ QAction *m_undoFileAction;
+ QAction *m_undoProjectAction;
+ QAction *m_showAction;
+ QAction *m_addAction;
+ QAction *m_commitAction;
+ QAction *m_pullAction;
+ QAction *m_pushAction;
+
+ QAction *m_submitCurrentAction;
+ QAction *m_diffSelectedFilesAction;
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ GitClient *m_gitClient;
+ GitOutputWindow *m_outputWindow;
+ ChangeSelectionDialog *m_changeSelectionDialog;
+ SettingsPage *m_settingsPage;
+ QList<Core::IEditorFactory*> m_editorFactories;
+ CoreListener *m_coreListener;
+ Core::IEditorFactory *m_submitEditorFactory;
+ QString m_submitRepository;
+ QTemporaryFile *m_changeTmpFile;
+};
+
+} // namespace Git
+} // namespace Internal
+
+#endif
diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp
new file mode 100644
index 0000000000..bf0d78af57
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditor.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitsubmiteditor.h"
+#include "gitsubmiteditorwidget.h"
+#include "gitconstants.h"
+#include "commitdata.h"
+
+#include <QtCore/QDebug>
+
+namespace Git {
+namespace Internal {
+
+GitSubmitEditor::GitSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent) :
+ VCSBaseSubmitEditor(parameters, new GitSubmitEditorWidget(parent))
+{
+ setDisplayName(tr("Git Commit"));
+}
+
+GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget()
+{
+ return static_cast<GitSubmitEditorWidget *>(widget());
+}
+
+QStringList GitSubmitEditor::vcsFileListToFileList(const QStringList &rawList) const
+{
+ QStringList rc;
+ foreach (const QString &rf, rawList)
+ rc.push_back(fileFromChangeLine(rf));
+ return rc;
+}
+
+void GitSubmitEditor::setCommitData(const CommitData &d)
+{
+ submitEditorWidget()->setPanelData(d.panelData);
+ submitEditorWidget()->setPanelInfo(d.panelInfo);
+
+ // Commited: Checked, user cannot uncheck
+ addFiles(d.commitFiles, true, false);
+ // Not Updated: User can check
+ addFiles(d.notUpdatedFiles, false, true);
+ addFiles(d.untrackedFiles, false, true);
+}
+
+GitSubmitEditorPanelData GitSubmitEditor::panelData() const
+{
+ return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData();
+}
+
+QString GitSubmitEditor::fileFromChangeLine(const QString &line)
+{
+ QString rc = line;
+ // "modified: mainwindow.cpp"
+ const int index = rc.indexOf(QLatin1Char(':'));
+ if (index != -1)
+ rc.remove(0, index + 1);
+ const QChar blank(' ');
+ while (rc.startsWith(blank))
+ rc.remove(0, 1);
+ return rc;
+}
+}
+}
diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h
new file mode 100644
index 0000000000..b424361a6a
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditor.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITSUBMITEDITOR_H
+#define GITSUBMITEDITOR_H
+
+#include <vcsbase/vcsbasesubmiteditor.h>
+
+namespace Git {
+namespace Internal {
+
+class GitSubmitEditorWidget;
+struct CommitData;
+struct GitSubmitEditorPanelData;
+
+/* */
+class GitSubmitEditor : public VCSBase::VCSBaseSubmitEditor
+{
+ Q_OBJECT
+public:
+ explicit GitSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent);
+
+ void setCommitData(const CommitData &);
+ GitSubmitEditorPanelData panelData() const;
+
+ static QString fileFromChangeLine(const QString &line);
+
+protected:
+ virtual QStringList vcsFileListToFileList(const QStringList &) const;
+
+private:
+ inline GitSubmitEditorWidget *submitEditorWidget();
+};
+
+} // namespace Internal
+} // namespace Git
+
+#endif // GITSUBMITEDITOR_H
diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp
new file mode 100644
index 0000000000..aede10acd8
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditorwidget.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitsubmiteditorwidget.h"
+#include "commitdata.h"
+
+namespace Git {
+namespace Internal {
+
+GitSubmitEditorWidget::GitSubmitEditorWidget(QWidget *parent) :
+ Core::Utils::SubmitEditorWidget(parent),
+ m_gitSubmitPanel(new QWidget)
+{
+ m_gitSubmitPanelUi.setupUi(m_gitSubmitPanel);
+ insertTopWidget(m_gitSubmitPanel);
+}
+
+void GitSubmitEditorWidget::setPanelInfo(const GitSubmitEditorPanelInfo &info)
+{
+ m_gitSubmitPanelUi.repositoryLabel->setText(info.repository);
+ m_gitSubmitPanelUi.descriptionLabel->setText(info.description);
+ m_gitSubmitPanelUi.branchLabel->setText(info.branch);
+}
+
+GitSubmitEditorPanelData GitSubmitEditorWidget::panelData() const
+{
+ GitSubmitEditorPanelData rc;
+ rc.author = m_gitSubmitPanelUi.authorLineEdit->text();
+ rc.email = m_gitSubmitPanelUi.emailLineEdit->text();
+ return rc;
+};
+
+void GitSubmitEditorWidget::setPanelData(const GitSubmitEditorPanelData &data)
+{
+ m_gitSubmitPanelUi.authorLineEdit->setText(data.author);
+ m_gitSubmitPanelUi.emailLineEdit->setText(data.email);
+}
+
+}
+}
diff --git a/src/plugins/git/gitsubmiteditorwidget.h b/src/plugins/git/gitsubmiteditorwidget.h
new file mode 100644
index 0000000000..7a842f50ef
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditorwidget.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITSUBMITEDITORWIDGET_H
+#define GITSUBMITEDITORWIDGET_H
+
+#include "ui_gitsubmitpanel.h"
+#include <utils/submiteditorwidget.h>
+
+namespace Git {
+namespace Internal {
+
+struct GitSubmitEditorPanelInfo;
+struct GitSubmitEditorPanelData;
+
+/* Submit editor widget with 2 additional panes:
+ * 1) Info with branch, description, etc
+ * 2) Data, with author and email to edit.
+ * The file contents is the submit message.
+ * The previously added files will be added 'checked' to the file list, the
+ * remaining un-added and untracked files will be added 'unchecked' for the
+ * user to click. */
+
+class GitSubmitEditorWidget : public Core::Utils::SubmitEditorWidget
+{
+
+public:
+ explicit GitSubmitEditorWidget(QWidget *parent = 0);
+
+
+ GitSubmitEditorPanelData panelData() const;
+ void setPanelData(const GitSubmitEditorPanelData &data);
+
+ void setPanelInfo(const GitSubmitEditorPanelInfo &info);
+
+private:
+ QWidget *m_gitSubmitPanel;
+ Ui::GitSubmitPanel m_gitSubmitPanelUi;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // GITSUBMITEDITORWIDGET_H
diff --git a/src/plugins/git/gitsubmitpanel.ui b/src/plugins/git/gitsubmitpanel.ui
new file mode 100644
index 0000000000..8a42052a99
--- /dev/null
+++ b/src/plugins/git/gitsubmitpanel.ui
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Git::Internal::GitSubmitPanel</class>
+ <widget class="QWidget" name="Git::Internal::GitSubmitPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>201</width>
+ <height>210</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="infoGroup">
+ <property name="title">
+ <string>General Information</string>
+ </property>
+ <layout class="QFormLayout" name="infoFormLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="repositoryLabelLabel">
+ <property name="text">
+ <string>Repository:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="repositoryLabel">
+ <property name="text">
+ <string>repository</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="descriptionLabelLabel">
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>description</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="branchLabelLabel">
+ <property name="text">
+ <string>Branch:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="branchLabel">
+ <property name="text">
+ <string>branch</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="editGroup">
+ <property name="title">
+ <string>Commit Information</string>
+ </property>
+ <layout class="QFormLayout" name="editFormLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="authorLabel">
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="authorLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="emailLabel">
+ <property name="text">
+ <string>Email:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="emailLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp
new file mode 100644
index 0000000000..90f6371c0a
--- /dev/null
+++ b/src/plugins/git/settingspage.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QSettings>
+#include <QtGui/QLineEdit>
+#include <QtGui/QFileDialog>
+#include <QtCore/QDebug>
+
+using namespace Git::Internal;
+
+static const char *groupC = "Git";
+static const char *sysEnvKeyC = "SysEnv";
+static const char *pathKeyC = "Path";
+static const char *logCountKeyC = "LogCount";
+
+SettingsPage::SettingsPage()
+{
+ Core::ICore *coreIFace = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (coreIFace)
+ m_settings = coreIFace->settings();
+
+ if (m_settings) {
+ m_settings->beginGroup(QLatin1String(groupC));
+ m_adopt = m_settings->value(QLatin1String(sysEnvKeyC), true).toBool();
+ m_path = m_settings->value(QLatin1String(pathKeyC), QString()).toString();
+ m_logCount = m_settings->value(QLatin1String(logCountKeyC), 10).toInt();
+ m_settings->endGroup();
+ }
+}
+
+QString SettingsPage::name() const
+{
+ return tr("General");
+}
+
+QString SettingsPage::category() const
+{
+ return QLatin1String("Git");
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("Git");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+ m_ui.adoptCheckBox->setChecked(m_adopt);
+ m_ui.pathLineEdit->setText(m_path);
+ m_ui.logLineEdit->setText(QString::number(m_logCount));
+
+ connect(m_ui.adoptButton, SIGNAL(clicked()), this, SLOT(setSystemPath()));
+ return w;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_adopt = m_ui.adoptCheckBox->isChecked();
+ m_path = m_ui.pathLineEdit->text();
+ m_logCount = m_ui.logLineEdit->text().toInt();
+
+ if (!m_settings)
+ return;
+
+ m_settings->beginGroup(QLatin1String(groupC));
+ m_settings->setValue(QLatin1String(sysEnvKeyC), m_adopt);
+ m_settings->setValue(QLatin1String(pathKeyC), m_path);
+ m_settings->setValue(QLatin1String(logCountKeyC), m_logCount);
+ m_settings->endGroup();
+}
+
+void SettingsPage::setSystemPath()
+{
+ m_path = qgetenv("PATH");
+ m_ui.pathLineEdit->setText(m_path);
+}
diff --git a/src/plugins/git/settingspage.h b/src/plugins/git/settingspage.h
new file mode 100644
index 0000000000..de627bd9ce
--- /dev/null
+++ b/src/plugins/git/settingspage.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSPAGE_H
+#define SETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_settingspage.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Git {
+namespace Internal {
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ bool adoptEnvironment() const { return m_adopt; }
+ int logCount() const { return m_logCount; }
+ QString path() const { return m_path; }
+
+private slots:
+ void setSystemPath();
+
+private:
+ Ui_SettingsPage m_ui;
+ QSettings *m_settings;
+
+ bool m_adopt;
+ QString m_path;
+ int m_logCount;
+};
+
+} //namespace Internal
+} //namespace Git
+
+#endif
diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui
new file mode 100644
index 0000000000..738413e676
--- /dev/null
+++ b/src/plugins/git/settingspage.ui
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Git::Internal::SettingsPage</class>
+ <widget class="QWidget" name="Git::Internal::SettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>345</width>
+ <height>177</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="adoptCheckBox">
+ <property name="text">
+ <string>Use System Environment</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Environment variables</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>PATH:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="pathLineEdit"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="adoptButton">
+ <property name="text">
+ <string>Adopt</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>52</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt; font-weight:600;&quot;&gt;Note&lt;/span&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; that Git needs Perl in the environment as well&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Commit display count:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="logLineEdit">
+ <property name="toolTip">
+ <string>Note that huge amount of commits might take some time.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>pathLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>adoptCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>groupBox</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>144</x>
+ <y>33</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>139</x>
+ <y>65</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/helloworld/HelloWorld.pluginspec b/src/plugins/helloworld/HelloWorld.pluginspec
new file mode 100644
index 0000000000..9cd262ca4d
--- /dev/null
+++ b/src/plugins/helloworld/HelloWorld.pluginspec
@@ -0,0 +1,10 @@
+<plugin name="HelloWorld" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Hello World sample plugin.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/helloworld/helloworld.pro b/src/plugins/helloworld/helloworld.pro
new file mode 100644
index 0000000000..19be467b0f
--- /dev/null
+++ b/src/plugins/helloworld/helloworld.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+TARGET = HelloWorld
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+
+HEADERS += helloworldplugin.h \
+ helloworldwindow.h
+
+SOURCES += helloworldplugin.cpp \
+ helloworldwindow.cpp
+
diff --git a/src/plugins/helloworld/helloworldplugin.cpp b/src/plugins/helloworld/helloworldplugin.cpp
new file mode 100644
index 0000000000..ad7bf48fee
--- /dev/null
+++ b/src/plugins/helloworld/helloworldplugin.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helloworldplugin.h"
+
+#include "helloworldwindow.h"
+
+#include <coreplugin/modemanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/qplugin.h>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+
+#include <coreplugin/CoreTools>
+
+#include "helloworldplugin.h"
+
+using namespace HelloWorld::Internal;
+
+/*! Constructs the Hello World plugin. Normally plugins don't do anything in
+ their constructor except for initializing their member variables. The
+ actual work is done later, in the initialize() and extensionsInitialized()
+ methods.
+*/
+HelloWorldPlugin::HelloWorldPlugin()
+{
+}
+
+/*! Plugins are responsible for deleting objects they created on the heap, and
+ to unregister objects from the plugin manager that they registered there.
+*/
+HelloWorldPlugin::~HelloWorldPlugin()
+{
+}
+
+/*! Initializes the plugin. Returns true on success.
+ Plugins want to register objects with the plugin manager here.
+
+ \a error_message can be used to pass an error message to the plugin system,
+ if there was any.
+*/
+bool HelloWorldPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+ Q_UNUSED(error_message)
+
+ // Get the primary access point to the workbench.
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ // Create our own widget that we want to show in a view in the IDE.
+ HelloWorldWindow *window = new HelloWorldWindow;
+
+ // Create a unique context id for our own view, that will be used for the
+ // menu entry later.
+ QList<int> context = QList<int>()
+ << core->uniqueIDManager()->uniqueIdentifier(
+ QLatin1String("HelloWorld.MainView"));
+
+ // Create a new view that contains our widget and register it with the
+ // plugin manager. The view will have the id "HelloWorld.HelloWorldWindow",
+ // and if it has focus it provides 'context' to the context list in
+ // Qt Creator. It will be put into the right dock widget area.
+ addAutoReleasedObject(new Core::BaseView("HelloWorld.HelloWorldWindow",
+ window, context,
+ Qt::RightDockWidgetArea));
+
+ // Create an action to be triggered by a menu entry
+ QAction *helloWorldAction = new QAction("Say \"&Hello World!\"", this);
+ connect(helloWorldAction, SIGNAL(triggered()), SLOT(sayHelloWorld()));
+
+ // Register the action with the action manager
+ Core::ActionManagerInterface *actionManager = core->actionManager();
+ Core::ICommand *command =
+ actionManager->registerAction(
+ helloWorldAction, "HelloWorld.HelloWorldAction", context);
+
+ // Create our own menu to place in the Tools menu
+ Core::IActionContainer *helloWorldMenu =
+ actionManager->createMenu("HelloWorld.HelloWorldMenu");
+ QMenu *menu = helloWorldMenu->menu();
+ menu->setTitle(tr("&Hello World"));
+ menu->setEnabled(true);
+
+ // Add the Hello World action command to the menu
+ helloWorldMenu->addAction(command);
+
+ // Request the Tools menu and add the Hello World menu to it
+ Core::IActionContainer *toolsMenu =
+ actionManager->actionContainer(Core::Constants::M_TOOLS);
+ toolsMenu->addMenu(helloWorldMenu);
+
+ // Add a mode with a push button based on BaseMode. Like the BaseView, it will unregister
+ // itself from the plugin manager when it is deleted.
+ addAutoReleasedObject(new Core::BaseMode(tr("Hello world!"),
+ "HelloWorld.HelloWorldMode",
+ QIcon(),
+ 0, // priority
+ new QPushButton(tr("Hello World PushButton!"))));
+
+ // Add the Hello World action command to the mode manager (with 0 priority)
+ Core::ModeManager *modeManager = core->modeManager();
+ modeManager->addAction(command, 0);
+
+ return true;
+}
+
+/*! Notification that all extensions that this plugin depends on have been
+ initialized. The dependencies are defined in the plugins .qwp file.
+
+ Normally this method is used for things that rely on other plugins to have
+ added objects to the plugin manager, that implement interfaces that we're
+ interested in. These objects can now be requested through the
+ PluginManagerInterface.
+
+ The HelloWorldPlugin doesn't need things from other plugins, so it does
+ nothing here.
+*/
+void HelloWorldPlugin::extensionsInitialized()
+{
+}
+
+void HelloWorldPlugin::sayHelloWorld()
+{
+ // When passing 0 for the parent, the message box becomes an
+ // application-global modal dialog box
+ QMessageBox::information(
+ 0, "Hello World!", "Hello World! Beautiful day today, isn't it?");
+}
+
+Q_EXPORT_PLUGIN(HelloWorldPlugin)
diff --git a/src/plugins/helloworld/helloworldplugin.h b/src/plugins/helloworld/helloworldplugin.h
new file mode 100644
index 0000000000..3e73e6ae8f
--- /dev/null
+++ b/src/plugins/helloworld/helloworldplugin.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELLOWORLDPLUGIN_H
+#define HELLOWORLDPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace HelloWorld {
+namespace Internal {
+
+class HelloWorldPlugin
+ : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ HelloWorldPlugin();
+ ~HelloWorldPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+
+ void extensionsInitialized();
+
+private slots:
+ void sayHelloWorld();
+
+private:
+};
+
+} // namespace Internal
+} // namespace HelloWorld
+
+#endif //HELLOWORLDPLUGIN_H
diff --git a/src/plugins/helloworld/helloworldwindow.cpp b/src/plugins/helloworld/helloworldwindow.cpp
new file mode 100644
index 0000000000..66a1b3d224
--- /dev/null
+++ b/src/plugins/helloworld/helloworldwindow.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QTextEdit>
+#include <QtGui/QVBoxLayout>
+
+#include "helloworldwindow.h"
+
+using namespace HelloWorld::Internal;
+
+HelloWorldWindow::HelloWorldWindow(QWidget *parent)
+ :QWidget(parent)
+{
+ QBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(new QTextEdit("Focus me to activate my context!"));
+ setWindowTitle(tr("Hello, world!"));
+}
diff --git a/src/plugins/helloworld/helloworldwindow.h b/src/plugins/helloworld/helloworldwindow.h
new file mode 100644
index 0000000000..8d02923a2e
--- /dev/null
+++ b/src/plugins/helloworld/helloworldwindow.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELLOWORLDWINDOW_H
+#define HELLOWORLDWINDOW_H
+
+#include <QtGui/QWidget>
+
+QT_FORWARD_DECLARE_CLASS(QLabel);
+
+namespace HelloWorld {
+namespace Internal {
+
+class HelloWorldWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ HelloWorldWindow(QWidget *parent = 0);
+};
+
+} // namespace Internal
+} // namespace HelloWorld
+
+#endif // HELLOWORLDWINDOW_H
diff --git a/src/plugins/help/Help.pluginspec b/src/plugins/help/Help.pluginspec
new file mode 100644
index 0000000000..b60b320827
--- /dev/null
+++ b/src/plugins/help/Help.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="Help" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Help system.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="Find" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/help/centralwidget.cpp b/src/plugins/help/centralwidget.cpp
new file mode 100644
index 0000000000..6c63c28b1e
--- /dev/null
+++ b/src/plugins/help/centralwidget.cpp
@@ -0,0 +1,687 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "centralwidget.h"
+#include "helpviewer.h"
+#include "topicchooser.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QEvent>
+#include <QtCore/QTimer>
+
+#include <QtGui/QMenu>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QPrinter>
+#include <QtGui/QLineEdit>
+#include <QtGui/QCheckBox>
+#include <QtGui/QTabBar>
+#include <QtGui/QTabWidget>
+#include <QtGui/QToolButton>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QMainWindow>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QTextCursor>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QApplication>
+#include <QtGui/QTextDocumentFragment>
+#include <QtGui/QPrintPreviewDialog>
+#include <QtGui/QPageSetupDialog>
+
+#include <QtHelp/QHelpEngine>
+
+using namespace Help::Internal;
+
+namespace {
+ HelpViewer* helpViewerFromTabPosition(const QTabWidget *widget, const QPoint &point)
+ {
+ QTabBar *tabBar = qFindChild<QTabBar*>(widget);
+ for (int i = 0; i < tabBar->count(); ++i) {
+ if (tabBar->tabRect(i).contains(point))
+ return qobject_cast<HelpViewer*>(widget->widget(i));
+ }
+ return 0;
+ }
+ CentralWidget *staticCentralWidget = 0;
+}
+
+CentralWidget::CentralWidget(QHelpEngine *engine, QWidget *parent)
+ : QWidget(parent)
+ , findBar(0)
+ , tabWidget(0)
+ , helpEngine(engine)
+ , printer(0)
+{
+ lastTabPage = 0;
+ globalActionList.clear();
+ collectionFile = helpEngine->collectionFile();
+
+ QString system = QLatin1String("win");
+
+#ifdef Q_OS_MAC
+ system = QLatin1String("mac");
+#endif
+
+ tabWidget = new QTabWidget;
+ tabWidget->setDocumentMode(true);
+ tabWidget->setMovable(true);
+ connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
+ connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentPageChanged(int)));
+
+ QToolButton *newTabButton = new QToolButton(this);
+ newTabButton->setAutoRaise(true);
+ newTabButton->setToolTip(tr("Add new page"));
+ newTabButton->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/addtab.png").arg(system)));
+
+ tabWidget->setCornerWidget(newTabButton, Qt::TopLeftCorner);
+ connect(newTabButton, SIGNAL(clicked()), this, SLOT(newTab()));
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+ vboxLayout->setMargin(0);
+ vboxLayout->addWidget(tabWidget);
+
+ QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
+ if (tabBar) {
+ tabBar->installEventFilter(this);
+ tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tabBar, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(showTabBarContextMenu(const QPoint&)));
+ }
+
+ staticCentralWidget = this;
+}
+
+CentralWidget::~CentralWidget()
+{
+ QDir dir;
+ QString currentPages;
+ QHelpEngineCore engine(collectionFile, 0);
+
+ if (engine.setupData()) {
+ for (int i = 0; i < tabWidget->count(); ++i) {
+ HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i));
+ if (viewer && viewer->source().isValid())
+ currentPages.append(viewer->source().toString()).append(QLatin1Char('|'));
+ }
+ engine.setCustomValue(QLatin1String("LastTabPage"), lastTabPage);
+ engine.setCustomValue(QLatin1String("LastShownPages"), currentPages);
+ }
+}
+
+CentralWidget *CentralWidget::instance()
+{
+ return staticCentralWidget;
+}
+
+void CentralWidget::newTab()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ setSourceInNewTab(viewer->source());
+}
+
+void CentralWidget::zoomIn()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->zoomIn();
+}
+
+void CentralWidget::zoomOut()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->zoomOut();
+}
+
+void CentralWidget::nextPage()
+{
+ if (tabWidget->currentIndex() < tabWidget->count() -1)
+ tabWidget->setCurrentIndex(tabWidget->currentIndex() +1);
+ else
+ tabWidget->setCurrentIndex(0);
+}
+
+void CentralWidget::resetZoom()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->resetZoom();
+}
+
+void CentralWidget::previousPage()
+{
+ int index = tabWidget->currentIndex() -1;
+ if (index >= 0)
+ tabWidget->setCurrentIndex(index);
+ else
+ tabWidget->setCurrentIndex(tabWidget->count() -1);
+}
+
+void CentralWidget::closeTab()
+{
+ closeTab(tabWidget->currentIndex());
+}
+
+void CentralWidget::closeTab(int index)
+{
+ HelpViewer* viewer = helpViewerAtIndex(index);
+ if (!viewer || tabWidget->count() == 1)
+ return;
+
+ tabWidget->removeTab(index);
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+}
+
+void CentralWidget::setSource(const QUrl &url)
+{
+ HelpViewer* viewer = currentHelpViewer();
+ HelpViewer* lastViewer = qobject_cast<HelpViewer*>(tabWidget->widget(lastTabPage));
+
+ if (!viewer && !lastViewer) {
+ viewer = new HelpViewer(helpEngine, this);
+ viewer->installEventFilter(this);
+ lastTabPage = tabWidget->addTab(viewer, QString());
+ tabWidget->setCurrentIndex(lastTabPage);
+ connectSignals();
+ qApp->processEvents();
+ } else
+ viewer = lastViewer;
+
+ viewer->setSource(url);
+ currentPageChanged(lastTabPage);
+ viewer->setFocus(Qt::OtherFocusReason);
+ tabWidget->setCurrentIndex(lastTabPage);
+ tabWidget->setTabText(lastTabPage, quoteTabTitle(viewer->documentTitle()));
+}
+
+void CentralWidget::setLastShownPages()
+{
+ const QStringList lastShownPageList = helpEngine->customValue(QLatin1String("LastShownPages")).
+ toString().split(QLatin1Char('|'), QString::SkipEmptyParts);
+
+ if (!lastShownPageList.isEmpty()) {
+ foreach (const QString page, lastShownPageList)
+ setSourceInNewTab(page);
+
+ tabWidget->setCurrentIndex(helpEngine->customValue(QLatin1String("LastTabPage"), 0).toInt());
+ } else {
+ QUrl url = helpEngine->findFile(QUrl("qthelp://com.trolltech.qt.440/qdoc/index.html"));
+ if (url.isValid())
+ setSource(url);
+ else
+ setSource(QUrl("qthelp://com.trolltech.qt.440/qdoc/index.html"));
+ }
+
+ updateBrowserFont();
+}
+
+bool CentralWidget::hasSelection() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ return viewer ? viewer->hasSelection() : false;
+}
+
+QUrl CentralWidget::currentSource() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->source();
+
+ return QUrl();
+}
+
+QString CentralWidget::currentTitle() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->documentTitle();
+
+ return QString();
+}
+
+void CentralWidget::copySelection()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->copy();
+}
+
+void CentralWidget::initPrinter()
+{
+#ifndef QT_NO_PRINTER
+ if (!printer)
+ printer = new QPrinter(QPrinter::HighResolution);
+#endif
+}
+
+void CentralWidget::print()
+{
+#ifndef QT_NO_PRINTER
+ HelpViewer* viewer = currentHelpViewer();
+ if (!viewer)
+ return;
+
+ initPrinter();
+
+ QPrintDialog *dlg = new QPrintDialog(printer, this);
+#if !defined(USE_WEBKIT)
+ if (viewer->textCursor().hasSelection())
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
+#endif
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintPageRange);
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies);
+ dlg->setWindowTitle(tr("Print Document"));
+ if (dlg->exec() == QDialog::Accepted) {
+ viewer->print(printer);
+ }
+ delete dlg;
+#endif
+}
+
+void CentralWidget::printPreview()
+{
+#ifndef QT_NO_PRINTER
+ initPrinter();
+ QPrintPreviewDialog preview(printer, this);
+ connect(&preview, SIGNAL(paintRequested(QPrinter *)), SLOT(printPreview(QPrinter *)));
+ preview.exec();
+#endif
+}
+
+void CentralWidget::printPreview(QPrinter *p)
+{
+#ifndef QT_NO_PRINTER
+ HelpViewer *viewer = currentHelpViewer();
+ if (viewer)
+ viewer->print(p);
+#endif
+}
+
+void CentralWidget::pageSetup()
+{
+#ifndef QT_NO_PRINTER
+ initPrinter();
+ QPageSetupDialog dlg(printer);
+ dlg.exec();
+#endif
+}
+
+bool CentralWidget::isHomeAvailable() const
+{
+ return currentHelpViewer() ? true : false;
+}
+
+void CentralWidget::home()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->home();
+}
+
+bool CentralWidget::isForwardAvailable() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->isForwardAvailable();
+
+ return false;
+}
+
+void CentralWidget::forward()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->forward();
+}
+
+bool CentralWidget::isBackwardAvailable() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->isBackwardAvailable();
+
+ return false;
+}
+
+void CentralWidget::backward()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->backward();
+}
+
+
+QList<QAction*> CentralWidget::globalActions() const
+{
+ return globalActionList;
+}
+
+void CentralWidget::setGlobalActions(const QList<QAction*> &actions)
+{
+ globalActionList = actions;
+}
+void CentralWidget::setSourceInNewTab(const QUrl &url)
+{
+ HelpViewer* viewer = new HelpViewer(helpEngine, this);
+ viewer->installEventFilter(this);
+ viewer->setSource(url);
+ viewer->setFocus(Qt::OtherFocusReason);
+ tabWidget->setCurrentIndex(tabWidget->addTab(viewer, viewer->documentTitle()));
+
+ QFont font = qApp->font();
+ if (helpEngine->customValue(QLatin1String("useBrowserFont")).toBool())
+ font = qVariantValue<QFont>(helpEngine->customValue(QLatin1String("browserFont")));
+
+ viewer->setFont(font);
+
+ connectSignals();
+}
+
+HelpViewer *CentralWidget::newEmptyTab()
+{
+ HelpViewer* viewer = new HelpViewer(helpEngine, this);
+ viewer->installEventFilter(this);
+ viewer->setFocus(Qt::OtherFocusReason);
+#if !defined(USE_WEBKIT)
+ viewer->setDocumentTitle(tr("unknown"));
+#endif
+ tabWidget->setCurrentIndex(tabWidget->addTab(viewer, tr("unknown")));
+
+ connectSignals();
+ return viewer;
+}
+
+void CentralWidget::connectSignals()
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer) {
+ connect(viewer, SIGNAL(copyAvailable(bool)), this, SIGNAL(copyAvailable(bool)));
+ connect(viewer, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
+ connect(viewer, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
+ connect(viewer, SIGNAL(sourceChanged(const QUrl&)), this, SIGNAL(sourceChanged(const QUrl&)));
+ connect(viewer, SIGNAL(highlighted(const QString&)), this, SIGNAL(highlighted(const QString&)));
+
+ connect(viewer, SIGNAL(sourceChanged(const QUrl&)), this, SLOT(setTabTitle(const QUrl&)));
+ }
+}
+
+HelpViewer *CentralWidget::helpViewerAtIndex(int index) const
+{
+ return qobject_cast<HelpViewer*>(tabWidget->widget(index));
+}
+
+HelpViewer *CentralWidget::currentHelpViewer() const
+{
+ return qobject_cast<HelpViewer*>(tabWidget->currentWidget());
+}
+
+void CentralWidget::activateTab(bool onlyHelpViewer)
+{
+ if (currentHelpViewer()) {
+ currentHelpViewer()->setFocus();
+ } else {
+ int idx = 0;
+ if (onlyHelpViewer)
+ idx = lastTabPage;
+ tabWidget->setCurrentIndex(idx);
+ tabWidget->currentWidget()->setFocus();
+ }
+}
+
+void CentralWidget::setTabTitle(const QUrl& url)
+{
+ int tab = lastTabPage;
+ HelpViewer* viewer = currentHelpViewer();
+
+#if defined(USE_WEBKIT)
+ if (!viewer || viewer->source() != url) {
+ QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
+ for (tab = 0; tab < tabBar->count(); ++tab) {
+ viewer = qobject_cast<HelpViewer*>(tabWidget->widget(tab));
+ if (viewer && viewer->source() == url)
+ break;
+ }
+ }
+#endif
+
+ if (viewer) {
+ tabWidget->setTabText(tab,
+ quoteTabTitle(viewer->documentTitle().trimmed()));
+ }
+}
+
+void CentralWidget::currentPageChanged(int index)
+{
+ const HelpViewer *viewer = currentHelpViewer();
+
+ if (viewer || tabWidget->count() == 1)
+ lastTabPage = index;
+
+ bool enabled = false;
+ if (viewer)
+ enabled = tabWidget->count() > 1;
+
+ tabWidget->setTabsClosable(enabled);
+ tabWidget->cornerWidget(Qt::TopLeftCorner)->setEnabled(true);
+
+ emit currentViewerChanged();
+}
+
+void CentralWidget::showTabBarContextMenu(const QPoint &point)
+{
+ HelpViewer* viewer = helpViewerFromTabPosition(tabWidget, point);
+ if (!viewer)
+ return;
+
+ QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
+
+ QMenu menu(QLatin1String(""), tabBar);
+ QAction *new_page = menu.addAction(tr("Add New Page"));
+ QAction *close_page = menu.addAction(tr("Close This Page"));
+ QAction *close_pages = menu.addAction(tr("Close Other Pages"));
+ menu.addSeparator();
+ QAction *newBookmark = menu.addAction(tr("Add Bookmark for this Page..."));
+
+ if (tabBar->count() == 1) {
+ close_page->setEnabled(false);
+ close_pages->setEnabled(false);
+ }
+
+ QAction *picked_action = menu.exec(tabBar->mapToGlobal(point));
+ if (!picked_action)
+ return;
+
+ if (picked_action == new_page)
+ setSourceInNewTab(viewer->source());
+
+ if (picked_action == close_page) {
+ tabWidget->removeTab(tabWidget->indexOf(viewer));
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+ }
+
+ if (picked_action == close_pages) {
+ int currentPage = tabWidget->indexOf(viewer);
+ for (int i = tabBar->count() -1; i >= 0; --i) {
+ viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i));
+ if (i != currentPage && viewer) {
+ tabWidget->removeTab(i);
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+
+ if (i < currentPage)
+ --currentPage;
+ }
+ }
+ }
+
+ if (picked_action == newBookmark)
+ emit addNewBookmark(viewer->documentTitle(), viewer->source().toString());
+}
+
+// if we have a current help viewer then this is the 'focus proxy', otherwise
+// it's the tab widget itself
+// this is needed, so an embedding program can just set the focus to the central widget
+// and it does TheRightThing
+void CentralWidget::focusInEvent(QFocusEvent * /* event */)
+{
+ if (currentHelpViewer())
+ QTimer::singleShot(1, currentHelpViewer(), SLOT(setFocus()));
+ else
+ QTimer::singleShot(1, tabWidget, SLOT(setFocus()));
+}
+
+bool CentralWidget::eventFilter(QObject *object, QEvent *e)
+{
+ if (currentHelpViewer() == object && e->type() == QEvent::KeyPress){
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->key() == Qt::Key_Backspace) {
+ HelpViewer *viewer = currentHelpViewer();
+ if (viewer && viewer->isBackwardAvailable())
+ viewer->backward();
+ return true;
+ }
+ }
+
+ QTabBar *tabBar = qobject_cast<QTabBar*>(object);
+ bool mousRel = e->type() == QEvent::MouseButtonRelease;
+ bool dblClick = e->type() == QEvent::MouseButtonDblClick;
+
+ if (tabBar && (mousRel || dblClick)) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(e);
+ HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, mouseEvent->pos());
+ if (tabWidget->count() <= 1)
+ return QWidget::eventFilter(object, e);
+
+ if (viewer && (mouseEvent->button() == Qt::MidButton || dblClick)) {
+ tabWidget->removeTab(tabWidget->indexOf(viewer));
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+ currentPageChanged(tabWidget->currentIndex());
+ return true;
+ }
+ }
+ return QWidget::eventFilter(object, e);
+}
+
+void CentralWidget::updateBrowserFont()
+{
+ QFont font = qApp->font();
+ if (helpEngine->customValue(QLatin1String("useBrowserFont")).toBool())
+ font = qVariantValue<QFont>(helpEngine->customValue(QLatin1String("browserFont")));
+
+ QWidget* widget = 0;
+ for (int i = 0; i < tabWidget->count(); ++i) {
+ widget = tabWidget->widget(i);
+ if (widget->font() != font)
+ widget->setFont(font);
+ }
+}
+
+bool CentralWidget::find(const QString &txt, QTextDocument::FindFlags findFlags, bool incremental)
+{
+ HelpViewer* viewer = currentHelpViewer();
+
+#if defined(USE_WEBKIT)
+ Q_UNUSED(incremental);
+ if (viewer) {
+ QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument;
+ if (findFlags & QTextDocument::FindBackward)
+ options |= QWebPage::FindBackward;
+ if (findFlags & QTextDocument::FindCaseSensitively)
+ options |= QWebPage::FindCaseSensitively;
+
+ return viewer->findText(txt, options);
+ }
+ return false;
+#else
+ QTextCursor cursor;
+ QTextDocument *doc = 0;
+ QTextBrowser *browser = 0;
+
+ if (viewer) {
+ doc = viewer->document();
+ cursor = viewer->textCursor();
+ browser = qobject_cast<QTextBrowser*>(viewer);
+ }
+ /*
+ if (tabWidget->currentWidget() == m_searchWidget) {
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(m_searchWidget);
+ if (browser) {
+ doc = browser->document();
+ cursor = browser->textCursor();
+ }
+ }
+ */
+ if (!browser || !doc || cursor.isNull())
+ return false;
+ if (incremental)
+ cursor.setPosition(cursor.selectionStart());
+
+ QTextCursor found = doc->find(txt, cursor, findFlags);
+ if (found.isNull()) {
+ if ((findFlags&QTextDocument::FindBackward) == 0)
+ cursor.movePosition(QTextCursor::Start);
+ else
+ cursor.movePosition(QTextCursor::End);
+ found = doc->find(txt, cursor, findFlags);
+ if (found.isNull()) {
+ return false;
+ }
+ }
+ if (!found.isNull()) {
+ viewer->setTextCursor(found);
+ }
+ return true;
+#endif
+}
+
+void CentralWidget::showTopicChooser(const QMap<QString, QUrl> &links,
+ const QString &keyword)
+{
+ TopicChooser tc(this, keyword, links);
+ if (tc.exec() == QDialog::Accepted)
+ setSource(tc.link());
+}
+
+void CentralWidget::copy()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->copy();
+}
+
+QString CentralWidget::quoteTabTitle(const QString &title) const
+{
+ QString s = title;
+ return s.replace(QLatin1Char('&'), QLatin1String("&&"));
+}
diff --git a/src/plugins/help/centralwidget.h b/src/plugins/help/centralwidget.h
new file mode 100644
index 0000000000..a75e999b07
--- /dev/null
+++ b/src/plugins/help/centralwidget.h
@@ -0,0 +1,157 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef CENTRALWIDGET_H
+#define CENTRALWIDGET_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QPoint>
+#include <QtCore/QObject>
+
+#include <QtGui/QWidget>
+#include <QtGui/QTextDocument>
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+class QLabel;
+class QAction;
+class QCheckBox;
+class QLineEdit;
+class QToolButton;
+class QTabWidget;
+class QHelpEngine;
+class QFocusEvent;
+class CentralWidget;
+class HelpViewer;
+
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class PrintHelper;
+
+}
+}
+
+QT_BEGIN_NAMESPACE
+
+class CentralWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CentralWidget(QHelpEngine *engine, QWidget *parent = 0);
+ ~CentralWidget();
+
+ bool hasSelection() const;
+ QUrl currentSource() const;
+ QString currentTitle() const;
+ bool isHomeAvailable() const;
+ bool isForwardAvailable() const;
+ bool isBackwardAvailable() const;
+ QList<QAction*> globalActions() const;
+ void setGlobalActions(const QList<QAction*> &actions);
+ HelpViewer *currentHelpViewer() const;
+ void activateTab(bool onlyHelpViewer = false);
+ bool find(const QString &txt, QTextDocument::FindFlags findFlags, bool incremental);
+ void setLastShownPages();
+
+ static CentralWidget *instance();
+
+public slots:
+ void zoomIn();
+ void zoomOut();
+ void nextPage();
+ void resetZoom();
+ void previousPage();
+ void copySelection();
+ void print();
+ void pageSetup();
+ void printPreview();
+ void updateBrowserFont();
+ void setSource(const QUrl &url);
+ void setSourceInNewTab(const QUrl &url);
+ HelpViewer *newEmptyTab();
+ void home();
+ void forward();
+ void backward();
+ void showTopicChooser(const QMap<QString, QUrl> &links,
+ const QString &keyword);
+ void copy();
+
+protected:
+ void focusInEvent(QFocusEvent *event);
+
+signals:
+ void currentViewerChanged();
+ void copyAvailable(bool yes);
+ void sourceChanged(const QUrl &url);
+ void highlighted(const QString &link);
+ void forwardAvailable(bool available);
+ void backwardAvailable(bool available);
+ void addNewBookmark(const QString &title, const QString &url);
+
+private slots:
+ void newTab();
+ void closeTab();
+ void closeTab(int index);
+ void setTabTitle(const QUrl& url);
+ void currentPageChanged(int index);
+ void showTabBarContextMenu(const QPoint &point);
+ void printPreview(QPrinter *printer);
+
+private:
+ void connectSignals();
+ bool eventFilter(QObject *object, QEvent *e);
+ void initPrinter();
+ HelpViewer *helpViewerAtIndex(int index) const;
+ QString quoteTabTitle(const QString &title) const;
+
+private:
+ int lastTabPage;
+ QString collectionFile;
+ QList<QAction*> globalActionList;
+
+ QWidget *findBar;
+ QTabWidget* tabWidget;
+ QHelpEngine *helpEngine;
+ QPrinter *printer;
+};
+
+QT_END_NAMESPACE
+//} // namespace Internal
+//} // namespace Help
+
+#endif // CENTRALWIDGET_H
diff --git a/src/plugins/help/contentstoolwindow.cpp b/src/plugins/help/contentstoolwindow.cpp
new file mode 100644
index 0000000000..1af3aff3b1
--- /dev/null
+++ b/src/plugins/help/contentstoolwindow.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtCore/QStack>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QKeyEvent>
+
+#include "contentstoolwindow.h"
+#include "helpengine.h"
+
+using namespace Help::Internal;
+
+ContentsToolWidget::ContentsToolWidget()
+{
+ wasInitialized = false;
+
+ setRootIsDecorated(true);
+ setItemHidden(headerItem(), true);
+ setUniformRowHeights(true);
+ setColumnCount(1);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ setWindowTitle(tr("Contents"));
+ setWindowIcon(QIcon(":/help/images/book.png"));
+}
+
+void ContentsToolWidget::focusInEvent(QFocusEvent *e)
+{
+ if (wasInitialized) {
+ if (e && e->reason() != Qt::MouseFocusReason
+ && !currentItem() && topLevelItemCount())
+ setCurrentItem(topLevelItem(0));
+ return;
+ }
+ wasInitialized = true;
+ setCursor(QCursor(Qt::WaitCursor));
+ emit buildRequested();
+}
+
+void ContentsToolWidget::showEvent(QShowEvent *)
+{
+ if (wasInitialized)
+ return;
+ wasInitialized = true;
+ setCursor(QCursor(Qt::WaitCursor));
+ emit buildRequested();
+}
+
+void ContentsToolWidget::keyPressEvent(QKeyEvent *e)
+{
+ if (e && e->key() == Qt::Key_Escape) {
+ emit escapePressed();
+ e->accept();
+ return;
+ }
+ QTreeWidget::keyPressEvent(e);
+}
+
+
+enum
+{
+ LinkRole = Qt::UserRole + 1000
+};
+
+ContentsToolWindow::ContentsToolWindow(const QList<int> &context, HelpEngine *help)
+{
+ m_widget = new ContentsToolWidget;
+ helpEngine = help;
+ connect(helpEngine, SIGNAL(contentsInitialized()), this, SLOT(contentsDone()));
+ connect(m_widget, SIGNAL(buildRequested()), helpEngine, SLOT(buildContents()));
+
+ m_context = context;
+ m_context << 0;
+
+ connect(m_widget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(indexRequested()));
+ connect(m_widget, SIGNAL(escapePressed()), this, SIGNAL(escapePressed()));
+}
+
+ContentsToolWindow::~ContentsToolWindow()
+{
+ delete m_widget;
+}
+
+const QList<int> &ContentsToolWindow::context() const
+{
+ return m_context;
+}
+
+QWidget *ContentsToolWindow::widget()
+{
+ return m_widget;
+}
+
+void ContentsToolWindow::contentsDone()
+{
+ m_widget->setCursor(QCursor(Qt::WaitCursor));
+ QList<QPair<QString, ContentList> > contentList = helpEngine->contents();
+ for(QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) {
+ QTreeWidgetItem *newEntry;
+ QTreeWidgetItem *contentEntry;
+ QStack<QTreeWidgetItem*> stack;
+ stack.clear();
+ int depth = 0;
+ bool root = false;
+
+ QTreeWidgetItem *lastItem[64];
+ for(int j = 0; j < 64; ++j)
+ lastItem[j] = 0;
+
+ ContentList lst = (*it).second;
+ for (ContentList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
+ ContentItem item = *it;
+ if (item.depth == 0) {
+ newEntry = new QTreeWidgetItem(m_widget, 0);
+ newEntry->setIcon(0, QIcon(QString::fromUtf8(":/help/images/book.png")));
+ newEntry->setText(0, item.title);
+ newEntry->setData(0, LinkRole, item.reference);
+ stack.push(newEntry);
+ depth = 1;
+ root = true;
+ }
+ else{
+ if((item.depth > depth) && root) {
+ depth = item.depth;
+ stack.push(contentEntry);
+ }
+ if(item.depth == depth) {
+ contentEntry = new QTreeWidgetItem(stack.top(), lastItem[ depth ]);
+ lastItem[ depth ] = contentEntry;
+ contentEntry->setText(0, item.title);
+ contentEntry->setData(0, LinkRole, item.reference);
+ }
+ else if(item.depth < depth) {
+ stack.pop();
+ depth--;
+ item = *(--it);
+ }
+ }
+ }
+ }
+ m_widget->setCursor(QCursor(Qt::ArrowCursor));
+}
+
+void ContentsToolWindow::indexRequested()
+{
+ QTreeWidgetItem *itm = m_widget->currentItem();
+ if (!itm)
+ return;
+ emit showLinkRequested(itm->data(0, LinkRole).toString(), false);
+}
diff --git a/src/plugins/help/contentstoolwindow.h b/src/plugins/help/contentstoolwindow.h
new file mode 100644
index 0000000000..51163c1ea1
--- /dev/null
+++ b/src/plugins/help/contentstoolwindow.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CONTENTSTOOLWINDOW_H
+#define CONTENTSTOOLWINDOW_H
+
+#include <QtGui/QTreeWidget>
+
+#include <coreplugin/iview.h>
+
+namespace Help {
+namespace Internal {
+
+class HelpEngine;
+class ContentsToolWindow;
+
+class ContentsToolWidget : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ ContentsToolWidget();
+
+signals:
+ void buildRequested();
+ void escapePressed();
+
+private:
+ friend class ContentsToolWindow;
+ void showEvent(QShowEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+
+ bool wasInitialized;
+};
+
+class ContentsToolWindow : public Core::IView
+{
+ Q_OBJECT
+
+public:
+ ContentsToolWindow(const QList<int> &context, HelpEngine *help);
+ ~ContentsToolWindow();
+
+ const QList<int> &context() const;
+ QWidget *widget();
+
+ QList<QWidget*> dockToolBarWidgets() const { return QList<QWidget*>(); }
+
+ const char *uniqueViewName() const { return "Help.ContentsToolWindow"; }
+ const char *globalMenuGroup() const { return "Help.Group"; }
+ inline QKeySequence defaultShortcut() const { return QKeySequence(); }
+ Qt::DockWidgetArea defaultArea() const { return Qt::RightDockWidgetArea; }
+ IView::ViewPosition defaultPosition() const { return IView::First; }
+
+signals:
+ void showLinkRequested(const QString &link, bool newWindow);
+ void escapePressed();
+
+private slots:
+ void contentsDone();
+ void indexRequested();
+
+private:
+ HelpEngine *helpEngine;
+
+ QList<int> m_context;
+ ContentsToolWidget *m_widget;
+};
+
+} //namespace Internal
+} //namespace Help
+
+#endif
diff --git a/src/plugins/help/docsettingspage.cpp b/src/plugins/help/docsettingspage.cpp
new file mode 100644
index 0000000000..763d134c23
--- /dev/null
+++ b/src/plugins/help/docsettingspage.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "docsettingspage.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+#include <QtHelp/QHelpEngine>
+
+using namespace Help::Internal;
+
+DocSettingsPage::DocSettingsPage(QHelpEngine *helpEngine)
+ : m_helpEngine(helpEngine),
+ m_registeredDocs(false)
+{
+
+}
+
+QString DocSettingsPage::name() const
+{
+ return "Documentation";
+}
+
+QString DocSettingsPage::category() const
+{
+ return "Help";
+}
+
+QString DocSettingsPage::trCategory() const
+{
+ return tr("Help");
+}
+
+QWidget *DocSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+
+ connect(m_ui.addButton, SIGNAL(clicked()),
+ this, SLOT(addDocumentation()));
+ connect(m_ui.removeButton, SIGNAL(clicked()),
+ this, SLOT(removeDocumentation()));
+
+ m_ui.docsListWidget->addItems(m_helpEngine->registeredDocumentations());
+ m_registeredDocs = false;
+ m_removeDocs.clear();
+
+ return w;
+}
+
+void DocSettingsPage::addDocumentation()
+{
+ QStringList files = QFileDialog::getOpenFileNames(m_ui.addButton->parentWidget(),
+ tr("Add Documentation"),
+ QString(), tr("Qt Help Files (*.qch)"));
+
+ if (files.isEmpty())
+ return;
+
+ foreach (const QString &file, files) {
+ QString nsName = QHelpEngineCore::namespaceName(file);
+ if (nsName.isEmpty()) {
+ QMessageBox::warning(m_ui.addButton->parentWidget(),
+ tr("Add Documentation"),
+ tr("The file %1 is not a valid Qt Help file!")
+ .arg(file));
+ continue;
+ }
+ m_helpEngine->registerDocumentation(file);
+ m_ui.docsListWidget->addItem(nsName);
+ }
+ m_registeredDocs = true;
+ emit documentationAdded();
+}
+
+void DocSettingsPage::removeDocumentation()
+{
+ QListWidgetItem *item = m_ui.docsListWidget->currentItem();
+ if (!item)
+ return;
+
+ m_removeDocs.append(item->text());
+ int row = m_ui.docsListWidget->currentRow();
+ m_ui.docsListWidget->takeItem(row);
+ if (row > 0)
+ --row;
+ if (m_ui.docsListWidget->count())
+ m_ui.docsListWidget->setCurrentRow(row);
+
+ delete item;
+}
+
+void DocSettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ emit dialogAccepted();
+}
+
+bool DocSettingsPage::applyChanges()
+{
+ QStringList::const_iterator it = m_removeDocs.constBegin();
+ while (it != m_removeDocs.constEnd()) {
+ if (!m_helpEngine->unregisterDocumentation((*it))) {
+ QMessageBox::warning(m_ui.addButton->parentWidget(),
+ tr("Documentation"),
+ tr("Cannot unregister documentation file %1!")
+ .arg((*it)));
+ }
+ ++it;
+ }
+ return m_registeredDocs || m_removeDocs.count();
+}
diff --git a/src/plugins/help/docsettingspage.h b/src/plugins/help/docsettingspage.h
new file mode 100644
index 0000000000..efafb94034
--- /dev/null
+++ b/src/plugins/help/docsettingspage.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef DOCSETTINGSPAGE_H
+#define DOCSETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_docsettingspage.h"
+
+QT_FORWARD_DECLARE_CLASS(QHelpEngine)
+
+namespace Help {
+namespace Internal {
+
+class DocSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ DocSettingsPage(QHelpEngine *helpEngine);
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ bool applyChanges();
+
+signals:
+ void documentationAdded();
+ void dialogAccepted();
+
+private slots:
+ void addDocumentation();
+ void removeDocumentation();
+
+private:
+ QHelpEngine *m_helpEngine;
+ bool m_registeredDocs;
+ QStringList m_removeDocs;
+ Ui::DocSettingsPage m_ui;
+};
+
+} // namespace Help
+} // namespace Internal
+
+#endif // DOCSETTINGSPAGE_H
diff --git a/src/plugins/help/docsettingspage.ui b/src/plugins/help/docsettingspage.ui
new file mode 100644
index 0000000000..311be060c7
--- /dev/null
+++ b/src/plugins/help/docsettingspage.ui
@@ -0,0 +1,77 @@
+<ui version="4.0" >
+ <class>DocSettingsPage</class>
+ <widget class="QWidget" name="DocSettingsPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>364</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Registered Documentation:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="_3" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="docsListWidget" />
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="_4" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="addButton" >
+ <property name="text" >
+ <string>Add...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp
new file mode 100644
index 0000000000..6087a94084
--- /dev/null
+++ b/src/plugins/help/filtersettingspage.cpp
@@ -0,0 +1,220 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "filtersettingspage.h"
+#include "filternamedialog.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+#include <QtHelp/QHelpEngine>
+
+using namespace Help::Internal;
+
+FilterSettingsPage::FilterSettingsPage(QHelpEngine *helpEngine)
+{
+ m_helpEngine = helpEngine;
+}
+
+QString FilterSettingsPage::name() const
+{
+ return "Filters";
+}
+
+QString FilterSettingsPage::category() const
+{
+ return "Help";
+}
+
+QString FilterSettingsPage::trCategory() const
+{
+ return tr("Help");
+}
+
+QWidget *FilterSettingsPage::createPage(QWidget *parent)
+{
+ m_currentPage = new QWidget(parent);
+ m_ui.setupUi(m_currentPage);
+ m_ui.attributeWidget->header()->hide();
+ m_ui.attributeWidget->setRootIsDecorated(false);
+
+ connect(m_ui.attributeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
+ this, SLOT(updateFilterMap()));
+ connect(m_ui.filterWidget,
+ SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
+ this, SLOT(updateAttributes(QListWidgetItem*)));
+ connect(m_ui.filterAddButton, SIGNAL(clicked()),
+ this, SLOT(addFilter()));
+ connect(m_ui.filterRemoveButton, SIGNAL(clicked()),
+ this, SLOT(removeFilter()));
+ updateFilterPage();
+
+ return m_currentPage;
+}
+
+void FilterSettingsPage::updateFilterPage()
+{
+ if (!m_helpEngine)
+ return;
+
+ m_ui.filterWidget->clear();
+ m_ui.attributeWidget->clear();
+
+ QHelpEngineCore help(m_helpEngine->collectionFile(), 0);
+ help.setupData();
+ m_filterMapBackup.clear();
+ const QStringList filters = help.customFilters();
+ foreach (const QString filter, filters) {
+ QStringList atts = help.filterAttributes(filter);
+ m_filterMapBackup.insert(filter, atts);
+ if (!m_filterMap.contains(filter))
+ m_filterMap.insert(filter, atts);
+ }
+
+ m_ui.filterWidget->addItems(m_filterMap.keys());
+
+ foreach (const QString a, help.filterAttributes())
+ new QTreeWidgetItem(m_ui.attributeWidget, QStringList() << a);
+
+ if (m_filterMap.keys().count())
+ m_ui.filterWidget->setCurrentRow(0);
+}
+
+void FilterSettingsPage::updateAttributes(QListWidgetItem *item)
+{
+ QStringList checkedList;
+ if (item)
+ checkedList = m_filterMap.value(item->text());
+ QTreeWidgetItem *itm;
+ for (int i=0; i<m_ui.attributeWidget->topLevelItemCount(); ++i) {
+ itm = m_ui.attributeWidget->topLevelItem(i);
+ if (checkedList.contains(itm->text(0)))
+ itm->setCheckState(0, Qt::Checked);
+ else
+ itm->setCheckState(0, Qt::Unchecked);
+ }
+}
+
+void FilterSettingsPage::updateFilterMap()
+{
+ if (!m_ui.filterWidget->currentItem())
+ return;
+ QString filter = m_ui.filterWidget->currentItem()->text();
+ if (!m_filterMap.contains(filter))
+ return;
+
+ QStringList newAtts;
+ QTreeWidgetItem *itm = 0;
+ for (int i=0; i<m_ui.attributeWidget->topLevelItemCount(); ++i) {
+ itm = m_ui.attributeWidget->topLevelItem(i);
+ if (itm->checkState(0) == Qt::Checked)
+ newAtts.append(itm->text(0));
+ }
+ m_filterMap[filter] = newAtts;
+}
+
+void FilterSettingsPage::addFilter()
+{
+ FilterNameDialog dia(m_currentPage);
+ if (dia.exec() == QDialog::Rejected)
+ return;
+
+ QString filterName = dia.filterName();
+ if (!m_filterMap.contains(filterName)) {
+ m_filterMap.insert(filterName, QStringList());
+ m_ui.filterWidget->addItem(filterName);
+ }
+
+ QList<QListWidgetItem*> lst = m_ui.filterWidget
+ ->findItems(filterName, Qt::MatchCaseSensitive);
+ m_ui.filterWidget->setCurrentItem(lst.first());
+}
+
+void FilterSettingsPage::removeFilter()
+{
+ QListWidgetItem *item = m_ui.filterWidget
+ ->takeItem(m_ui.filterWidget->currentRow());
+ if (!item)
+ return;
+
+ m_filterMap.remove(item->text());
+ m_removedFilters.append(item->text());
+ delete item;
+ if (m_ui.filterWidget->count())
+ m_ui.filterWidget->setCurrentRow(0);
+}
+
+void FilterSettingsPage::finished(bool)
+{
+}
+
+bool FilterSettingsPage::applyChanges()
+{
+ bool changed = false;
+ if (m_filterMap.count() != m_filterMapBackup.count()) {
+ changed = true;
+ } else {
+ QMapIterator<QString, QStringList> it(m_filterMapBackup);
+ while (it.hasNext() && !changed) {
+ it.next();
+ if (!m_filterMap.contains(it.key())) {
+ changed = true;
+ } else {
+ QStringList a = it.value();
+ QStringList b = m_filterMap.value(it.key());
+ if (a.count() != b.count()) {
+ changed = true;
+ } else {
+ QStringList::const_iterator i(a.constBegin());
+ while (i != a.constEnd()) {
+ if (!b.contains(*i)) {
+ changed = true;
+ break;
+ }
+ ++i;
+ }
+ }
+ }
+ }
+ }
+ if (changed) {
+ foreach (QString filter, m_removedFilters)
+ m_helpEngine->removeCustomFilter(filter);
+ QMapIterator<QString, QStringList> it(m_filterMap);
+ while (it.hasNext()) {
+ it.next();
+ m_helpEngine->addCustomFilter(it.key(), it.value());
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/src/plugins/help/filtersettingspage.h b/src/plugins/help/filtersettingspage.h
new file mode 100644
index 0000000000..5cf83619a2
--- /dev/null
+++ b/src/plugins/help/filtersettingspage.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef FILTERSETTINGSPAGE_H
+#define FILTERSETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_filtersettingspage.h"
+
+QT_FORWARD_DECLARE_CLASS(QHelpEngine)
+
+namespace Help {
+namespace Internal {
+
+class FilterSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ FilterSettingsPage(QHelpEngine *helpEngine);
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ bool applyChanges();
+
+private slots:
+ void updateAttributes(QListWidgetItem *item);
+ void updateFilterMap();
+ void updateFilterPage();
+ void addFilter();
+ void removeFilter();
+
+private:
+ QHelpEngine *m_helpEngine;
+ Ui::FilterSettingsPage m_ui;
+ QMap<QString, QStringList> m_filterMapBackup;
+ QMap<QString, QStringList> m_filterMap;
+ QStringList m_removedFilters;
+ QWidget *m_currentPage;
+};
+
+} // namespace Help
+} // namespace Internal
+
+#endif // DOCSETTINGSPAGE_H
diff --git a/src/plugins/help/filtersettingspage.ui b/src/plugins/help/filtersettingspage.ui
new file mode 100644
index 0000000000..367e7ce0a9
--- /dev/null
+++ b/src/plugins/help/filtersettingspage.ui
@@ -0,0 +1,72 @@
+<ui version="4.0" >
+ <class>FilterSettingsPage</class>
+ <widget class="QWidget" name="FilterSettingsPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" colspan="2" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_2" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="text" >
+ <string>Attributes:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QListWidget" name="filterWidget" />
+ </item>
+ <item rowspan="2" row="1" column="2" >
+ <widget class="QTreeWidget" name="attributeWidget" >
+ <property name="showDropIndicator" stdset="0" >
+ <bool>false</bool>
+ </property>
+ <property name="rootIsDecorated" >
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights" >
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QPushButton" name="filterAddButton" >
+ <property name="text" >
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="filterRemoveButton" >
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/help/help.pri b/src/plugins/help/help.pri
new file mode 100644
index 0000000000..cea3ed71f9
--- /dev/null
+++ b/src/plugins/help/help.pri
@@ -0,0 +1,3 @@
+include(help_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(Help)
diff --git a/src/plugins/help/help.pro b/src/plugins/help/help.pro
new file mode 100644
index 0000000000..a7de200f74
--- /dev/null
+++ b/src/plugins/help/help.pro
@@ -0,0 +1,36 @@
+TEMPLATE = lib
+TARGET = Help
+include(../../qworkbenchplugin.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/find/find.pri)
+include(../../plugins/quickopen/quickopen.pri)
+QT += network
+CONFIG += help
+DEFINES += QT_CLUCENE_SUPPORT \
+ HELP_LIBRARY
+HEADERS += helpplugin.h \
+ docsettingspage.h \
+ filtersettingspage.h \
+ helpmode.h \
+ centralwidget.h \
+ searchwidget.h \
+ helpfindsupport.h \
+ help_global.h \
+ helpindexfilter.h \
+ indexwindow.h
+SOURCES += helpplugin.cpp \
+ docsettingspage.cpp \
+ filtersettingspage.cpp \
+ helpmode.cpp \
+ centralwidget.cpp \
+ searchwidget.cpp \
+ helpfindsupport.cpp \
+ helpindexfilter.cpp
+FORMS += docsettingspage.ui \
+ filtersettingspage.ui
+RESOURCES += help.qrc
+include(../../../shared/help/help.pri)
+contains(QT_CONFIG, webkit) {
+ DEFINES += USE_WEBKIT
+ QT += webkit
+}
diff --git a/src/plugins/help/help.qrc b/src/plugins/help/help.qrc
new file mode 100644
index 0000000000..0b529633f8
--- /dev/null
+++ b/src/plugins/help/help.qrc
@@ -0,0 +1,16 @@
+<RCC>
+ <qresource prefix="/help" >
+ <file>images/find.png</file>
+ <file>images/book.png</file>
+ <file>images/previous.png</file>
+ <file>images/next.png</file>
+ <file>images/home.png</file>
+ <file>images/bookmark.png</file>
+ </qresource>
+ <qresource prefix="/trolltech/assistant" >
+ <file>images/mac/addtab.png</file>
+ <file>images/mac/closetab.png</file>
+ <file>images/win/addtab.png</file>
+ <file>images/win/closetab.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/help/help_global.h b/src/plugins/help/help_global.h
new file mode 100644
index 0000000000..104511ac88
--- /dev/null
+++ b/src/plugins/help/help_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef HELP_GLOBAL_H
+#define HELP_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(HELP_LIBRARY)
+# define HELP_EXPORT Q_DECL_EXPORT
+#else
+# define HELP_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // HELP_GLOBAL_H
diff --git a/src/plugins/help/helpengine.cpp b/src/plugins/help/helpengine.cpp
new file mode 100644
index 0000000000..790e4bf54a
--- /dev/null
+++ b/src/plugins/help/helpengine.cpp
@@ -0,0 +1,606 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QDateTime>
+#include <QtCore/QCoreApplication>
+
+#include "helpengine.h"
+#include "config.h"
+
+using namespace Help::Internal;
+
+static bool verifyDirectory(const QString &str)
+{
+ QFileInfo dirInfo(str);
+ if (!dirInfo.exists())
+ return QDir().mkdir(str);
+ if (!dirInfo.isDir()) {
+ qWarning("'%s' exists but is not a directory", str.toLatin1().constData());
+ return false;
+ }
+ return true;
+}
+
+struct IndexKeyword {
+ IndexKeyword(const QString &kw, const QString &l)
+ : keyword(kw), link(l) {}
+ IndexKeyword() : keyword(QString()), link(QString()) {}
+ bool operator<(const IndexKeyword &ik) const {
+ return keyword.toLower() < ik.keyword.toLower();
+ }
+ bool operator<=(const IndexKeyword &ik) const {
+ return keyword.toLower() <= ik.keyword.toLower();
+ }
+ bool operator>(const IndexKeyword &ik) const {
+ return keyword.toLower() > ik.keyword.toLower();
+ }
+ Q_DUMMY_COMPARISON_OPERATOR(IndexKeyword)
+ QString keyword;
+ QString link;
+};
+
+QDataStream &operator>>(QDataStream &s, IndexKeyword &ik)
+{
+ s >> ik.keyword;
+ s >> ik.link;
+ return s;
+}
+
+QDataStream &operator<<(QDataStream &s, const IndexKeyword &ik)
+{
+ s << ik.keyword;
+ s << ik.link;
+ return s;
+}
+
+
+/**
+ * Compare in a human-preferred alphanumeric way,
+ * e.g. 'Qt tutorial 2' will be less than 'Qt tutorial 11'.
+ */
+bool caseInsensitiveLessThan(const QString &as, const QString &bs)
+{
+ const QChar *a = as.unicode();
+ const QChar *b = bs.unicode();
+ int result = 0;
+ while (result == 0)
+ {
+ ushort aa = a->unicode();
+ ushort bb = b->unicode();
+
+ if (aa == 0 || bb == 0) {
+ result = aa - bb;
+ break;
+ }
+ else if (a->isDigit() && b->isDigit())
+ {
+ const QChar *a_begin = a;
+ const QChar *b_begin = b;
+ bool loop = true;
+ do {
+ if (a->isDigit()) ++a;
+ else if (b->isDigit()) ++b;
+ else loop = false;
+ } while (loop);
+
+ // optimization: comparing the length of the two numbers is more efficient than constructing two qstrings.
+ result = (a - a_begin) - (b - b_begin);
+ if (result == 0) {
+ QString astr(a_begin, a - a_begin);
+ QString bstr(b_begin, b - b_begin);
+ long la = astr.toLong();
+ long lb = bstr.toLong();
+ result = la - lb;
+ }
+ } else {
+ aa = QChar(aa).toLower().unicode();
+ bb = QChar(bb).toLower().unicode();
+ result = aa - bb;
+ ++a;
+ ++b;
+ }
+ }
+
+ return result < 0 ? true : false;
+}
+
+/**
+ * \a real is kinda a hack for the smart search, need a way to match a regexp to an item
+ * How would you say the best match for Q.*Wiget is QWidget?
+ */
+QModelIndex IndexListModel::filter(const QString &s, const QString &real)
+{
+ QStringList list;
+
+ int goodMatch = -1;
+ int perfectMatch = -1;
+ if (s.isEmpty())
+ perfectMatch = 0;
+
+ const QRegExp regExp(s);
+ QMultiMap<QString, QString>::iterator it = contents.begin();
+ QString lastKey;
+ for (; it != contents.end(); ++it) {
+ if (it.key() == lastKey)
+ continue;
+ lastKey = it.key();
+ const QString key = it.key();
+ if (key.contains(regExp) || key.contains(s, Qt::CaseInsensitive)) {
+ list.append(key);
+ //qDebug() << regExp << regExp.indexIn(s) << s << key << regExp.matchedLength();
+ if (perfectMatch == -1 && (key.startsWith(real, Qt::CaseInsensitive))) {
+ if (goodMatch == -1)
+ goodMatch = list.count() - 1;
+ if (s.length() == key.length())
+ perfectMatch = list.count() - 1;
+ } else if (perfectMatch > -1 && s == key) {
+ perfectMatch = list.count() - 1;
+ }
+ }
+ }
+
+ int bestMatch = perfectMatch;
+ if (bestMatch == -1)
+ bestMatch = goodMatch;
+
+ bestMatch = qMax(0, bestMatch);
+
+ // sort the new list
+ QString match;
+ if (bestMatch >= 0 && list.count() > bestMatch)
+ match = list[bestMatch];
+ qSort(list.begin(), list.end(), caseInsensitiveLessThan);
+ setStringList(list);
+ for (int i = 0; i < list.size(); ++i) {
+ if (list.at(i) == match){
+ bestMatch = i;
+ break;
+ }
+ }
+ return index(bestMatch, 0, QModelIndex());
+}
+
+
+
+
+
+
+
+
+
+HelpEngine::HelpEngine(QObject *parent, const QString &defaultQtVersionPath)
+ : QObject(parent)
+{
+ titleMapThread = new TitleMapThread(this);
+ connect(titleMapThread, SIGNAL(errorOccured(const QString&)),
+ this, SIGNAL(errorOccured(const QString&)));
+ connect(titleMapThread, SIGNAL(finished()), this, SLOT(titleMapFinished()));
+ indexThread = new IndexThread(this);
+ connect(indexThread, SIGNAL(errorOccured(const QString&)),
+ this, SIGNAL(errorOccured(const QString&)));
+ connect(indexThread, SIGNAL(finished()), this, SLOT(indexFinished()));
+
+ indexModel = new IndexListModel(this);
+
+ Config::loadConfig(defaultQtVersionPath);
+ cacheFilesPath = QDir::homePath() + QLatin1String("/.assistant");
+}
+
+HelpEngine::~HelpEngine()
+{
+ Config::configuration()->save();
+}
+
+void HelpEngine::init()
+{
+}
+
+QString HelpEngine::cacheFilePath() const
+{
+ return cacheFilesPath;
+}
+
+IndexListModel *HelpEngine::indices()
+{
+ return indexModel;
+}
+
+void HelpEngine::buildContents()
+{
+ contentsOnly = true;
+ if (!titleMapThread->isRunning()) {
+ titleMapThread->start(QThread::NormalPriority);
+ }
+}
+
+void HelpEngine::buildIndex()
+{
+ if (!titleMapThread->isRunning()) {
+ contentsOnly = false;
+ titleMapThread->start(QThread::NormalPriority);
+ }
+ if (!indexThread->isRunning())
+ indexThread->start(QThread::NormalPriority);
+}
+
+void HelpEngine::titleMapFinished()
+{
+ contentList = titleMapThread->contents();
+ titleMap = titleMapThread->documentTitleMap();
+ if (contentsOnly) {
+ contentsOnly = false;
+ emit contentsInitialized();
+ }
+}
+
+void HelpEngine::indexFinished()
+{
+ indexModel = indexThread->model();
+ emit indexInitialized();
+}
+
+void HelpEngine::removeOldCacheFiles(bool onlyFulltextSearchIndex)
+{
+ if (!verifyDirectory(cacheFilesPath)) {
+ qWarning("Failed to created assistant directory");
+ return;
+ }
+ QString pname = QLatin1String(".") + Config::configuration()->profileName();
+
+ QStringList fileList;
+ fileList << QLatin1String("indexdb40.dict")
+ << QLatin1String("indexdb40.doc");
+
+ if (!onlyFulltextSearchIndex)
+ fileList << QLatin1String("indexdb40") << QLatin1String("contentdb40");
+
+ QStringList::iterator it = fileList.begin();
+ for (; it != fileList.end(); ++it) {
+ if (QFile::exists(cacheFilesPath + QDir::separator() + *it + pname)) {
+ QFile f(cacheFilesPath + QDir::separator() + *it + pname);
+ f.remove();
+ }
+ }
+}
+
+quint32 HelpEngine::getFileAges()
+{
+ QStringList addDocuFiles = Config::configuration()->docFiles();
+ QStringList::const_iterator i = addDocuFiles.begin();
+
+ quint32 fileAges = 0;
+ for(; i != addDocuFiles.end(); ++i) {
+ QFileInfo fi(*i);
+ if (fi.exists())
+ fileAges += fi.lastModified().toTime_t();
+ }
+
+ return fileAges;
+}
+
+QString HelpEngine::removeAnchorFromLink(const QString &link)
+{
+ int i = link.length();
+ int j = link.lastIndexOf('/');
+ int l = link.lastIndexOf(QDir::separator());
+ if (l > j)
+ j = l;
+ if (j > -1) {
+ QString fileName = link.mid(j+1);
+ int k = fileName.lastIndexOf('#');
+ if (k > -1)
+ i = j + k + 1;
+ }
+ return link.left(i);
+}
+
+QString HelpEngine::titleOfLink(const QString &link)
+{
+ QString s = HelpEngine::removeAnchorFromLink(link);
+ s = titleMap[s];
+ if (s.isEmpty())
+ return link;
+ return s;
+}
+
+QString HelpEngine::home() const
+{
+ QString link = Config::configuration()->homePage();
+ if (!link.startsWith(QLatin1String("file:")))
+ link.prepend("file:");
+ return link;
+}
+
+
+
+
+
+
+
+
+
+
+TitleMapThread::TitleMapThread(HelpEngine *he)
+ : QThread(he)
+{
+ engine = he;
+ done = false;
+}
+
+TitleMapThread::~TitleMapThread()
+{
+
+}
+
+void TitleMapThread::run()
+{
+ if (done) {
+ engine->mutex.lock();
+ engine->titleMapDoneCondition.wakeAll();
+ engine->mutex.unlock();
+ return;
+ }
+
+ bool needRebuild = false;
+ if (Config::configuration()->profileName() == QLatin1String("default")) {
+ const QStringList docuFiles = Config::configuration()->docFiles();
+ for(QStringList::ConstIterator it = docuFiles.begin(); it != docuFiles.end(); it++) {
+ if (!QFile::exists(*it)) {
+ Config::configuration()->saveProfile(Profile::createDefaultProfile());
+ Config::configuration()->loadDefaultProfile();
+ needRebuild = true;
+ break;
+ }
+ }
+ }
+
+ if (Config::configuration()->docRebuild() || needRebuild) {
+ engine->removeOldCacheFiles();
+ Config::configuration()->setDocRebuild(false);
+ Config::configuration()->save();
+ }
+ if (contentList.isEmpty())
+ getAllContents();
+
+ titleMap.clear();
+ for(QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) {
+ ContentList lst = (*it).second;
+ foreach (ContentItem item, lst) {
+ titleMap[item.reference] = item.title.trimmed();
+ }
+ }
+ done = true;
+ engine->mutex.lock();
+ engine->titleMapDoneCondition.wakeAll();
+ engine->mutex.unlock();
+}
+
+void TitleMapThread::getAllContents()
+{
+ QFile contentFile(engine->cacheFilePath() + QDir::separator() + QLatin1String("contentdb40.")
+ + Config::configuration()->profileName());
+ contentList.clear();
+ if (!contentFile.open(QFile::ReadOnly)) {
+ buildContentDict();
+ return;
+ }
+
+ QDataStream ds(&contentFile);
+ quint32 fileAges;
+ ds >> fileAges;
+ if (fileAges != engine->getFileAges()) {
+ contentFile.close();
+ engine->removeOldCacheFiles(true);
+ buildContentDict();
+ return;
+ }
+ QString key;
+ QList<ContentItem> lst;
+ while (!ds.atEnd()) {
+ ds >> key;
+ ds >> lst;
+ contentList += qMakePair(key, QList<ContentItem>(lst));
+ }
+ contentFile.close();
+
+}
+
+void TitleMapThread::buildContentDict()
+{
+ QStringList docuFiles = Config::configuration()->docFiles();
+
+ quint32 fileAges = 0;
+ for(QStringList::iterator it = docuFiles.begin(); it != docuFiles.end(); it++) {
+ QFile file(*it);
+ if (!file.exists()) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Documentation file %1 does not exist!\n"
+ "Skipping file.").arg(QFileInfo(file).absoluteFilePath()));
+#endif
+ continue;
+ }
+ fileAges += QFileInfo(file).lastModified().toTime_t();
+ DocuParser *handler = DocuParser::createParser(*it);
+ if(!handler) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Documentation file %1 is not compatible!\n"
+ "Skipping file.").arg(QFileInfo(file).absoluteFilePath()));
+#endif
+ continue;
+ }
+ bool ok = handler->parse(&file);
+ file.close();
+ if(ok) {
+ contentList += qMakePair(*it, QList<ContentItem>(handler->getContentItems()));
+ delete handler;
+ } else {
+#ifdef _SHOW_ERRORS_
+ QString msg = QString::fromLatin1("In file %1:\n%2")
+ .arg(QFileInfo(file).absoluteFilePath())
+ .arg(handler->errorProtocol());
+ emit errorOccured(msg);
+#endif
+ continue;
+ }
+ }
+
+ QFile contentOut(engine->cacheFilePath() + QDir::separator() + QLatin1String("contentdb40.")
+ + Config::configuration()->profileName());
+ if (contentOut.open(QFile::WriteOnly)) {
+ QDataStream s(&contentOut);
+ s << fileAges;
+ for(QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) {
+ s << *it;
+ }
+ contentOut.close();
+ }
+}
+
+
+
+
+
+IndexThread::IndexThread(HelpEngine *he)
+ : QThread(he)
+{
+ engine = he;
+ indexModel = new IndexListModel(this);
+ indexDone = false;
+}
+
+void IndexThread::run()
+{
+ if (indexDone)
+ return;
+ engine->mutex.lock();
+ if (engine->titleMapThread->isRunning())
+ engine->titleMapDoneCondition.wait(&(engine->mutex));
+ engine->mutex.unlock();
+
+ keywordDocuments.clear();
+ QList<IndexKeyword> lst;
+ QFile indexFile(engine->cacheFilePath() + QDir::separator() + QLatin1String("indexdb40.") +
+ Config::configuration()->profileName());
+ if (!indexFile.open(QFile::ReadOnly)) {
+ buildKeywordDB();
+ if (!indexFile.open(QFile::ReadOnly)) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Failed to load keyword index file!"));
+#endif
+ return;
+ }
+ }
+
+ QDataStream ds(&indexFile);
+ quint32 fileAges;
+ ds >> fileAges;
+ if (fileAges != engine->getFileAges()) {
+ indexFile.close();
+ buildKeywordDB();
+ if (!indexFile.open(QFile::ReadOnly)) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Cannot open the index file %1")
+ .arg(QFileInfo(indexFile).absoluteFilePath()));
+#endif
+ return;
+ }
+ ds.setDevice(&indexFile);
+ ds >> fileAges;
+ }
+ ds >> lst;
+ indexFile.close();
+
+ for (int i=0; i<lst.count(); ++i) {
+ const IndexKeyword &idx = lst.at(i);
+ indexModel->addLink(idx.keyword, idx.link);
+ keywordDocuments << HelpEngine::removeAnchorFromLink(idx.link);
+ }
+ indexModel->publish();
+ indexDone = true;
+}
+
+void IndexThread::buildKeywordDB()
+{
+ QStringList addDocuFiles = Config::configuration()->docFiles();
+ QStringList::iterator i = addDocuFiles.begin();
+
+ int steps = 0;
+ for(; i != addDocuFiles.end(); i++)
+ steps += QFileInfo(*i).size();
+
+ QList<IndexKeyword> lst;
+ quint32 fileAges = 0;
+ for(i = addDocuFiles.begin(); i != addDocuFiles.end(); i++){
+ QFile file(*i);
+ if (!file.exists()) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Documentation file %1 does not exist!\n"
+ "Skipping file.").arg(QFileInfo(file).absoluteFilePath()));
+#endif
+ continue;
+ }
+ fileAges += QFileInfo(file).lastModified().toTime_t();
+ DocuParser *handler = DocuParser::createParser(*i);
+ bool ok = handler->parse(&file);
+ file.close();
+ if(!ok){
+#ifdef _SHOW_ERRORS_
+ QString msg = QString::fromLatin1("In file %1:\n%2")
+ .arg(QFileInfo(file).absoluteFilePath())
+ .arg(handler->errorProtocol());
+ emit errorOccured(msg);
+#endif
+ delete handler;
+ continue;
+ }
+
+ QList<IndexItem*> indLst = handler->getIndexItems();
+ foreach (IndexItem *indItem, indLst) {
+ QFileInfo fi(indItem->reference);
+ lst.append(IndexKeyword(indItem->keyword, indItem->reference));
+ }
+ delete handler;
+ }
+ if (!lst.isEmpty())
+ qSort(lst);
+
+ QFile indexout(engine->cacheFilePath() + QDir::separator() + QLatin1String("indexdb40.")
+ + Config::configuration()->profileName());
+ if (verifyDirectory(engine->cacheFilePath()) && indexout.open(QFile::WriteOnly)) {
+ QDataStream s(&indexout);
+ s << fileAges;
+ s << lst;
+ indexout.close();
+ }
+}
diff --git a/src/plugins/help/helpengine.h b/src/plugins/help/helpengine.h
new file mode 100644
index 0000000000..9aa79f4e52
--- /dev/null
+++ b/src/plugins/help/helpengine.h
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPENGINE_H
+#define HELPENGINE_H
+
+#include <QtCore/QThread>
+#include <QtCore/QPair>
+#include <QtCore/QMap>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
+#include <QtGui/QStringListModel>
+
+#include "docuparser.h"
+
+namespace Help {
+namespace Internal {
+
+class HelpEngine;
+
+typedef QList<ContentItem> ContentList;
+
+class IndexListModel: public QStringListModel
+{
+public:
+ IndexListModel(QObject *parent = 0)
+ : QStringListModel(parent) {}
+
+ void clear() { contents.clear(); setStringList(QStringList()); }
+
+ QString description(int index) const { return stringList().at(index); }
+ QStringList links(int index) const { return contents.values(stringList().at(index)); }
+ void addLink(const QString &description, const QString &link) { contents.insert(description, link); }
+
+ void publish() { filter(QString(), QString()); }
+
+ QModelIndex filter(const QString &s, const QString &real);
+
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const
+ { return QStringListModel::flags(index) & ~Qt::ItemIsEditable; }
+
+private:
+ QMultiMap<QString, QString> contents;
+};
+
+class TitleMapThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ TitleMapThread(HelpEngine *he);
+ ~TitleMapThread();
+ void setup();
+ QList<QPair<QString, ContentList> > contents() const { return contentList; }
+ QMap<QString, QString> documentTitleMap() const { return titleMap; }
+
+signals:
+ void errorOccured(const QString &errMsg);
+
+protected:
+ void run();
+
+private:
+ void getAllContents();
+ void buildContentDict();
+
+ QList<QPair<QString, ContentList> > contentList;
+ QMap<QString, QString> titleMap;
+
+ HelpEngine *engine;
+ bool done;
+};
+
+class IndexThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ IndexThread(HelpEngine *he);
+ void setup();
+ IndexListModel *model() const { return indexModel; }
+
+protected:
+ void run();
+
+signals:
+ void errorOccured(const QString &errMsg);
+
+private:
+ void buildKeywordDB();
+
+ HelpEngine *engine;
+ QStringList keywordDocuments;
+ IndexListModel *indexModel;
+ bool indexDone;
+};
+
+class HelpEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ HelpEngine(QObject *parent, const QString& defaultQtVersionPath);
+ ~HelpEngine();
+ void init();
+ QList<QPair<QString, ContentList> > contents() const { return contentList; }
+ IndexListModel *indices();
+
+ QString titleOfLink(const QString &link);
+ static QString removeAnchorFromLink(const QString &link);
+
+ QString home() const;
+
+signals:
+ void indexInitialized();
+ void contentsInitialized();
+ void errorOccured(const QString &errMsg);
+
+public slots:
+ void buildContents();
+ void buildIndex();
+
+private slots:
+ void titleMapFinished();
+ void indexFinished();
+
+private:
+ friend class TitleMapThread;
+ friend class IndexThread;
+
+ void removeOldCacheFiles(bool onlyFulltextSearchIndex = false);
+ QString cacheFilePath() const;
+ quint32 getFileAges();
+
+ QList<QPair<QString, ContentList> > contentList;
+ QMap<QString, QString> titleMap;
+
+ QString cacheFilesPath;
+ IndexListModel *indexModel;
+
+ QWaitCondition titleMapDoneCondition;
+ QMutex mutex;
+
+ TitleMapThread *titleMapThread;
+ IndexThread *indexThread;
+
+ bool contentsOnly;
+};
+
+} //namespace Internal
+} //namespace Help
+
+#endif
diff --git a/src/plugins/help/helpfindsupport.cpp b/src/plugins/help/helpfindsupport.cpp
new file mode 100644
index 0000000000..306a1d5f40
--- /dev/null
+++ b/src/plugins/help/helpfindsupport.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helpfindsupport.h"
+#include "helpviewer.h"
+
+using namespace Help::Internal;
+
+HelpFindSupport::HelpFindSupport(CentralWidget *centralWidget)
+ : m_centralWidget(centralWidget)
+{
+}
+
+HelpFindSupport::~HelpFindSupport()
+{
+}
+
+bool HelpFindSupport::isEnabled() const
+{
+ return true;
+}
+QString HelpFindSupport::currentFindString() const
+{
+ Q_ASSERT(m_centralWidget);
+ HelpViewer* viewer = m_centralWidget->currentHelpViewer();
+ if (!viewer)
+ return QString();
+#if defined(USE_WEBKIT)
+ return viewer->selectedText();
+#else
+ return viewer->textCursor().selectedText();
+#endif
+}
+
+
+QString HelpFindSupport::completedFindString() const { return QString(); }
+
+bool HelpFindSupport::findIncremental(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_centralWidget);
+ findFlags &= ~QTextDocument::FindBackward;
+ return m_centralWidget->find(txt, findFlags, true);
+}
+
+bool HelpFindSupport::findStep(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_centralWidget);
+ return m_centralWidget->find(txt, findFlags, false);
+}
diff --git a/src/plugins/help/helpfindsupport.h b/src/plugins/help/helpfindsupport.h
new file mode 100644
index 0000000000..082e908c75
--- /dev/null
+++ b/src/plugins/help/helpfindsupport.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPFINDSUPPORT_H
+#define HELPFINDSUPPORT_H
+
+#include "centralwidget.h"
+
+#include <find/ifindsupport.h>
+
+namespace Help {
+namespace Internal {
+
+class HelpFindSupport : public Find::IFindSupport
+{
+ Q_OBJECT
+
+public:
+ HelpFindSupport(CentralWidget *centralWidget);
+ ~HelpFindSupport();
+
+ bool isEnabled() const;
+ bool supportsReplace() const { return false; }
+ void resetIncrementalSearch() {}
+ void clearResults() {}
+ QString currentFindString() const;
+ QString completedFindString() const;
+
+ bool findIncremental(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool findStep(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool replaceStep(const QString &, const QString &,
+ QTextDocument::FindFlags ) { return false; }
+ int replaceAll(const QString &, const QString &,
+ QTextDocument::FindFlags ) { return 0; }
+
+private:
+ bool find(const QString &ttf, QTextDocument::FindFlags findFlags, bool incremental);
+
+ CentralWidget *m_centralWidget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPFINDSUPPORT_H
diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp
new file mode 100644
index 0000000000..b8aa2edfba
--- /dev/null
+++ b/src/plugins/help/helpindexfilter.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helpindexfilter.h"
+#include "helpplugin.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/modemanager.h>
+
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpIndexModel>
+
+using namespace QuickOpen;
+using namespace Help;
+using namespace Help::Internal;
+
+Q_DECLARE_METATYPE(IQuickOpenFilter*);
+
+HelpIndexFilter::HelpIndexFilter(HelpPlugin *plugin, QHelpEngine *helpEngine):
+ m_plugin(plugin),
+ m_helpEngine(helpEngine),
+ m_icon(QIcon()) // TODO: Put an icon next to the results
+{
+ setIncludedByDefault(false);
+ setShortcutString("?");
+
+ connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()),
+ this, SLOT(updateIndices()));
+}
+
+void HelpIndexFilter::updateIndices()
+{
+ const QString currentFilter = m_plugin->indexFilter();
+ if (!currentFilter.isEmpty())
+ m_plugin->setIndexFilter(QString());
+
+ m_helpIndex = m_helpEngine->indexModel()->stringList();
+
+ if (!currentFilter.isEmpty())
+ m_plugin->setIndexFilter(currentFilter);
+}
+
+QString HelpIndexFilter::trName() const
+{
+ return tr("Help index");
+}
+
+QString HelpIndexFilter::name() const
+{
+ return QLatin1String("HelpIndexFilter");
+}
+
+IQuickOpenFilter::Priority HelpIndexFilter::priority() const
+{
+ return Medium;
+}
+
+QList<FilterEntry> HelpIndexFilter::matchesFor(const QString &entry)
+{
+ QList<FilterEntry> entries;
+ foreach (const QString &string, m_helpIndex) {
+ if (string.contains(entry, Qt::CaseInsensitive)) {
+ FilterEntry entry(this, string, QVariant(), m_icon);
+ entries.append(entry);
+ }
+ }
+ return entries;
+}
+
+void HelpIndexFilter::accept(FilterEntry selection) const
+{
+ QMap<QString, QUrl> links = m_helpEngine->indexModel()->linksForKeyword(selection.displayName);
+ if (links.size() == 1) {
+ emit linkActivated(links.begin().value());
+ } else if (!links.isEmpty()) {
+ emit linksActivated(links, selection.displayName);
+ }
+}
+
+void HelpIndexFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+ // Nothing to refresh
+}
diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h
new file mode 100644
index 0000000000..0d62a9b5e1
--- /dev/null
+++ b/src/plugins/help/helpindexfilter.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPINDEXFILTER_H
+#define HELPINDEXFILTER_H
+
+#include <quickopen/iquickopenfilter.h>
+
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QHelpEngine;
+class QUrl;
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class HelpPlugin;
+
+class HelpIndexFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ HelpIndexFilter(HelpPlugin *plugin, QHelpEngine *helpEngine);
+
+ // IQuickOpenFilter
+ QString trName() const;
+ QString name() const;
+ Priority priority() const;
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &future);
+
+signals:
+ void linkActivated(const QUrl &link) const;
+ void linksActivated(const QMap<QString, QUrl> &urls, const QString &keyword) const;
+
+private slots:
+ void updateIndices();
+
+private:
+ HelpPlugin *m_plugin;
+ QHelpEngine *m_helpEngine;
+ QStringList m_helpIndex;
+ QIcon m_icon;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPINDEXFILTER_H
diff --git a/src/plugins/help/helpmode.cpp b/src/plugins/help/helpmode.cpp
new file mode 100644
index 0000000000..b57da2da22
--- /dev/null
+++ b/src/plugins/help/helpmode.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helpmode.h"
+#include "helpplugin.h"
+
+#include <QtCore/QLatin1String>
+#include <QtGui/QWidget>
+#include <coreplugin/findplaceholder.h>
+
+using namespace Help;
+using namespace Help::Internal;
+
+HelpMode::HelpMode(QWidget *widget, QWidget *centralWidget, QObject *parent):
+ BaseMode(tr("Help"),
+ Constants::ID_MODE_HELP,
+ QIcon((QLatin1String(":/fancyactionbar/images/mode_Reference.png"))), Constants::P_MODE_HELP, widget, parent),
+ m_centralWidget(centralWidget)
+{
+ m_centralWidget->layout()->setSpacing(0);
+ m_centralWidget->layout()->addWidget(new Core::FindToolBarPlaceHolder(this));
+}
+
+
diff --git a/src/plugins/help/helpmode.h b/src/plugins/help/helpmode.h
new file mode 100644
index 0000000000..19b5c73a29
--- /dev/null
+++ b/src/plugins/help/helpmode.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPMODE_H
+#define HELPMODE_H
+
+#include <QtCore/QObject>
+
+#include <coreplugin/basemode.h>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class HelpMode : public Core::BaseMode
+{
+ Q_OBJECT
+
+public:
+ HelpMode(QWidget *widget, QWidget *centralWidget, QObject *parent = 0);
+
+private:
+ QWidget *m_centralWidget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPMODE_H
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
new file mode 100644
index 0000000000..17712cd576
--- /dev/null
+++ b/src/plugins/help/helpplugin.cpp
@@ -0,0 +1,684 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "helpplugin.h"
+#include "docsettingspage.h"
+#include "filtersettingspage.h"
+#include "helpindexfilter.h"
+#include "helpmode.h"
+#include "helpviewer.h"
+#include "contentwindow.h"
+#include "indexwindow.h"
+#include "bookmarkmanager.h"
+#include "centralwidget.h"
+#include "helpfindsupport.h"
+#include "searchwidget.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/qplugin.h>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QDir>
+#include <QtCore/QResource>
+#include <QtGui/QAction>
+#include <QtGui/QShortcut>
+#include <QtGui/QSplitter>
+#include <QtGui/QStyle>
+#include <QtGui/QToolBar>
+#include <QtGui/QComboBox>
+#include <QtHelp/QHelpEngine>
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/minisplitter.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/rightpane.h>
+#include <coreplugin/sidebar.h>
+#include <coreplugin/welcomemode.h>
+
+using namespace Help;
+using namespace Help::Internal;
+
+HelpManager::HelpManager(QHelpEngine *helpEngine)
+ : m_helpEngine(helpEngine)
+{
+}
+
+void HelpManager::registerDocumentation(const QStringList &fileNames)
+{
+ bool needsSetup = false;
+ {
+ QHelpEngineCore hc(m_helpEngine->collectionFile());
+ hc.setupData();
+ foreach (const QString &fileName, fileNames) {
+ if (!QFile::exists(fileName))
+ continue;
+ QString fileNamespace = QHelpEngineCore::namespaceName(fileName);
+ if (!fileNamespace.isEmpty() && !hc.registeredDocumentations().contains(fileNamespace)) {
+ if (hc.registerDocumentation(fileName))
+ needsSetup = true;
+ else
+ qDebug() << "error registering" << fileName << hc.error();
+ }
+ }
+ }
+ if (needsSetup)
+ qDebug() << m_helpEngine->setupData();
+}
+
+HelpPlugin::HelpPlugin() :
+ m_core(0),
+ m_helpEngine(0),
+ m_contextHelpEngine(0),
+ m_contentWidget(0),
+ m_indexWidget(0),
+ m_centralWidget(0),
+ m_helpViewerForSideBar(0),
+ m_mode(0),
+ m_shownLastPages(false),
+ m_contentItem(0),
+ m_indexItem(0),
+ m_searchItem(0),
+ m_bookmarkItem(0),
+ m_rightPaneSideBar(0)
+{
+}
+
+HelpPlugin::~HelpPlugin()
+{
+}
+
+bool HelpPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ QList<int> globalcontext;
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+ QList<int> modecontext;
+ modecontext << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_MODE_HELP);
+
+ // FIXME shouldn't the help engine create the directory if it doesn't exist?
+ QFileInfo fi(m_core->settings()->fileName());
+ QDir directory(fi.absolutePath());
+ if (!directory.exists())
+ directory.mkpath(directory.absolutePath());
+ m_helpEngine = new QHelpEngine(directory.absolutePath()
+ + QLatin1String("/helpcollection.qhc"), this);
+ connect(m_helpEngine, SIGNAL(setupFinished()),
+ this, SLOT(updateFilterComboBox()));
+
+ addAutoReleasedObject(new HelpManager(m_helpEngine));
+
+ m_docSettingsPage = new DocSettingsPage(m_helpEngine);
+ addAutoReleasedObject(m_docSettingsPage);
+
+ m_filterSettingsPage = new FilterSettingsPage(m_helpEngine);
+ addAutoReleasedObject(m_filterSettingsPage);
+ connect(m_docSettingsPage, SIGNAL(documentationAdded()),
+ m_filterSettingsPage, SLOT(updateFilterPage()));
+ connect(m_docSettingsPage, SIGNAL(dialogAccepted()),
+ this, SLOT(checkForHelpChanges()));
+
+ m_contentWidget = new ContentWindow(m_helpEngine);
+ m_contentWidget->setWindowTitle(tr("Contents"));
+ m_indexWidget = new IndexWindow(m_helpEngine);
+ m_indexWidget->setWindowTitle(tr("Index"));
+ m_searchWidget = new SearchWidget(m_helpEngine->searchEngine());
+ m_searchWidget->setWindowTitle(tr("Search"));
+ m_bookmarkManager = new BookmarkManager(m_helpEngine);
+ m_bookmarkWidget = new BookmarkWidget(m_bookmarkManager, 0, false);
+ m_bookmarkWidget->setWindowTitle(tr("Bookmarks"));
+ connect(m_bookmarkWidget, SIGNAL(addBookmark()),
+ this, SLOT(addBookmark()));
+
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ Core::ICommand *cmd;
+
+ // Add Home, Previous and Next actions (used in the toolbar)
+ QAction *homeAction = new QAction(QIcon(QLatin1String(":/help/images/home.png")), tr("Home"), this);
+ cmd = am->registerAction(homeAction, QLatin1String("Help.Home"), globalcontext);
+
+ QAction *previousAction = new QAction(QIcon(QLatin1String(":/help/images/previous.png")),
+ tr("Previous"), this);
+ cmd = am->registerAction(previousAction, QLatin1String("Help.Previous"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::Key_Backspace));
+
+ QAction *nextAction = new QAction(QIcon(QLatin1String(":/help/images/next.png")), tr("Next"), this);
+ cmd = am->registerAction(nextAction, QLatin1String("Help.Next"), modecontext);
+
+ QAction *addBookmarkAction = new QAction(QIcon(QLatin1String(":/help/images/bookmark.png")),
+ tr("Add Bookmark"), this);
+ cmd = am->registerAction(addBookmarkAction, QLatin1String("Help.AddBookmark"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_M));
+
+ // Add Index, Contents, and Context menu items and a separator to the Help menu
+ QAction *indexAction = new QAction(tr("Index"), this);
+ cmd = am->registerAction(indexAction, QLatin1String("Help.Index"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+ QAction *contentsAction = new QAction(tr("Contents"), this);
+ cmd = am->registerAction(contentsAction, QLatin1String("Help.Contents"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+ QAction *searchAction = new QAction(tr("Search"), this);
+ cmd = am->registerAction(searchAction, QLatin1String("Help.Search"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+ QAction *contextAction = new QAction(tr("Context Help"), this);
+ cmd = am->registerAction(contextAction, QLatin1String("Help.Context"), globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+#ifndef Q_OS_MAC
+ QAction *sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("Help.Separator"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+#endif
+
+ m_centralWidget = new CentralWidget(m_helpEngine);
+ Aggregation::Aggregate *agg = new Aggregation::Aggregate;
+ agg->add(m_centralWidget);
+ agg->add(new HelpFindSupport(m_centralWidget));
+ QWidget *mainWidget = new QWidget;
+ QVBoxLayout *mainWidgetLayout = new QVBoxLayout(mainWidget);
+ mainWidgetLayout->setMargin(0);
+ mainWidgetLayout->setSpacing(0);
+ mainWidgetLayout->addWidget(createToolBar());
+ mainWidgetLayout->addWidget(m_centralWidget);
+
+ m_contentItem = new Core::SideBarItem(m_contentWidget);
+ m_indexItem = new Core::SideBarItem(m_indexWidget);
+ m_searchItem = new Core::SideBarItem(m_searchWidget);
+ m_bookmarkItem = new Core::SideBarItem(m_bookmarkWidget);
+ QList<Core::SideBarItem*> itemList;
+ itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem;
+ m_sideBar = new Core::SideBar(itemList, QList<Core::SideBarItem*>() << m_indexItem);
+
+ QSplitter *splitter = new Core::MiniSplitter;
+ splitter->setOpaqueResize(false);
+ splitter->addWidget(m_sideBar);
+ splitter->addWidget(mainWidget);
+ splitter->setStretchFactor(0, 0);
+ splitter->setStretchFactor(1, 1);
+ splitter->setSizes(QList<int>() << 300 << 300);
+
+ m_mode = new HelpMode(splitter, m_centralWidget);
+ m_mode->setContext(QList<int>() << modecontext);
+ addAutoReleasedObject(m_mode);
+
+ QAction *printAction = new QAction(this);
+ am->registerAction(printAction, Core::Constants::PRINT, modecontext);
+ connect(printAction, SIGNAL(triggered()), m_centralWidget, SLOT(print()));
+
+ QAction *copyAction = new QAction(this);
+ cmd = am->registerAction(copyAction, Core::Constants::COPY, modecontext);
+ connect(copyAction, SIGNAL(triggered()), m_centralWidget, SLOT(copy()));
+ copyAction->setText(cmd->action()->text());
+ copyAction->setIcon(cmd->action()->icon());
+
+ QMap<QString, Core::ICommand*> shortcutMap;
+ QShortcut *shortcut = new QShortcut(splitter);
+ shortcut->setWhatsThis(tr("Activate Index in Help mode"));
+ cmd = am->registerShortcut(shortcut, QLatin1String("Help.IndexShortcut"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_I));
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateIndex()));
+ shortcutMap.insert(m_indexWidget->windowTitle(), cmd);
+
+ shortcut = new QShortcut(splitter);
+ shortcut->setWhatsThis(tr("Activate Contents in Help mode"));
+ cmd = am->registerShortcut(shortcut, QLatin1String("Help.ContentsShortcut"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_T));
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateContents()));
+ shortcutMap.insert(m_contentWidget->windowTitle(), cmd);
+
+ shortcut = new QShortcut(splitter);
+ shortcut->setWhatsThis(tr("Activate Search in Help mode"));
+ cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S));
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
+ shortcutMap.insert(m_searchWidget->windowTitle(), cmd);
+ shortcutMap.insert(m_bookmarkWidget->windowTitle(), 0);
+
+ m_sideBar->setShortcutMap(shortcutMap);
+
+ connect(homeAction, SIGNAL(triggered()), m_centralWidget, SLOT(home()));
+ connect(previousAction, SIGNAL(triggered()), m_centralWidget, SLOT(backward()));
+ connect(nextAction, SIGNAL(triggered()), m_centralWidget, SLOT(forward()));
+ connect(addBookmarkAction, SIGNAL(triggered()), this, SLOT(addBookmark()));
+ connect(m_contentWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_searchWidget, SIGNAL(requestShowLink(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_searchWidget, SIGNAL(requestShowLinkInNewTab(const QUrl&)),
+ m_centralWidget, SLOT(setSourceInNewTab(const QUrl&)));
+ connect(m_bookmarkWidget, SIGNAL(requestShowLink(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+
+ connect(m_centralWidget, SIGNAL(backwardAvailable(bool)),
+ previousAction, SLOT(setEnabled(bool)));
+ connect(m_centralWidget, SIGNAL(forwardAvailable(bool)),
+ nextAction, SLOT(setEnabled(bool)));
+ connect(m_centralWidget, SIGNAL(addNewBookmark(const QString&, const QString&)),
+ this, SLOT(addNewBookmark(const QString&, const QString&)));
+
+ QList<QAction*> actionList;
+ actionList << previousAction
+ << nextAction
+ << homeAction
+#ifndef Q_OS_MAC
+ << sep
+#endif
+ << copyAction;
+ m_centralWidget->setGlobalActions(actionList);
+
+ connect(contextAction, SIGNAL(triggered()), this, SLOT(activateContext()));
+ connect(indexAction, SIGNAL(triggered()), this, SLOT(activateIndex()));
+ connect(contentsAction, SIGNAL(triggered()), this, SLOT(activateContents()));
+ connect(searchAction, SIGNAL(triggered()), this, SLOT(activateSearch()));
+
+ connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*)),
+ this, SLOT(modeChanged(Core::IMode*)));
+
+ connect(m_contentWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linksActivated(const QMap<QString, QUrl>&, const QString&)),
+ m_centralWidget, SLOT(showTopicChooser(const QMap<QString, QUrl>&, const QString&)));
+
+ HelpIndexFilter *helpIndexFilter = new HelpIndexFilter(this, m_helpEngine);
+ addAutoReleasedObject(helpIndexFilter);
+ connect(helpIndexFilter, SIGNAL(linkActivated(QUrl)),
+ this, SLOT(switchToHelpMode(QUrl)));
+ connect(helpIndexFilter, SIGNAL(linksActivated(const QMap<QString, QUrl>&, const QString&)),
+ this, SLOT(switchToHelpMode(const QMap<QString, QUrl>&, const QString&)));
+
+ previousAction->setEnabled(m_centralWidget->isBackwardAvailable());
+ nextAction->setEnabled(m_centralWidget->isForwardAvailable());
+
+ createRightPaneSideBar();
+
+ return true;
+}
+
+void HelpPlugin::createRightPaneSideBar()
+{
+ QAction *switchToHelpMode = new QAction("Go to Help Mode", this);
+ m_rightPaneBackwardAction = new QAction(QIcon(QLatin1String(":/help/images/previous.png")), tr("Previous"), this);
+ m_rightPaneForwardAction = new QAction(QIcon(QLatin1String(":/help/images/next.png")), tr("Next"), this);
+
+ QToolBar *rightPaneToolBar = new QToolBar();
+ rightPaneToolBar->addAction(switchToHelpMode);
+ rightPaneToolBar->addAction(m_rightPaneBackwardAction);
+ rightPaneToolBar->addAction(m_rightPaneForwardAction);
+
+ connect(switchToHelpMode, SIGNAL(triggered()), this, SLOT(switchToHelpMode()));
+ connect(m_rightPaneBackwardAction, SIGNAL(triggered()), this, SLOT(rightPaneBackward()));
+ connect(m_rightPaneForwardAction, SIGNAL(triggered()), this, SLOT(rightPaneForward()));
+
+ QToolButton *closeButton = new QToolButton();
+ closeButton->setProperty("type", QLatin1String("dockbutton"));
+ closeButton->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+
+ // Dummy layout to align the close button to the right
+ QHBoxLayout *hboxLayout = new QHBoxLayout();
+ hboxLayout->setSpacing(0);
+ hboxLayout->setMargin(0);
+ hboxLayout->addStretch(5);
+ hboxLayout->addWidget(closeButton);
+
+ QWidget *w = new QWidget(rightPaneToolBar);
+ w->setLayout(hboxLayout);
+ rightPaneToolBar->addWidget(w);
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(slotHideRightPane()));
+
+ QVBoxLayout *rightPaneLayout = new QVBoxLayout;
+ rightPaneLayout->setMargin(0);
+ rightPaneLayout->setSpacing(0);
+ rightPaneLayout->addWidget(rightPaneToolBar);
+
+ m_helpViewerForSideBar = new HelpViewer(m_helpEngine, 0);
+ rightPaneLayout->addWidget(m_helpViewerForSideBar);
+
+ m_rightPaneSideBar = new QWidget;
+ m_rightPaneSideBar->setLayout(rightPaneLayout);
+ m_rightPaneSideBar->setFocusProxy(m_helpViewerForSideBar);
+ addAutoReleasedObject(new Core::BaseRightPaneWidget(m_rightPaneSideBar));
+}
+
+void HelpPlugin::rightPaneBackward()
+{
+ m_helpViewerForSideBar->backward();
+}
+
+void HelpPlugin::rightPaneForward()
+{
+ m_helpViewerForSideBar->forward();
+}
+
+void HelpPlugin::switchToHelpMode()
+{
+ switchToHelpMode(m_helpViewerForSideBar->source());
+ Core::RightPaneWidget::instance()->setShown(false);
+}
+
+void HelpPlugin::switchToHelpMode(const QUrl &source)
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_centralWidget->setSource(source);
+ m_centralWidget->setFocus();
+}
+
+void HelpPlugin::switchToHelpMode(const QMap<QString, QUrl> &urls, const QString &keyword)
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_centralWidget->showTopicChooser(urls, keyword);
+}
+
+void HelpPlugin::slotHideRightPane()
+{
+ Core::RightPaneWidget::instance()->setShown(false);
+}
+
+void HelpPlugin::extensionsInitialized()
+{
+ m_sideBar->readSettings(m_core->settings());
+ if (!m_helpEngine->setupData()) {
+ qWarning() << "Could not initialize help engine: " << m_helpEngine->error();
+ return;
+ }
+
+ bool needsSetup = false;
+ bool assistantInternalDocRegistered = false;
+
+ foreach (QString ns, m_helpEngine->registeredDocumentations()) {
+ if (ns == QString("com.nokia.qtcreator.%1%2")
+ .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR)) {
+ assistantInternalDocRegistered = true;
+ break;
+ }
+ }
+
+ if (!assistantInternalDocRegistered) {
+ QFileInfo fi(m_helpEngine->collectionFile());
+
+ const QString qchFileName =
+ QDir::cleanPath(QCoreApplication::applicationDirPath()
+#if defined(Q_OS_MAC)
+ + QLatin1String("/../Resources/doc/qtcreator.qch"));
+#else
+ + QLatin1String("/../doc/qtcreator.qch"));
+#endif
+ QHelpEngineCore hc(fi.absoluteFilePath());
+ hc.setupData();
+ if (!hc.registerDocumentation(qchFileName))
+ qDebug() << hc.error();
+ needsSetup = true;
+ }
+
+ int i = m_helpEngine->customValue(
+ QLatin1String("UnfilteredFilterInserted")).toInt();
+ if (i != 1) {
+ {
+ QHelpEngineCore hc(m_helpEngine->collectionFile());
+ hc.setupData();
+ hc.addCustomFilter(tr("Unfiltered"), QStringList());
+ hc.setCustomValue(QLatin1String("UnfilteredFilterInserted"), 1);
+ }
+ m_helpEngine->blockSignals(true);
+ m_helpEngine->setCurrentFilter(tr("Unfiltered"));
+ m_helpEngine->blockSignals(false);
+ needsSetup = true;
+ }
+
+ if (needsSetup)
+ m_helpEngine->setupData();
+
+ updateFilterComboBox();
+ m_bookmarkManager->setupBookmarkModels();
+
+ if (Core::Internal::WelcomeMode *welcomeMode = qobject_cast<Core::Internal::WelcomeMode*>(m_core->modeManager()->mode(Core::Constants::MODE_WELCOME))) {
+ connect(welcomeMode, SIGNAL(requestHelp(QString)), this, SLOT(openGettingStarted()));
+ }
+}
+
+void HelpPlugin::shutdown()
+{
+ m_sideBar->saveSettings(m_core->settings());
+ m_bookmarkManager->saveBookmarks();
+ delete m_bookmarkManager;
+}
+
+void HelpPlugin::setIndexFilter(const QString &filter)
+{
+ m_indexWidget->setSearchLineEditText(filter);
+}
+
+QString HelpPlugin::indexFilter() const
+{
+ return m_indexWidget->searchLineEditText();
+}
+
+void HelpPlugin::modeChanged(Core::IMode *mode)
+{
+ if (mode == m_mode && !m_shownLastPages) {
+ m_shownLastPages = true;
+ qApp->processEvents();
+ qApp->setOverrideCursor(Qt::WaitCursor);
+ m_centralWidget->setLastShownPages();
+ qApp->restoreOverrideCursor();
+ }
+}
+
+void HelpPlugin::activateContext()
+{
+ using namespace Core;
+ // case 1 sidebar shown and has focus, we show whatever we have in the
+ // sidebar in big
+ RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current();
+ if(placeHolder && Core::RightPaneWidget::instance()->hasFocus()) {
+ switchToHelpMode();
+ return;
+ }
+
+ bool useSideBar = false;
+ if (placeHolder && !Core::RightPaneWidget::instance()->hasFocus())
+ useSideBar = true;
+
+ // Find out what to show
+ HelpViewer *viewer = 0;
+ if (IContext *context = m_core->currentContextObject()) {
+ if (!m_contextHelpEngine) {
+ m_contextHelpEngine = new QHelpEngineCore(m_helpEngine->collectionFile(), this);
+ //m_contextHelpEngine->setAutoSaveFilter(false);
+ m_contextHelpEngine->setupData();
+ m_contextHelpEngine->setCurrentFilter(tr("Unfiltered"));
+ }
+
+ const QString &id = context->contextHelpId();
+ QMap<QString, QUrl> links = m_contextHelpEngine->linksForIdentifier(id);
+ if (!links.isEmpty()) {
+ if (useSideBar) {
+ Core::RightPaneWidget::instance()->setShown(true);
+ viewer = m_helpViewerForSideBar;
+ } else {
+ viewer = m_centralWidget->currentHelpViewer();
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ }
+
+ if (viewer) {
+ QUrl source = *links.begin();
+ if (viewer->source() != source)
+ viewer->setSource(source);
+ viewer->setFocus();
+ }
+ } else {
+ // No link found
+ if (useSideBar) {
+ Core::RightPaneWidget::instance()->setShown(true);
+ viewer = m_helpViewerForSideBar;
+ } else {
+ viewer = m_centralWidget->currentHelpViewer();
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ }
+
+ if (viewer) {
+ viewer->setHtml(tr("<title>No Documentation</title><br><br>"
+ "<center><b>%1</b><br><br>No documentation available.").
+ arg(id));
+ viewer->setSource(QUrl());
+ //activateIndex();
+ }
+ }
+ } else {
+ // No context object
+ if (useSideBar) {
+ Core::RightPaneWidget::instance()->setShown(true);
+ viewer = m_helpViewerForSideBar;
+ } else {
+ viewer = m_centralWidget->currentHelpViewer();
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ }
+
+ if (viewer) {
+ viewer->setSource(QUrl());
+ viewer->setHtml("<title>No Documentation</title><br><br><center>No"
+ " documentation available.");
+ //activateIndex();
+ }
+ }
+}
+
+void HelpPlugin::activateIndex()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_sideBar->activateItem(m_indexItem);
+}
+
+void HelpPlugin::activateContents()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_sideBar->activateItem(m_contentItem);
+}
+
+void HelpPlugin::activateSearch()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_sideBar->activateItem(m_searchItem);
+}
+
+QToolBar *HelpPlugin::createToolBar()
+{
+ QToolBar *toolWidget = new QToolBar;
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ toolWidget->addAction(am->command(QLatin1String("Help.Home"))->action());
+ toolWidget->addAction(am->command(QLatin1String("Help.Previous"))->action());
+ toolWidget->addAction(am->command(QLatin1String("Help.Next"))->action());
+ toolWidget->addSeparator();
+ toolWidget->addAction(am->command(QLatin1String("Help.AddBookmark"))->action());
+ //int size = toolWidget->style()->pixelMetric(QStyle::PM_SmallIconSize);
+ //toolWidget->setIconSize(QSize(size, size));
+ toolWidget->setMovable(false);
+
+ toolWidget->addSeparator();
+
+ QWidget *w = new QWidget;
+ QHBoxLayout *layout = new QHBoxLayout(w);
+ layout->setMargin(0);
+ layout->addSpacing(10);
+ layout->addWidget(new QLabel(tr("Filtered by:")));
+ m_filterComboBox = new QComboBox;
+ m_filterComboBox->setMinimumContentsLength(20);
+ connect(m_filterComboBox, SIGNAL(activated(const QString&)),
+ this, SLOT(filterDocumentation(const QString&)));
+ layout->addWidget(m_filterComboBox);
+ toolWidget->addWidget(w);
+
+ return toolWidget;
+}
+
+void HelpPlugin::updateFilterComboBox()
+{
+ QString curFilter = m_filterComboBox->currentText();
+ if (curFilter.isEmpty())
+ curFilter = m_helpEngine->currentFilter();
+ m_filterComboBox->clear();
+ m_filterComboBox->addItems(m_helpEngine->customFilters());
+ int idx = m_filterComboBox->findText(curFilter);
+ if (idx < 0)
+ idx = 0;
+ m_filterComboBox->setCurrentIndex(idx);
+}
+
+void HelpPlugin::checkForHelpChanges()
+{
+ bool changed = m_docSettingsPage->applyChanges();
+ changed |= m_filterSettingsPage->applyChanges();
+ if (changed)
+ m_helpEngine->setupData();
+}
+
+void HelpPlugin::filterDocumentation(const QString &customFilter)
+{
+ m_helpEngine->setCurrentFilter(customFilter);
+}
+
+void HelpPlugin::addBookmark()
+{
+ addNewBookmark(m_centralWidget->currentTitle(), m_centralWidget->currentSource().toString());
+}
+
+void HelpPlugin::addNewBookmark(const QString &title, const QString &url)
+{
+ if (url.isEmpty())
+ return;
+
+ m_bookmarkManager->showBookmarkDialog(m_centralWidget, title, url);
+}
+
+void HelpPlugin::openGettingStarted()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_centralWidget->setSource(
+ QString("qthelp://com.nokia.qtcreator.%1%2/doc/index.html")
+ .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR));
+}
+
+
+Q_EXPORT_PLUGIN(HelpPlugin)
diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h
new file mode 100644
index 0000000000..21dab96dc9
--- /dev/null
+++ b/src/plugins/help/helpplugin.h
@@ -0,0 +1,169 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef HELPPLUGIN_H
+#define HELPPLUGIN_H
+
+#include "help_global.h"
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QComboBox;
+class QHelpEngineCore;
+class QHelpEngine;
+class QShortcut;
+class QToolBar;
+class QUrl;
+
+class IndexWindow;
+class ContentWindow;
+class BookmarkManager;
+class BookmarkWidget;
+class CentralWidget;
+class HelpViewer;
+QT_END_NAMESPACE
+
+
+namespace Core {
+class ICore;
+class IMode;
+class SideBar;
+class SideBarItem;
+}
+
+namespace Help {
+
+namespace Constants {
+ const char * const HELPVIEWER_KIND = "Qt Help Viewer";
+ const char * const C_MODE_HELP = "Help Mode";
+ const int P_MODE_HELP = 70;
+ const char * const ID_MODE_HELP = "Help.HelpMode";
+}
+
+class HELP_EXPORT HelpManager : public QObject
+{
+ Q_OBJECT
+public:
+ HelpManager(QHelpEngine *helpEngine);
+
+ void registerDocumentation(const QStringList &fileNames);
+
+private:
+ QHelpEngine *m_helpEngine;
+};
+
+namespace Internal {
+
+class HelpMode;
+class HelpPluginEditorFactory;
+class DocSettingsPage;
+class FilterSettingsPage;
+class SearchWidget;
+
+class HelpPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ HelpPlugin();
+ virtual ~HelpPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ void shutdown();
+
+ // Necessary to get the unfiltered list in the help index filter
+ void setIndexFilter(const QString &filter);
+ QString indexFilter() const;
+
+private slots:
+ void modeChanged(Core::IMode *mode);
+ void activateContext();
+ void activateIndex();
+ void activateContents();
+ void activateSearch();
+ void checkForHelpChanges();
+ void updateFilterComboBox();
+ void filterDocumentation(const QString &customFilter);
+ void addBookmark();
+ void addNewBookmark(const QString &title, const QString &url);
+
+ void rightPaneBackward();
+ void rightPaneForward();
+ void switchToHelpMode();
+ void switchToHelpMode(const QUrl &source);
+ void switchToHelpMode(const QMap<QString, QUrl> &urls, const QString &keyword);
+ void slotHideRightPane();
+
+ void openGettingStarted();
+
+private:
+ QToolBar *createToolBar();
+ void createRightPaneSideBar();
+
+ Core::ICore *m_core;
+ QHelpEngine *m_helpEngine;
+ QHelpEngineCore *m_contextHelpEngine;
+ ContentWindow *m_contentWidget;
+ IndexWindow *m_indexWidget;
+ BookmarkWidget *m_bookmarkWidget;
+ BookmarkManager *m_bookmarkManager;
+ SearchWidget *m_searchWidget;
+ CentralWidget *m_centralWidget;
+ HelpViewer *m_helpViewerForSideBar;
+ HelpMode *m_mode;
+ bool m_shownLastPages;
+
+ Core::SideBarItem *m_contentItem;
+ Core::SideBarItem *m_indexItem;
+ Core::SideBarItem *m_searchItem;
+ Core::SideBarItem *m_bookmarkItem;
+
+ DocSettingsPage *m_docSettingsPage;
+ FilterSettingsPage *m_filterSettingsPage;
+
+ QComboBox *m_filterComboBox;
+ Core::SideBar *m_sideBar;
+ QWidget *m_rightPaneSideBar;
+
+ QAction *m_rightPaneBackwardAction;
+ QAction *m_rightPaneForwardAction;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPPLUGIN_H
diff --git a/src/plugins/help/images/book.png b/src/plugins/help/images/book.png
new file mode 100644
index 0000000000..ecd311b31f
--- /dev/null
+++ b/src/plugins/help/images/book.png
Binary files differ
diff --git a/src/plugins/help/images/bookmark.png b/src/plugins/help/images/bookmark.png
new file mode 100644
index 0000000000..7b2e5fd0ce
--- /dev/null
+++ b/src/plugins/help/images/bookmark.png
Binary files differ
diff --git a/src/plugins/help/images/find.png b/src/plugins/help/images/find.png
new file mode 100644
index 0000000000..fafcd3bb21
--- /dev/null
+++ b/src/plugins/help/images/find.png
Binary files differ
diff --git a/src/plugins/help/images/home.png b/src/plugins/help/images/home.png
new file mode 100644
index 0000000000..9cee3025d0
--- /dev/null
+++ b/src/plugins/help/images/home.png
Binary files differ
diff --git a/src/plugins/help/images/mac/addtab.png b/src/plugins/help/images/mac/addtab.png
new file mode 100644
index 0000000000..20928fb402
--- /dev/null
+++ b/src/plugins/help/images/mac/addtab.png
Binary files differ
diff --git a/src/plugins/help/images/mac/closetab.png b/src/plugins/help/images/mac/closetab.png
new file mode 100644
index 0000000000..ab9d669eee
--- /dev/null
+++ b/src/plugins/help/images/mac/closetab.png
Binary files differ
diff --git a/src/plugins/help/images/next.png b/src/plugins/help/images/next.png
new file mode 100644
index 0000000000..7700d6fce6
--- /dev/null
+++ b/src/plugins/help/images/next.png
Binary files differ
diff --git a/src/plugins/help/images/previous.png b/src/plugins/help/images/previous.png
new file mode 100644
index 0000000000..99dc8733c7
--- /dev/null
+++ b/src/plugins/help/images/previous.png
Binary files differ
diff --git a/src/plugins/help/images/win/addtab.png b/src/plugins/help/images/win/addtab.png
new file mode 100644
index 0000000000..4bb0feb92d
--- /dev/null
+++ b/src/plugins/help/images/win/addtab.png
Binary files differ
diff --git a/src/plugins/help/images/win/closetab.png b/src/plugins/help/images/win/closetab.png
new file mode 100644
index 0000000000..ef9e02086c
--- /dev/null
+++ b/src/plugins/help/images/win/closetab.png
Binary files differ
diff --git a/src/plugins/help/indextoolwindow.cpp b/src/plugins/help/indextoolwindow.cpp
new file mode 100644
index 0000000000..f80bd453cb
--- /dev/null
+++ b/src/plugins/help/indextoolwindow.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QListView>
+#include <QtGui/QApplication>
+
+#include "indextoolwindow.h"
+#include "helpengine.h"
+#include "topicchooser.h"
+
+using namespace Help::Internal;
+
+IndexToolWidget::IndexToolWidget()
+{
+ wasInitialized = false;
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+
+ QLabel *l = new QLabel(tr("Look for:"), this);
+ layout->addWidget(l);
+
+ findLineEdit = new QLineEdit(this);
+ findLineEdit->installEventFilter(this);
+ layout->addWidget(findLineEdit);
+
+ indicesView = new QListView(this);
+ indicesView->setLayoutMode(QListView::Batched);
+ indicesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ layout->addWidget(indicesView);
+
+ setWindowTitle(tr("Index"));
+ setWindowIcon(QIcon(":/help/images/find.png"));
+}
+
+void IndexToolWidget::focusInEvent(QFocusEvent *e)
+{
+ showEvent(0);
+ if (e && e->reason() != Qt::MouseFocusReason) {
+ findLineEdit->selectAll();
+ findLineEdit->setFocus();
+ }
+}
+
+void IndexToolWidget::showEvent(QShowEvent *)
+{
+ if (!wasInitialized) {
+ wasInitialized = true;
+ setCursor(QCursor(Qt::WaitCursor));
+ emit buildRequested();
+ }
+}
+
+bool IndexToolWidget::eventFilter(QObject * o, QEvent * e)
+{
+ if (o == findLineEdit && e->type() == QEvent::KeyPress) {
+ switch (static_cast<QKeyEvent*>(e)->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageDown:
+ case Qt::Key_PageUp:
+ QApplication::sendEvent(indicesView, e);
+ break;
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+ default:
+ break;
+ }
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+
+IndexToolWindow::IndexToolWindow(const QList<int> &context, HelpEngine *help)
+{
+ m_context = context;
+ m_context << 0;
+
+ m_widget = new IndexToolWidget;
+
+ helpEngine = help;
+ connect(helpEngine, SIGNAL(indexInitialized()), this, SLOT(indexDone()));
+ model = 0;
+
+ connect(m_widget->findLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(searchInIndex(const QString &)));
+ connect(m_widget->findLineEdit, SIGNAL(returnPressed()), this, SLOT(indexRequested()));
+ connect(m_widget, SIGNAL(buildRequested()), helpEngine, SLOT(buildIndex()));
+
+ connect(m_widget->indicesView, SIGNAL(activated(const QModelIndex&)),
+ this, SLOT(indexRequested()));
+ connect(m_widget, SIGNAL(escapePressed()), this, SIGNAL(escapePressed()));
+
+}
+
+IndexToolWindow::~IndexToolWindow()
+{
+ delete m_widget;
+}
+
+const QList<int> &IndexToolWindow::context() const
+{
+ return m_context;
+}
+
+QWidget *IndexToolWindow::widget()
+{
+ return m_widget;
+}
+
+void IndexToolWindow::indexDone()
+{
+ model = helpEngine->indices();
+ m_widget->indicesView->setModel(model);
+ m_widget->setCursor(QCursor(Qt::ArrowCursor));
+}
+
+void IndexToolWindow::searchInIndex(const QString &str)
+{
+ if (!model)
+ return;
+ QRegExp atoz("[A-Z]");
+ int matches = str.count(atoz);
+ if (matches > 0 && !str.contains(".*"))
+ {
+ int start = 0;
+ QString newSearch;
+ for (; matches > 0; --matches) {
+ int match = str.indexOf(atoz, start+1);
+ if (match <= start)
+ continue;
+ newSearch += str.mid(start, match-start);
+ newSearch += ".*";
+ start = match;
+ }
+ newSearch += str.mid(start);
+ m_widget->indicesView->setCurrentIndex(model->filter(newSearch, str));
+ }
+ else
+ m_widget->indicesView->setCurrentIndex(model->filter(str, str));
+}
+
+void IndexToolWindow::indexRequested()
+{
+ if (!model)
+ return;
+ int row = m_widget->indicesView->currentIndex().row();
+ if (row == -1 || row >= model->rowCount())
+ return;
+
+ QString description = model->description(row);
+ QStringList links = model->links(row);
+
+ bool blocked = m_widget->findLineEdit->blockSignals(true);
+ m_widget->findLineEdit->setText(description);
+ m_widget->findLineEdit->blockSignals(blocked);
+
+ if (links.count() == 1) {
+ emit showLinkRequested(links.first(), false);
+ } else {
+ qSort(links);
+ QStringList::Iterator it = links.begin();
+ QStringList linkList;
+ QStringList linkNames;
+ for (; it != links.end(); ++it) {
+ linkList << *it;
+ linkNames << helpEngine->titleOfLink(*it);
+ }
+ QString link = TopicChooser::getLink(m_widget, linkNames, linkList, description);
+ if (!link.isEmpty())
+ emit showLinkRequested(link, false);
+ }
+
+ model->publish();
+ m_widget->indicesView->setCurrentIndex(model->index(model->stringList().indexOf(description)));
+ m_widget->indicesView->scrollTo(m_widget->indicesView->currentIndex(), QAbstractItemView::PositionAtTop);
+}
+
diff --git a/src/plugins/help/indextoolwindow.h b/src/plugins/help/indextoolwindow.h
new file mode 100644
index 0000000000..4d4eb8f6b2
--- /dev/null
+++ b/src/plugins/help/indextoolwindow.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INDEXTOOLWINDOW_H
+#define INDEXTOOLWINDOW_H
+
+#include <QtCore/QModelIndex>
+#include <QtGui/QWidget>
+
+#include <coreplugin/iview.h>
+
+class QListView;
+class QLineEdit;
+
+namespace Help {
+namespace Internal {
+
+class HelpEngine;
+class IndexListModel;
+class IndexToolWindow;
+
+class IndexToolWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ IndexToolWidget();
+
+signals:
+ void buildRequested();
+ void escapePressed();
+
+private:
+ friend class IndexToolWindow;
+
+ bool eventFilter(QObject * o, QEvent * e);
+ void showEvent(QShowEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ bool wasInitialized;
+ QLineEdit *findLineEdit;
+ QListView *indicesView;
+};
+
+
+class IndexToolWindow : public Core::IView
+{
+ Q_OBJECT
+
+public:
+ IndexToolWindow(const QList<int> &context, HelpEngine *help);
+ ~IndexToolWindow();
+
+ const QList<int> &context() const;
+ QWidget *widget();
+
+ QList<QWidget*> dockToolBarWidgets() const { return QList<QWidget*>(); }
+
+ const char *uniqueViewName() const { return "Help.IndexToolWindow"; }
+ const char *globalMenuGroup() const { return "Help.Group"; }
+ inline QKeySequence defaultShortcut() const { return QKeySequence(); }
+ Qt::DockWidgetArea defaultArea() const { return Qt::RightDockWidgetArea; }
+ IView::ViewPosition defaultPosition() const { return IView::Second; }
+
+signals:
+ void showLinkRequested(const QString &link, bool newWindow);
+ void escapePressed();
+
+private slots:
+ void indexDone();
+ void searchInIndex(const QString &str);
+ void indexRequested();
+
+private:
+ HelpEngine *helpEngine;
+ IndexListModel *model;
+
+ QList<int> m_context;
+ IndexToolWidget *m_widget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // INDEXTOOLWINDOW_H
diff --git a/src/plugins/help/indexwindow.h b/src/plugins/help/indexwindow.h
new file mode 100644
index 0000000000..a0e43a3f2a
--- /dev/null
+++ b/src/plugins/help/indexwindow.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INDEXWINDOW
+#define INDEXWINDOW
+
+#include <QtCore/QUrl>
+#include <QtGui/QWidget>
+#include <QtGui/QLineEdit>
+
+QT_BEGIN_NAMESPACE
+
+class QHelpIndexWidget;
+class QHelpEngine;
+
+class IndexWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0);
+ ~IndexWindow();
+
+ void setSearchLineEditText(const QString &text);
+ QString searchLineEditText() const
+ {
+ return m_searchLineEdit->text();
+ }
+
+signals:
+ void linkActivated(const QUrl &link);
+ void linksActivated(const QMap<QString, QUrl> &links,
+ const QString &keyword);
+ void escapePressed();
+
+private slots:
+ void filterIndices(const QString &filter);
+ void enableSearchLineEdit();
+ void disableSearchLineEdit();
+
+private:
+ bool eventFilter(QObject *obj, QEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ QLineEdit *m_searchLineEdit;
+ QHelpIndexWidget *m_indexWidget;
+ QHelpEngine *m_helpEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/help/searchwidget.cpp b/src/plugins/help/searchwidget.cpp
new file mode 100644
index 0000000000..620ca7ef76
--- /dev/null
+++ b/src/plugins/help/searchwidget.cpp
@@ -0,0 +1,213 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "searchwidget.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+#include <QtGui/QMenu>
+#include <QtGui/QLayout>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+#include <QtGui/QApplication>
+#include <QtGui/QTextBrowser>
+
+#include <QtHelp/QHelpSearchEngine>
+#include <QtHelp/QHelpSearchQueryWidget>
+#include <QtHelp/QHelpSearchResultWidget>
+
+using namespace Help::Internal;
+
+SearchWidget::SearchWidget(QHelpSearchEngine *engine, QWidget *parent)
+ : QWidget(parent)
+ , zoomCount(0)
+ , searchEngine(engine)
+{
+ QVBoxLayout *vLayout = new QVBoxLayout(this);
+
+ resultWidget = searchEngine->resultWidget();
+ QHelpSearchQueryWidget *queryWidget = searchEngine->queryWidget();
+
+ vLayout->addWidget(queryWidget);
+ vLayout->addWidget(resultWidget);
+
+ setFocusProxy(queryWidget);
+
+ connect(queryWidget, SIGNAL(search()), this, SLOT(search()));
+ connect(resultWidget, SIGNAL(requestShowLink(const QUrl&)),
+ this, SIGNAL(requestShowLink(const QUrl&)));
+
+ connect(searchEngine, SIGNAL(searchingStarted()), this, SLOT(searchingStarted()));
+ connect(searchEngine, SIGNAL(searchingFinished(int)), this, SLOT(searchingFinished(int)));
+}
+
+SearchWidget::~SearchWidget()
+{
+ // nothing todo
+}
+
+void SearchWidget::zoomIn()
+{
+#ifndef QT_CLUCENE_SUPPORT
+ return;
+#endif
+
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (browser && zoomCount != 10) {
+ zoomCount++;
+ browser->zoomIn();
+ }
+}
+
+void SearchWidget::zoomOut()
+{
+#ifndef QT_CLUCENE_SUPPORT
+ return;
+#endif
+
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (browser && zoomCount != -5) {
+ zoomCount--;
+ browser->zoomOut();
+ }
+}
+
+void SearchWidget::resetZoom()
+{
+#ifndef QT_CLUCENE_SUPPORT
+ return;
+#endif
+
+ if (zoomCount == 0)
+ return;
+
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (browser) {
+ browser->zoomOut(zoomCount);
+ zoomCount = 0;
+ }
+}
+
+void SearchWidget::search() const
+{
+ QList<QHelpSearchQuery> query = searchEngine->queryWidget()->query();
+ searchEngine->search(query);
+}
+
+void SearchWidget::searchingStarted()
+{
+ qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
+}
+
+void SearchWidget::searchingFinished(int hits)
+{
+ Q_UNUSED(hits)
+ qApp->restoreOverrideCursor();
+}
+
+void SearchWidget::keyPressEvent(QKeyEvent *keyEvent)
+{
+ if (keyEvent->key() == Qt::Key_Escape)
+ emit escapePressed();
+}
+
+void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
+{
+ QMenu menu;
+ QPoint point = contextMenuEvent->globalPos();
+
+#ifdef QT_CLUCENE_SUPPORT
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (!browser)
+ return;
+
+ point = browser->mapFromGlobal(point);
+ if (!browser->rect().contains(point, true))
+ return;
+
+ QUrl link = browser->anchorAt(point);
+
+ QAction *copyAction = menu.addAction(tr("&Copy") +
+ QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_C))));
+ copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection());
+
+ QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location"));
+ copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid());
+
+ QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") +
+ QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL))) +
+ QLatin1String("LMB"));
+ newTabAction->setEnabled(!link.isEmpty() && link.isValid());
+
+ menu.addSeparator();
+
+ QAction *selectAllAction = menu.addAction(tr("Select All") +
+ QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_A))));
+
+ QAction *usedAction = menu.exec(mapToGlobal(contextMenuEvent->pos()));
+ if (usedAction == copyAction) {
+ QTextCursor cursor = browser->textCursor();
+ if (!cursor.isNull() && cursor.hasSelection()) {
+ QString selectedText = cursor.selectedText();
+ QMimeData *data = new QMimeData();
+ data->setText(selectedText);
+ QApplication::clipboard()->setMimeData(data);
+ }
+ }
+ else if (usedAction == copyAnchorAction) {
+ QApplication::clipboard()->setText(link.toString());
+ }
+ else if (usedAction == newTabAction) {
+ emit requestShowLinkInNewTab(link);
+ }
+ else if (usedAction == selectAllAction) {
+ browser->selectAll();
+ }
+#else
+ point = resultWidget->mapFromGlobal(point);
+ QUrl link = resultWidget->linkAt(point);
+ if (link.isEmpty() || !link.isValid())
+ return;
+
+ QAction *curTab = menu.addAction(tr("Open Link"));
+ QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
+
+ QAction *action = menu.exec(mapToGlobal(contextMenuEvent->pos()));
+ if (curTab == action)
+ emit requestShowLink(link);
+ else if (newTab == action)
+ emit requestShowLinkInNewTab(link);
+#endif
+}
diff --git a/src/plugins/help/searchwidget.h b/src/plugins/help/searchwidget.h
new file mode 100644
index 0000000000..64143fafbf
--- /dev/null
+++ b/src/plugins/help/searchwidget.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef SEARCHWIDGET_H
+#define SEARCHWIDGET_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QPoint>
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QMouseEvent;
+class QHelpSearchEngine;
+class QHelpSearchResultWidget;
+
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class SearchWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SearchWidget(QHelpSearchEngine *engine, QWidget *parent = 0);
+ ~SearchWidget();
+
+ void zoomIn();
+ void zoomOut();
+ void resetZoom();
+
+signals:
+ void requestShowLink(const QUrl &url);
+ void requestShowLinkInNewTab(const QUrl &url);
+ void escapePressed();
+
+private slots:
+ void search() const;
+ void searchingStarted();
+ void searchingFinished(int hits);
+
+private:
+ void keyPressEvent(QKeyEvent *keyEvent);
+ void contextMenuEvent(QContextMenuEvent *contextMenuEvent);
+
+private:
+ int zoomCount;
+ QHelpSearchEngine *searchEngine;
+ QHelpSearchResultWidget *resultWidget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // SEARCHWIDGET_H
diff --git a/src/plugins/perforce/Perforce.mimetypes.xml b/src/plugins/perforce/Perforce.mimetypes.xml
new file mode 100644
index 0000000000..3c2d332771
--- /dev/null
+++ b/src/plugins/perforce/Perforce.mimetypes.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/vnd.nokia.text.p4.submit">
+ <comment>Perforce submit template</comment>
+ <sub-class-of type="text/plain"/>
+ <magic priority="50">
+ <match value="# A Perforce Change Specification." type="string" offset="0"/>
+ </magic>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/perforce/Perforce.pluginspec b/src/plugins/perforce/Perforce.pluginspec
new file mode 100644
index 0000000000..367b3afd79
--- /dev/null
+++ b/src/plugins/perforce/Perforce.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="Perforce" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Perforce integration.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="VCSBase" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/perforce/annotationhighlighter.cpp b/src/plugins/perforce/annotationhighlighter.cpp
new file mode 100644
index 0000000000..ab4b855c4b
--- /dev/null
+++ b/src/plugins/perforce/annotationhighlighter.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "annotationhighlighter.h"
+
+namespace Perforce {
+namespace Internal {
+
+PerforceAnnotationHighlighter::PerforceAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ VCSBase::BaseAnnotationHighlighter(changeNumbers, document),
+ m_colon(QLatin1Char(':'))
+{
+}
+
+QString PerforceAnnotationHighlighter::changeNumber(const QString &block) const
+{
+ const int pos = block.indexOf(m_colon);
+ return pos > 1 ? block.left(pos) : QString();
+}
+
+}
+}
diff --git a/src/plugins/perforce/annotationhighlighter.h b/src/plugins/perforce/annotationhighlighter.h
new file mode 100644
index 0000000000..e162753c4b
--- /dev/null
+++ b/src/plugins/perforce/annotationhighlighter.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ANNOTATIONHIGHLIGHTER_H
+#define ANNOTATIONHIGHLIGHTER_H
+
+#include <vcsbase/baseannotationhighlighter.h>
+
+namespace Perforce {
+namespace Internal {
+
+// Annotation highlighter for p4 triggering on 'changenumber:'
+class PerforceAnnotationHighlighter : public VCSBase::BaseAnnotationHighlighter
+{
+ Q_OBJECT
+public:
+ explicit PerforceAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = 0);
+
+private:
+ virtual QString changeNumber(const QString &block) const;
+
+ const QChar m_colon;
+};
+
+} //namespace Perforce
+} //namespace Internal
+
+#endif
diff --git a/src/plugins/perforce/changenumberdialog.cpp b/src/plugins/perforce/changenumberdialog.cpp
new file mode 100644
index 0000000000..8bf5827900
--- /dev/null
+++ b/src/plugins/perforce/changenumberdialog.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QIntValidator>
+
+#include "changenumberdialog.h"
+
+using namespace Perforce::Internal;
+
+ChangeNumberDialog::ChangeNumberDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ m_ui.numberLineEdit->setValidator(new QIntValidator(0, 1000000, this));
+}
+
+int ChangeNumberDialog::number() const
+{
+ if (m_ui.numberLineEdit->text().isEmpty())
+ return -1;
+ bool ok;
+ return m_ui.numberLineEdit->text().toInt(&ok);
+}
diff --git a/src/plugins/perforce/changenumberdialog.h b/src/plugins/perforce/changenumberdialog.h
new file mode 100644
index 0000000000..cc2429f297
--- /dev/null
+++ b/src/plugins/perforce/changenumberdialog.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CHANGENUMBERDIALOG_H
+#define CHANGENUMBERDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_changenumberdialog.h"
+
+namespace Perforce {
+namespace Internal {
+
+// Input a change number for pending changes.
+class ChangeNumberDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ChangeNumberDialog(QWidget *parent = 0);
+ int number() const;
+
+private:
+ Ui::ChangeNumberDialog m_ui;
+
+};
+
+} //namespace Perforce
+} //namespace Internal
+
+#endif
+
+
diff --git a/src/plugins/perforce/changenumberdialog.ui b/src/plugins/perforce/changenumberdialog.ui
new file mode 100644
index 0000000000..6fbcbc32e3
--- /dev/null
+++ b/src/plugins/perforce/changenumberdialog.ui
@@ -0,0 +1,79 @@
+<ui version="4.0" >
+ <class>Perforce::Internal::ChangeNumberDialog</class>
+ <widget class="QDialog" name="Perforce::Internal::ChangeNumberDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>319</width>
+ <height>76</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Change Number</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="numberLineEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Change Number:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Perforce::Internal::ChangeNumberDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>59</x>
+ <y>24</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>160</x>
+ <y>38</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Perforce::Internal::ChangeNumberDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>59</x>
+ <y>24</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>160</x>
+ <y>38</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/images/diff.png b/src/plugins/perforce/images/diff.png
new file mode 100644
index 0000000000..b3597f9ff8
--- /dev/null
+++ b/src/plugins/perforce/images/diff.png
Binary files differ
diff --git a/src/plugins/perforce/images/submit.png b/src/plugins/perforce/images/submit.png
new file mode 100644
index 0000000000..4f302302b9
--- /dev/null
+++ b/src/plugins/perforce/images/submit.png
Binary files differ
diff --git a/src/plugins/perforce/p4.h b/src/plugins/perforce/p4.h
new file mode 100644
index 0000000000..70c1838491
--- /dev/null
+++ b/src/plugins/perforce/p4.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef P4_API_INCL
+#define P4_API_INCL
+
+#include <qconfig.h>
+
+#ifdef USE_P4_API
+#
+# if defined(Q_OS_WIN) && defined(SetPort)
+# undef SetPort
+# endif
+#
+# include <clientapi.h>
+# include <diff.h>
+#endif
+
+#endif // P4_API_INCL
diff --git a/src/plugins/perforce/pendingchangesdialog.cpp b/src/plugins/perforce/pendingchangesdialog.cpp
new file mode 100644
index 0000000000..971153ba97
--- /dev/null
+++ b/src/plugins/perforce/pendingchangesdialog.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QRegExp>
+
+#include "pendingchangesdialog.h"
+
+using namespace Perforce::Internal;
+
+PendingChangesDialog::PendingChangesDialog(const QString &data, QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ if (!data.isEmpty()) {
+ QRegExp r("Change\\s(\\d+).*\\s\\*pending\\*\\s(.+)\n");
+ r.setMinimal(true);
+ int pos = 0;
+ QListWidgetItem *item;
+ while ((pos = r.indexIn(data, pos)) != -1) {
+ item = new QListWidgetItem(tr("Change %1: %2").arg(r.cap(1))
+ .arg(r.cap(2).trimmed()), m_ui.listWidget);
+ item->setData(234, r.cap(1).trimmed());
+ ++pos;
+ }
+ }
+ m_ui.listWidget->setSelectionMode(QListWidget::SingleSelection);
+ if (m_ui.listWidget->count()) {
+ m_ui.listWidget->setCurrentRow(0);
+ m_ui.submitButton->setEnabled(true);
+ } else {
+ m_ui.submitButton->setEnabled(false);
+ }
+}
+
+int PendingChangesDialog::changeNumber() const
+{
+ QListWidgetItem *item = m_ui.listWidget->item(m_ui.listWidget->currentRow());
+ if (!item)
+ return -1;
+ bool ok = true;
+ int i = item->data(234).toInt(&ok);
+ return ok ? i : -1;
+}
diff --git a/src/plugins/perforce/pendingchangesdialog.h b/src/plugins/perforce/pendingchangesdialog.h
new file mode 100644
index 0000000000..b31acf367a
--- /dev/null
+++ b/src/plugins/perforce/pendingchangesdialog.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PENDINGCHANGESDIALOG_H
+#define PENDINGCHANGESDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_pendingchangesdialog.h"
+
+namespace Perforce {
+namespace Internal {
+
+class PendingChangesDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ PendingChangesDialog(const QString &data, QWidget *parent = 0);
+ int changeNumber() const;
+
+private:
+ Ui::PendingChangesDialog m_ui;
+};
+
+} //namespace Perforce
+} //namespace Internal
+
+#endif
+
diff --git a/src/plugins/perforce/pendingchangesdialog.ui b/src/plugins/perforce/pendingchangesdialog.ui
new file mode 100644
index 0000000000..bcee662a02
--- /dev/null
+++ b/src/plugins/perforce/pendingchangesdialog.ui
@@ -0,0 +1,99 @@
+<ui version="4.0" >
+ <class>Perforce::Internal::PendingChangesDialog</class>
+ <widget class="QDialog" name="Perforce::Internal::PendingChangesDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>333</width>
+ <height>126</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>P4 Pending Changes</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="listWidget" />
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>131</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="submitButton" >
+ <property name="text" >
+ <string>Submit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>submitButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Perforce::Internal::PendingChangesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>278</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>96</x>
+ <y>254</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Perforce::Internal::PendingChangesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>369</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>179</x>
+ <y>282</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/perforce.pro b/src/plugins/perforce/perforce.pro
new file mode 100644
index 0000000000..992777f172
--- /dev/null
+++ b/src/plugins/perforce/perforce.pro
@@ -0,0 +1,38 @@
+TEMPLATE = lib
+TARGET = Perforce
+
+include(../../qworkbenchplugin.pri)
+include(perforce_dependencies.pri)
+
+HEADERS += p4.h \
+ perforceplugin.h \
+ perforceoutputwindow.h \
+ settingspage.h \
+ perforceeditor.h \
+ changenumberdialog.h \
+ perforcesubmiteditor.h \
+ pendingchangesdialog.h \
+ perforceconstants.h \
+ perforceversioncontrol.h \
+ perforcesettings.h \
+ annotationhighlighter.h \
+ perforcesubmiteditorwidget.h
+
+SOURCES += perforceplugin.cpp \
+ perforceoutputwindow.cpp \
+ settingspage.cpp \
+ perforceeditor.cpp \
+ changenumberdialog.cpp \
+ perforcesubmiteditor.cpp \
+ pendingchangesdialog.cpp \
+ perforceversioncontrol.cpp \
+ perforcesettings.cpp \
+ annotationhighlighter.cpp \
+ perforcesubmiteditorwidget.cpp
+
+FORMS += settingspage.ui \
+ changenumberdialog.ui \
+ pendingchangesdialog.ui \
+ submitpanel.ui
+
+RESOURCES += perforce.qrc
diff --git a/src/plugins/perforce/perforce.qrc b/src/plugins/perforce/perforce.qrc
new file mode 100644
index 0000000000..de0db02a3d
--- /dev/null
+++ b/src/plugins/perforce/perforce.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/trolltech.perforce" >
+ <file>images/diff.png</file>
+ <file>images/submit.png</file>
+ <file>Perforce.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/perforce/perforce_dependencies.pri b/src/plugins/perforce/perforce_dependencies.pri
new file mode 100644
index 0000000000..9e7c28e9e1
--- /dev/null
+++ b/src/plugins/perforce/perforce_dependencies.pri
@@ -0,0 +1,5 @@
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/vcsbase/vcsbase.pri)
+include(../../libs/utils/utils.pri)
diff --git a/src/plugins/perforce/perforceconstants.h b/src/plugins/perforce/perforceconstants.h
new file mode 100644
index 0000000000..57cfb7ef3a
--- /dev/null
+++ b/src/plugins/perforce/perforceconstants.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCE_CONSTANTS_H
+#define PERFORCE_CONSTANTS_H
+
+namespace Perforce {
+ namespace Constants {
+ const char * const C_PERFORCEEDITOR = "Perforce Editor";
+
+ const char * const PERFORCEEDITOR_KIND = "Perforce Editor";
+ const char * const C_PERFORCESUBMITEDITOR = "Perforce Submit Editor";
+ const char * const PERFORCESUBMITEDITOR_KIND = "Perforce Submit Editor";
+ const char * const ICON_SUBMIT = ":/trolltech.perforce/images/submit.png";
+ const char * const ICON_DIFF = ":/trolltech.perforce/images/diff.png";
+ const char * const SUBMIT_CURRENT = "Nokia.Perforce.SubmitCurrentLog";
+ const char * const DIFF_SELECTED = "Nokia.Perforce.DiffSelectedFilesInLog";
+ const char * const SUBMIT_MIMETYPE = "application/vnd.nokia.text.p4.submit";
+
+ enum { debug = 0 };
+ }
+}
+
+#endif // PERFORCE_CONSTANTS_H
diff --git a/src/plugins/perforce/perforceeditor.cpp b/src/plugins/perforce/perforceeditor.cpp
new file mode 100644
index 0000000000..dd9da666f2
--- /dev/null
+++ b/src/plugins/perforce/perforceeditor.cpp
@@ -0,0 +1,159 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "perforceeditor.h"
+#include "annotationhighlighter.h"
+#include "perforceplugin.h"
+#include "perforceconstants.h"
+#include "perforceplugin.h"
+
+#include <vcsbase/diffhighlighter.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QSet>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLayout>
+#include <QtGui/QTextEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QTextCursor>
+#include <QtCore/QProcess>
+
+namespace Perforce {
+namespace Internal {
+
+// ------------ PerforceEditor
+PerforceEditor::PerforceEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent) :
+ VCSBase::VCSBaseEditor(type, parent),
+ m_changeNumberPattern(QLatin1String("^\\d+$")),
+ m_plugin(PerforcePlugin::perforcePluginInstance())
+{
+ Q_ASSERT(m_changeNumberPattern.isValid());
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforceEditor::PerforceEditor" << type->type << type->kind;
+}
+
+QSet<QString> PerforceEditor::annotationChanges() const
+{
+ QSet<QString> changes;
+ const QString txt = toPlainText();
+ if (txt.isEmpty())
+ return changes;
+ // Hunt for first change number in annotation: "<change>:"
+ QRegExp r(QLatin1String("^(\\d+):"));
+ Q_ASSERT(r.isValid());
+ if (r.indexIn(txt) != -1) {
+ changes.insert(r.cap(1));
+ r.setPattern(QLatin1String("\n(\\d+):"));
+ Q_ASSERT(r.isValid());
+ int pos = 0;
+ while ((pos = r.indexIn(txt, pos)) != -1) {
+ pos += r.matchedLength();
+ changes.insert(r.cap(1));
+ }
+ }
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforceEditor::annotationChanges() returns #" << changes.size();
+ return changes;
+}
+
+QString PerforceEditor::changeUnderCursor(const QTextCursor &c) const
+{
+ QTextCursor cursor = c;
+ // Any number is regarded as change number.
+ cursor.select(QTextCursor::WordUnderCursor);
+ if (!cursor.hasSelection())
+ return QString();
+ const QString change = cursor.selectedText();
+ return m_changeNumberPattern.exactMatch(change) ? change : QString();
+}
+
+VCSBase::DiffHighlighter *PerforceEditor::createDiffHighlighter() const
+{
+ const QRegExp filePattern(QLatin1String("^====.*"));
+ return new VCSBase::DiffHighlighter(filePattern);
+}
+
+VCSBase::BaseAnnotationHighlighter *PerforceEditor::createAnnotationHighlighter(const QSet<QString> &changes) const
+{
+ return new PerforceAnnotationHighlighter(changes);
+}
+
+QString PerforceEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
+{
+ QString errorMessage;
+ const QString diffIndicator = QLatin1String("==== ");
+ const QString diffEndIndicator = QLatin1String(" ====");
+ // Go back chunks. Note that for 'describe', an extra, empty line
+ // occurs.
+ for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) {
+ QString diffFileName = block.text();
+ if (diffFileName.startsWith(diffIndicator) && diffFileName.endsWith(diffEndIndicator)) {
+ // Split:
+ // 1) "==== //depot/.../mainwindow.cpp#2 - /depot/.../mainwindow.cpp ===="
+ // (as created by p4 diff) or
+ // 2) "==== //depot/.../mainwindow.cpp#15 (text) ===="
+ // (as created by p4 describe).
+ diffFileName.remove(0, diffIndicator.size());
+ diffFileName.truncate(diffFileName.size() - diffEndIndicator.size());
+ const int separatorPos = diffFileName.indexOf(QLatin1String(" - "));
+ if (separatorPos == -1) {
+ // ==== depot path (text) ==== (p4 describe)
+ const int blankPos = diffFileName.indexOf(QLatin1Char(' '));
+ if (blankPos == -1)
+ return QString();
+ diffFileName.truncate(blankPos);
+ } else {
+ // ==== depot path - local path ==== (p4 diff)
+ diffFileName.truncate(separatorPos);
+ }
+ // Split off revision "#4"
+ const int revisionPos = diffFileName.lastIndexOf(QLatin1Char('#'));
+ if (revisionPos != -1 && revisionPos < diffFileName.length() - 1)
+ diffFileName.truncate(revisionPos);
+ // Ask plugin to map back
+ const QString fileName = m_plugin->fileNameFromPerforceName(diffFileName.trimmed(), &errorMessage);
+ if (fileName.isEmpty())
+ qWarning(errorMessage.toUtf8().constData());
+ return fileName;
+ }
+ }
+ return QString();
+}
+
+} // namespace Internal
+} // namespace Perforce
diff --git a/src/plugins/perforce/perforceeditor.h b/src/plugins/perforce/perforceeditor.h
new file mode 100644
index 0000000000..2ca9b0304e
--- /dev/null
+++ b/src/plugins/perforce/perforceeditor.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCEEDITOR_H
+#define PERFORCEEDITOR_H
+
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/QRegExp>
+
+namespace Perforce {
+namespace Internal {
+
+class PerforcePlugin;
+
+class PerforceEditor : public VCSBase::VCSBaseEditor
+{
+ Q_OBJECT
+
+public:
+ explicit PerforceEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent);
+
+private:
+ virtual QSet<QString> annotationChanges() const;
+ virtual QString changeUnderCursor(const QTextCursor &) const;
+ virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
+ virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const;
+ virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const;
+
+ const QRegExp m_changeNumberPattern;
+ PerforcePlugin *m_plugin;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif // PERFORCEEDITOR_H
diff --git a/src/plugins/perforce/perforceoutputwindow.cpp b/src/plugins/perforce/perforceoutputwindow.cpp
new file mode 100644
index 0000000000..4d37d6a9af
--- /dev/null
+++ b/src/plugins/perforce/perforceoutputwindow.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+
+#include "perforceoutputwindow.h"
+#include "perforceplugin.h"
+
+using namespace Perforce::Internal;
+
+PerforceOutputWindow::PerforceOutputWindow(PerforcePlugin *p4Plugin)
+ : m_p4Plugin(p4Plugin)
+{
+ m_outputListWidget = new QListWidget;
+ m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_outputListWidget->setFrameStyle(QFrame::NoFrame);
+
+ m_outputListWidget->setWindowTitle(tr("Perforce Output"));
+
+ m_diffAction = new QAction(tr("Diff"), this);
+ connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diff()));
+
+ connect(m_outputListWidget, SIGNAL(itemActivated(QListWidgetItem*)),
+ this, SLOT(openFiles()));
+}
+
+PerforceOutputWindow::~PerforceOutputWindow()
+{
+ delete m_outputListWidget;
+}
+
+bool PerforceOutputWindow::hasFocus()
+{
+ return m_outputListWidget->hasFocus();
+}
+
+bool PerforceOutputWindow::canFocus()
+{
+ return false;
+}
+
+void PerforceOutputWindow::setFocus()
+{
+
+}
+
+QWidget *PerforceOutputWindow::outputWidget(QWidget *parent)
+{
+ m_outputListWidget->setParent(parent);
+ return m_outputListWidget;
+}
+
+QString PerforceOutputWindow::name() const
+{
+ return tr("Perforce");
+}
+
+void PerforceOutputWindow::clearContents()
+{
+ m_outputListWidget->clear();
+}
+
+void PerforceOutputWindow::visibilityChanged(bool /* b */)
+{
+
+}
+
+void PerforceOutputWindow::append(const QString &txt, bool doPopup)
+{
+ const QStringList lines = txt.split(QLatin1Char('\n'));
+ foreach (const QString &s, lines)
+ m_outputListWidget->addItem(s);
+ m_outputListWidget->scrollToBottom();
+ if (doPopup)
+ popup();
+}
+
+void PerforceOutputWindow::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *menu = new QMenu(m_outputListWidget);
+ menu->addAction(m_diffAction);
+ menu->exec(event->globalPos());
+ delete menu;
+}
+
+void PerforceOutputWindow::diff()
+{
+ QStringList files;
+ foreach (QListWidgetItem *i, m_outputListWidget->selectedItems()) {
+ if (m_outputListWidget->row(i) > 0)
+ files.append(getFileName(i));
+ }
+ if (files.count() == 0 && m_outputListWidget->row(m_outputListWidget->currentItem()) > 0)
+ files.append(getFileName(m_outputListWidget->currentItem()));
+
+ m_p4Plugin->p4Diff(files);
+}
+
+QString PerforceOutputWindow::getFileName(const QListWidgetItem *item)
+{
+ QString fileName;
+ if (!item || item->text().isEmpty())
+ return fileName;
+
+ QString line = item->text();
+ QRegExp regExp("(/.+)#\\d+\\s-\\s(.+)$");
+ regExp.setMinimal(true);
+ if (regExp.indexIn(line) > -1 && regExp.numCaptures() >= 1) {
+ fileName = regExp.cap(1);
+ QString description;
+ if (regExp.numCaptures() >= 2)
+ description = regExp.cap(2);
+ }
+ return fileName;
+}
+
+void PerforceOutputWindow::openFiles()
+{
+ QStringList files;
+ foreach (QListWidgetItem *i, m_outputListWidget->selectedItems()) {
+ if (m_outputListWidget->row(i) > 0)
+ files.append(getFileName(i));
+ }
+ if (files.count() == 0 && m_outputListWidget->row(m_outputListWidget->currentItem()) > 0)
+ files.append(getFileName(m_outputListWidget->currentItem()));
+
+ m_p4Plugin->openFiles(files);
+}
+
+int PerforceOutputWindow::priorityInStatusBar() const
+{
+ return -1;
+}
diff --git a/src/plugins/perforce/perforceoutputwindow.h b/src/plugins/perforce/perforceoutputwindow.h
new file mode 100644
index 0000000000..7391ca667d
--- /dev/null
+++ b/src/plugins/perforce/perforceoutputwindow.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCEOUTPUTWINDOW_H
+#define PERFORCEOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+#include <QtGui/QListWidgetItem>
+
+namespace Perforce {
+namespace Internal {
+
+class PerforcePlugin;
+
+class PerforceOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ PerforceOutputWindow(PerforcePlugin *p4Plugin);
+ ~PerforceOutputWindow();
+
+ QWidget *outputWidget(QWidget *parent);
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+
+ QString name() const;
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool visible);
+
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+public slots:
+ void append(const QString &txt, bool doPopup = false);
+
+private slots:;
+ void diff();
+ void openFiles();
+
+private:
+ void contextMenuEvent(QContextMenuEvent *event);
+
+ static QString getFileName(const QListWidgetItem *item);
+
+ PerforcePlugin *m_p4Plugin;
+ QListWidget *m_outputListWidget;
+ QAction *m_diffAction;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
new file mode 100644
index 0000000000..b3d2f43a26
--- /dev/null
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -0,0 +1,1270 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "p4.h"
+#include "perforceplugin.h"
+#include "perforceoutputwindow.h"
+#include "settingspage.h"
+#include "perforcesubmiteditor.h"
+#include "changenumberdialog.h"
+#include "perforceconstants.h"
+#include "perforceversioncontrol.h"
+#include "perforceeditor.h"
+#include "pendingchangesdialog.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <utils/synchronousprocess.h>
+#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/basevcssubmiteditorfactory.h>
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtCore/QTextCodec>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtGui/QFileDialog>
+
+using namespace Perforce::Internal;
+
+enum { p4Timeout = 20000 };
+
+static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
+{
+ VCSBase::RegularCommandOutput,
+ "Perforce Command Log Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "application/vnd.nokia.text.scs_commandlog",
+ "scslog"},
+{ VCSBase::LogOutput,
+ "Perforce File Log Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "application/vnd.nokia.text.scs_filelog",
+ "scsfilelog"},
+{ VCSBase::AnnotateOutput,
+ "Perforce Annotation Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "application/vnd.nokia.text.scs_annotation",
+ "scsannotate"},
+{ VCSBase::DiffOutput,
+ "Perforce Diff Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "text/x-patch","diff"}
+};
+
+// Utility to find a parameter set by type
+static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
+{
+ const VCSBase::EditorContentType et = static_cast<VCSBase::EditorContentType>(ie);
+ return VCSBase::VCSBaseEditor::findType(editorParameters, sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters), et);
+}
+
+static inline QString debugCodec(const QTextCodec *c)
+{
+ return c ? QString::fromAscii(c->name()) : QString::fromAscii("Null codec");
+}
+
+const char * const PerforcePlugin::PERFORCE_MENU = "Perforce.Menu";
+const char * const PerforcePlugin::EDIT = "Perforce.Edit";
+const char * const PerforcePlugin::ADD = "Perforce.Add";
+const char * const PerforcePlugin::DELETE_FILE = "Perforce.Delete";
+const char * const PerforcePlugin::OPENED = "Perforce.Opened";
+const char * const PerforcePlugin::REVERT = "Perforce.Revert";
+const char * const PerforcePlugin::DIFF_CURRENT = "Perforce.DiffCurrent";
+const char * const PerforcePlugin::DIFF_PROJECT = "Perforce.DiffProject";
+const char * const PerforcePlugin::DIFF_ALL = "Perforce.DiffAll";
+const char * const PerforcePlugin::RESOLVE = "Perforce.Resolve";
+const char * const PerforcePlugin::SUBMIT = "Perforce.Submit";
+const char * const PerforcePlugin::PENDING_CHANGES = "Perforce.PendingChanges";
+const char * const PerforcePlugin::DESCRIBE = "Perforce.Describe";
+const char * const PerforcePlugin::ANNOTATE_CURRENT = "Perforce.AnnotateCurrent";
+const char * const PerforcePlugin::ANNOTATE = "Perforce.Annotate";
+const char * const PerforcePlugin::FILELOG_CURRENT = "Perforce.FilelogCurrent";
+const char * const PerforcePlugin::FILELOG = "Perforce.Filelog";
+const char * const PerforcePlugin::SEPARATOR1 = "Perforce.Separator1";
+const char * const PerforcePlugin::SEPARATOR2 = "Perforce.Separator2";
+const char * const PerforcePlugin::SEPARATOR3 = "Perforce.Separator3";
+
+////
+// CoreListener
+////
+
+bool CoreListener::editorAboutToClose(Core::IEditor *editor)
+{
+ return m_plugin->editorAboutToClose(editor);
+}
+
+////
+// PerforcePlugin
+////
+
+Core::ICore *PerforcePlugin::m_coreInstance = NULL;
+PerforcePlugin *PerforcePlugin::m_perforcePluginInstance = NULL;
+
+PerforcePlugin::PerforcePlugin() :
+ m_perforceOutputWindow(0),
+ m_settingsPage(0),
+ m_editAction(0),
+ m_addAction(0),
+ m_deleteAction(0),
+ m_openedAction(0),
+ m_revertAction(0),
+ m_diffCurrentAction(0),
+ m_diffProjectAction(0),
+ m_diffAllAction(0),
+ m_resolveAction(0),
+ m_submitAction(0),
+ m_pendingAction(0),
+ m_describeAction(0),
+ m_annotateCurrentAction(0),
+ m_annotateAction(0),
+ m_filelogCurrentAction(0),
+ m_filelogAction(0),
+ m_changeTmpFile(0),
+#ifdef USE_P4_API
+ m_workbenchClientUser(0),
+#endif
+ m_coreListener(0),
+ m_submitEditorFactory(0),
+ m_versionControl(0)
+{
+}
+
+static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
+ Perforce::Constants::SUBMIT_MIMETYPE,
+ Perforce::Constants::PERFORCESUBMITEDITOR_KIND,
+ Perforce::Constants::C_PERFORCESUBMITEDITOR,
+ Core::Constants::UNDO,
+ Core::Constants::REDO,
+ Perforce::Constants::SUBMIT_CURRENT,
+ Perforce::Constants::DIFF_SELECTED
+};
+
+bool PerforcePlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ typedef VCSBase::VCSEditorFactory<PerforceEditor> PerforceEditorFactory;
+ typedef VCSBase::VCSSubmitEditorFactory<PerforceSubmitEditor> PerforceSubmitEditorFactory;
+
+ m_coreInstance = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!m_coreInstance->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.perforce/Perforce.mimetypes.xml"), errorMessage))
+ return false;
+ m_perforcePluginInstance = this;
+
+ if (QSettings *settings = m_coreInstance->settings())
+ m_settings.fromSettings(settings);
+
+ m_perforceOutputWindow = new PerforceOutputWindow(this);
+ addObject(m_perforceOutputWindow);
+
+ m_settingsPage = new SettingsPage;
+ addObject(m_settingsPage);
+
+ // Editor factories
+ m_submitEditorFactory = new PerforceSubmitEditorFactory(&submitParameters);
+ addObject(m_submitEditorFactory);
+
+ static const char *describeSlot = SLOT(describe(QString,QString));
+ const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
+ for (int i = 0; i < editorCount; i++) {
+ m_editorFactories.push_back(new PerforceEditorFactory(editorParameters + i, m_coreInstance, this, describeSlot));
+ addObject(m_editorFactories.back());
+ }
+
+ m_versionControl = new PerforceVersionControl(this);
+ addObject(m_versionControl);
+
+#ifdef USE_P4_API
+ m_workbenchClientUser = new WorkbenchClientUser(m_perforceOutputWindow, this);
+ m_enableP4APIActions = true;
+#endif
+
+ m_coreListener = new CoreListener(this);
+ addObject(m_coreListener);
+
+
+ //register actions
+ Core::ActionManagerInterface *am = m_coreInstance->actionManager();
+
+ Core::IActionContainer *mtools =
+ am->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *mperforce =
+ am->createMenu(QLatin1String(PERFORCE_MENU));
+ mperforce->menu()->setTitle(tr("&Perforce"));
+ mtools->addMenu(mperforce);
+
+ QList<int> globalcontext;
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+
+ QList<int> perforcesubmitcontext;
+ perforcesubmitcontext <<
+ m_coreInstance->uniqueIDManager()->uniqueIdentifier(Constants::C_PERFORCESUBMITEDITOR);
+
+ Core::ICommand *command;
+ QAction *tmpaction;
+
+ m_editAction = new QAction(tr("Edit"), this);
+ command = am->registerAction(m_editAction, PerforcePlugin::EDIT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+E")));
+ command->setDefaultText(tr("Edit File"));
+ connect(m_editAction, SIGNAL(triggered()), this, SLOT(openCurrentFile()));
+ mperforce->addAction(command);
+
+ m_addAction = new QAction(tr("Add"), this);
+ command = am->registerAction(m_addAction, PerforcePlugin::ADD, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+A")));
+ command->setDefaultText(tr("Add File"));
+ connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile()));
+ mperforce->addAction(command);
+
+ m_deleteAction = new QAction(tr("Delete"), this);
+ command = am->registerAction(m_deleteAction, PerforcePlugin::DELETE_FILE, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultText(tr("Delete File"));
+ connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deleteCurrentFile()));
+ mperforce->addAction(command);
+
+ m_revertAction = new QAction(tr("Revert"), this);
+ command = am->registerAction(m_revertAction, PerforcePlugin::REVERT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+R")));
+ command->setDefaultText(tr("Revert File"));
+ connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
+ mperforce->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Edit"), globalcontext);
+ mperforce->addAction(command);
+
+ m_diffCurrentAction = new QAction(tr("Diff Current File"), this);
+ command = am->registerAction(m_diffCurrentAction, PerforcePlugin::DIFF_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultText(tr("Diff Current File"));
+ connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
+ mperforce->addAction(command);
+
+ m_diffProjectAction = new QAction(tr("Diff Current Project/Session"), this);
+ command = am->registerAction(m_diffProjectAction, PerforcePlugin::DIFF_PROJECT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+D")));
+ command->setDefaultText(tr("Diff Current Project/Session"));
+ connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject()));
+ mperforce->addAction(command);
+
+ m_diffAllAction = new QAction(tr("Diff Opened Files"), this);
+ command = am->registerAction(m_diffAllAction, PerforcePlugin::DIFF_ALL, globalcontext);
+ connect(m_diffAllAction, SIGNAL(triggered()), this, SLOT(diffAllOpened()));
+ mperforce->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Diff"), globalcontext);
+ mperforce->addAction(command);
+
+ m_openedAction = new QAction(tr("Opened"), this);
+ command = am->registerAction(m_openedAction, PerforcePlugin::OPENED, globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+O")));
+ connect(m_openedAction, SIGNAL(triggered()), this, SLOT(printOpenedFileList()));
+ mperforce->addAction(command);
+
+#ifdef USE_P4_API
+ m_resolveAction = new QAction(tr("Resolve"), this);
+ command = am->registerAction(m_resolveAction, PerforcePlugin::RESOLVE, globalcontext);
+ connect(m_resolveAction, SIGNAL(triggered()), this, SLOT(resolve()));
+ mperforce->addAction(command);
+#endif
+
+ m_submitAction = new QAction(tr("Submit Project"), this);
+ command = am->registerAction(m_submitAction, PerforcePlugin::SUBMIT, globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+S")));
+ connect(m_submitAction, SIGNAL(triggered()), this, SLOT(submit()));
+ mperforce->addAction(command);
+
+ m_pendingAction = new QAction(tr("Pending Changes..."), this);
+ command = am->registerAction(m_pendingAction, PerforcePlugin::PENDING_CHANGES, globalcontext);
+ connect(m_pendingAction, SIGNAL(triggered()), this, SLOT(printPendingChanges()));
+ mperforce->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Changes"), globalcontext);
+ mperforce->addAction(command);
+
+ m_describeAction = new QAction(tr("Describe..."), this);
+ command = am->registerAction(m_describeAction, PerforcePlugin::DESCRIBE, globalcontext);
+ connect(m_describeAction, SIGNAL(triggered()), this, SLOT(describeChange()));
+ mperforce->addAction(command);
+
+ m_annotateCurrentAction = new QAction(tr("Annotate Current File"), this);
+ command = am->registerAction(m_annotateCurrentAction, PerforcePlugin::ANNOTATE_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultText(tr("Annotate Current File"));
+ connect(m_annotateCurrentAction, SIGNAL(triggered()), this, SLOT(annotateCurrentFile()));
+ mperforce->addAction(command);
+
+ m_annotateAction = new QAction(tr("Annotate..."), this);
+ command = am->registerAction(m_annotateAction, PerforcePlugin::ANNOTATE, globalcontext);
+ connect(m_annotateAction, SIGNAL(triggered()), this, SLOT(annotate()));
+ mperforce->addAction(command);
+
+ m_filelogCurrentAction = new QAction(tr("Filelog Current File"), this);
+ command = am->registerAction(m_filelogCurrentAction, PerforcePlugin::FILELOG_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+F")));
+ command->setDefaultText(tr("Filelog Current File"));
+ connect(m_filelogCurrentAction, SIGNAL(triggered()), this, SLOT(filelogCurrentFile()));
+ mperforce->addAction(command);
+
+ m_filelogAction = new QAction(tr("Filelog..."), this);
+ command = am->registerAction(m_filelogAction, PerforcePlugin::FILELOG, globalcontext);
+ connect(m_filelogAction, SIGNAL(triggered()), this, SLOT(filelog()));
+ mperforce->addAction(command);
+
+ m_submitCurrentLogAction = new QAction(QIcon(Constants::ICON_SUBMIT), tr("Submit"), this);
+ command = am->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, perforcesubmitcontext);
+ connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
+
+ m_diffSelectedFiles = new QAction(QIcon(Constants::ICON_DIFF), tr("Diff Selected Files"), this);
+ command = am->registerAction(m_diffSelectedFiles, Constants::DIFF_SELECTED, perforcesubmitcontext);
+
+ m_undoAction = new QAction(tr("&Undo"), this);
+ command = am->registerAction(m_undoAction, Core::Constants::UNDO, perforcesubmitcontext);
+
+ m_redoAction = new QAction(tr("&Redo"), this);
+ command = am->registerAction(m_redoAction, Core::Constants::REDO, perforcesubmitcontext);
+
+ connect(m_coreInstance, SIGNAL(contextChanged(Core::IContext *)),
+ this, SLOT(updateActions()));
+
+ connect(m_coreInstance->fileManager(), SIGNAL(currentFileChanged(const QString &)),
+ this, SLOT(updateActions()));
+
+ return true;
+}
+
+void PerforcePlugin::extensionsInitialized()
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+ if (m_projectExplorer) {
+ connect(m_projectExplorer,
+ SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
+ this, SLOT(updateActions()));
+ }
+ updateActions();
+}
+
+void PerforcePlugin::openCurrentFile()
+{
+ runP4Cmd(QStringList() << QLatin1String("edit") << currentFileName(), QStringList(), true);
+}
+
+void PerforcePlugin::addCurrentFile()
+{
+ runP4Cmd(QStringList() << QLatin1String("add") << currentFileName(), QStringList(), true);
+}
+
+void PerforcePlugin::deleteCurrentFile()
+{
+ runP4Cmd(QStringList() << QLatin1String("delete") << currentFileName(), QStringList(), true);
+}
+
+void PerforcePlugin::revertCurrentFile()
+{
+ Q_ASSERT(m_coreInstance);
+
+ const QString fileName = currentFileName();
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName);
+ QStringList args;
+ args << QLatin1String("diff") << QLatin1String("-sa");
+ PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec);
+ if (result.error)
+ return;
+
+ if (!result.stdOut.isEmpty()) {
+ bool doNotRevert = QMessageBox::warning(0, tr("p4 revert"),
+ tr("The file has been changed. Do you want to revert it?"),
+ QMessageBox::Yes, QMessageBox::No)
+ == QMessageBox::No;
+ if (doNotRevert)
+ return;
+ }
+
+ Core::FileManager *fm = m_coreInstance->fileManager();
+ QList<Core::IFile *> files = fm->managedFiles(fileName);
+ foreach (Core::IFile *file, files) {
+ fm->blockFileChange(file);
+ }
+ PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true);
+ Core::IFile::ReloadBehavior tempBehavior =
+ Core::IFile::ReloadAll;
+ foreach (Core::IFile *file, files) {
+ file->modified(&tempBehavior);
+ fm->unblockFileChange(file);
+ }
+}
+
+void PerforcePlugin::diffCurrentFile()
+{
+ p4Diff(QStringList(currentFileName()));
+}
+
+void PerforcePlugin::diffCurrentProject()
+{
+ Q_ASSERT(m_projectExplorer);
+ QStringList files;
+ QString name;
+ ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
+ if (currentProject) {
+ files << currentProject->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ name = currentProject->name();
+ } else if (m_projectExplorer->session()) {
+ name = m_projectExplorer->session()->file()->fileName();
+ QList<ProjectExplorer::Project *> projects = m_projectExplorer->session()->projects();
+ foreach (ProjectExplorer::Project *project, projects)
+ files << project->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ }
+ QStringList nativeFiles;
+ foreach (const QString &f, files)
+ nativeFiles << QDir::toNativeSeparators(f);
+ p4Diff(nativeFiles, name);
+}
+
+void PerforcePlugin::diffAllOpened()
+{
+ p4Diff(QStringList());
+}
+
+void PerforcePlugin::printOpenedFileList()
+{
+ Core::IEditor *e = m_coreInstance->editorManager()->currentEditor();
+ if (e)
+ e->widget()->setFocus();
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), true);
+}
+
+#ifdef USE_P4_API
+void PerforcePlugin::resolve()
+{
+ m_workbenchClientUser->setMode(WorkbenchClientUser::Resolve);
+ runP4APICmd(QLatin1String("resolve"));
+}
+#endif
+
+void PerforcePlugin::submit()
+{
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command()) {
+ showOutput(tr("No p4 executable specified!"));
+ return;
+ }
+
+ if (m_changeTmpFile) {
+ showOutput(tr("Another submit is currently executed."));
+ m_perforceOutputWindow->popup(false);
+ return;
+ }
+
+ m_changeTmpFile = new QTemporaryFile(this);
+ if (!m_changeTmpFile->open()) {
+ showOutput(tr("Cannot create temporary file."));
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(), false);
+ if (result.error) {
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ m_changeTmpFile->write(result.stdOut.toAscii());
+ m_changeTmpFile->seek(0);
+
+ // Assemble file list of project
+ Q_ASSERT(m_projectExplorer);
+ QStringList files;
+ QString name;
+ ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
+ if (currentProject) {
+ files << currentProject->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ name = currentProject->name();
+ } else if (m_projectExplorer->session()) {
+ name = m_projectExplorer->session()->file()->fileName();
+ QList<ProjectExplorer::Project *> projects = m_projectExplorer->session()->projects();
+ foreach (ProjectExplorer::Project *project, projects)
+ files << project->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ }
+ QStringList nativeFiles;
+ foreach (const QString &f, files)
+ nativeFiles << QDir::toNativeSeparators(f);
+
+ PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, false);
+ if (result2.error) {
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ QStringList stdOutLines = result2.stdOut.split(QLatin1Char('\n'));
+ QStringList depotFileNames;
+ foreach(const QString &line, stdOutLines) {
+ if (line.startsWith("... depotFile")) {
+ depotFileNames.append(line.mid(14));
+ }
+ }
+ if (depotFileNames.isEmpty()) {
+ showOutput(tr("Project has no files"));
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ openPerforceSubmitEditor(m_changeTmpFile->fileName(), depotFileNames);
+}
+
+Core::IEditor *PerforcePlugin::openPerforceSubmitEditor(const QString &fileName, const QStringList &depotFileNames)
+{
+ Core::IEditor *editor =
+ m_coreInstance->editorManager()->openEditor(fileName, Constants::PERFORCESUBMITEDITOR_KIND);
+ m_coreInstance->editorManager()->ensureEditorManagerVisible();
+ PerforceSubmitEditor *submitEditor = dynamic_cast<PerforceSubmitEditor*>(editor);
+ Q_ASSERT(submitEditor);
+ submitEditor->restrictToProjectFiles(depotFileNames);
+ connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(slotDiff(QStringList)));
+ // The actions are for some reason enabled by the context switching
+ // mechanism. Disable them correctly.
+ m_diffSelectedFiles->setEnabled(false);
+ m_undoAction->setEnabled(false);
+ m_redoAction->setEnabled(false);
+ return editor;
+}
+
+void PerforcePlugin::printPendingChanges()
+{
+ qApp->setOverrideCursor(Qt::WaitCursor);
+ PendingChangesDialog dia(pendingChangesData(), m_coreInstance->mainWindow());
+ qApp->restoreOverrideCursor();
+ if (dia.exec() == QDialog::Accepted) {
+ int i = dia.changeNumber();
+ PerforceResponse result = runP4Cmd(QStringList()<<"submit"<<"-c"<<QString::number(i), QStringList(), true);
+ }
+}
+
+void PerforcePlugin::describeChange()
+{
+ ChangeNumberDialog dia;
+ if (dia.exec() == QDialog::Accepted && dia.number() > 0)
+ describe(QString(), QString::number(dia.number()));
+}
+
+void PerforcePlugin::annotateCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ annotate(file);
+}
+
+void PerforcePlugin::annotate()
+{
+ const QString file = QFileDialog::getOpenFileName(0, tr("p4 annotate"), currentFileName());
+ if (!file.isEmpty())
+ annotate(file);
+}
+
+void PerforcePlugin::annotate(const QString &fileName)
+{
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName);
+ QStringList args;
+ args << QLatin1String("annotate") << QLatin1String("-cqi") << fileName;
+ const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec);
+ if (!result.error) {
+ const QFileInfo fi(fileName);
+ showOutputInEditor(tr("p4 annotate %1").arg(fi.fileName()), result.stdOut, VCSBase::AnnotateOutput, codec);
+ }
+}
+
+void PerforcePlugin::filelogCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ filelog(file);
+}
+
+void PerforcePlugin::filelog()
+{
+ const QString file = QFileDialog::getOpenFileName(0, tr("p4 filelog"), currentFileName());
+ if (!file.isEmpty())
+ filelog(file);
+}
+
+void PerforcePlugin::filelog(const QString &fileName)
+{
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName);
+ QStringList args;
+ args << QLatin1String("filelog") << QLatin1String("-li") << fileName;
+ const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec);
+ if (!result.error) {
+ const QFileInfo fi(fileName);
+ showOutputInEditor(tr("p4 filelog %1").arg(fi.fileName()), result.stdOut, VCSBase::LogOutput, codec);
+ }
+}
+
+void PerforcePlugin::updateActions()
+{
+ QString fileName = currentFileName();
+ QString baseName = QFileInfo(fileName).fileName();
+ const bool hasFile = !currentFileName().isEmpty();
+ m_editAction->setEnabled(hasFile);
+ m_addAction->setEnabled(hasFile);
+ m_deleteAction->setEnabled(hasFile);
+ m_revertAction->setEnabled(hasFile);
+ m_diffCurrentAction->setEnabled(hasFile);
+ m_annotateCurrentAction->setEnabled(hasFile);
+ m_filelogCurrentAction->setEnabled(hasFile);
+ if (hasFile) {
+ m_editAction->setText(tr("Edit %1").arg(baseName));
+ m_addAction->setText(tr("Add %1").arg(baseName));
+ m_deleteAction->setText(tr("Delete %1").arg(baseName));
+ m_revertAction->setText(tr("Revert %1").arg(baseName));
+ m_diffCurrentAction->setText(tr("Diff %1").arg(baseName));
+ m_annotateCurrentAction->setText(tr("Annotate %1").arg(baseName));
+ m_filelogCurrentAction->setText(tr("Filelog %1").arg(baseName));
+ } else {
+ m_editAction->setText(tr("Edit"));
+ m_addAction->setText(tr("Add"));
+ m_deleteAction->setText(tr("Delete"));
+ m_revertAction->setText(tr("Revert"));
+ m_diffCurrentAction->setText(tr("Diff"));
+ m_annotateCurrentAction->setText(tr("Annotate Current File"));
+ m_filelogCurrentAction->setText(tr("Filelog Current File"));
+ }
+ if (m_projectExplorer && m_projectExplorer->currentProject()) {
+ m_diffProjectAction->setEnabled(true);
+ m_diffProjectAction->setText(tr("Diff Project %1").arg(m_projectExplorer->currentProject()->name()));
+ m_submitAction->setEnabled(true);
+ } else {
+ m_diffProjectAction->setEnabled(false);
+ m_diffProjectAction->setText(tr("Diff Current Project/Soluion"));
+ m_submitAction->setEnabled(false);
+ }
+ m_diffAllAction->setEnabled(true);
+ m_openedAction->setEnabled(true);
+ m_describeAction->setEnabled(true);
+ m_annotateAction->setEnabled(true);
+ m_filelogAction->setEnabled(true);
+ m_pendingAction->setEnabled(true);
+
+
+#ifdef USE_P4_API
+ m_resolveAction->setEnabled(m_enableP4APIActions);
+#endif
+}
+
+bool PerforcePlugin::managesDirectory(const QString &directory) const
+{
+ const QString p4Path = directory + QLatin1String("/...");
+ QStringList args;
+ args << QLatin1String("fstat") << QLatin1String("-m1") << p4Path;
+
+ const PerforceResponse result = runP4Cmd(args, QStringList(), false, false);
+ return result.stdOut.contains("depotFile") || result.stdErr.contains("... - no such file(s)");
+}
+
+QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) const
+{
+ // First check with p4 client -o
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), false, false);
+ if (result.error)
+ return QString::null;
+
+ QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)"));
+ regExp.setMinimal(true);
+ if (regExp.indexIn(result.stdOut) != -1) {
+ QString file = regExp.cap(2).trimmed();
+ if (QFileInfo(file).exists())
+ return file;
+ }
+ return QString::null;
+}
+
+bool PerforcePlugin::vcsOpen(const QString &fileName)
+{
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(), true);
+ return !result.error;
+}
+
+bool PerforcePlugin::vcsAdd(const QString &fileName)
+{
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(), true);
+ return !result.error;
+}
+
+bool PerforcePlugin::vcsDelete(const QString &fileName)
+{
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true);
+ PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(), true);
+ // TODO need to carefully parse the actual messages from perforce
+ // or do a fstat before to decide what to do
+
+ // Different states are:
+ // File is in depot and unopened => p4 delete %
+ // File is in depot and opened => p4 revert %, p4 delete %
+ // File is not in depot => p4 revert %
+ return !(result.error && result2.error);
+}
+
+PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
+ const QStringList &extraArgs,
+ bool showStdOutInOutputWindow,
+ bool showStdErrInOutputWindow,
+ QTextCodec *outputCodec) const
+{
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforcePlugin::runP4Cmd" << args << extraArgs << debugCodec(outputCodec);
+ PerforceResponse response;
+ response.error = true;
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command()) {
+ response.message = tr("No p4 executable specified!");
+ m_perforceOutputWindow->append(response.message, true);
+ return response;
+ }
+
+ // handle extra args
+ QTemporaryFile tempfile;
+ tempfile.setAutoRemove(true);
+ const QChar newLine = QLatin1Char('\n');
+ const QChar blank = QLatin1Char(' ');
+ QStringList actualArgs = basicP4Args();
+ if (!extraArgs.isEmpty()) {
+ if (tempfile.open()) {
+ QTextStream stream(&tempfile);
+ stream << extraArgs.join(QString(newLine));
+ actualArgs << QLatin1String("-x") << tempfile.fileName();
+ tempfile.close();
+ } else {
+ qWarning()<<"Could not create temporary file. Appending all file names to command line.";
+ actualArgs << extraArgs;
+ }
+ }
+ actualArgs << args;
+
+ response.command = m_settings.p4Command;
+ response.command += blank;
+ response.command += actualArgs.join(QString(blank));
+ const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
+ const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, response.command);
+ showOutput(outputText, false);
+
+ // Run, connect stderr to the output window
+ Core::Utils::SynchronousProcess process;
+ process.setTimeout(p4Timeout);
+ process.setStdOutCodec(outputCodec);
+ process.setEnvironment(environment());
+
+ // connect stderr to the output window if desired
+ if (showStdErrInOutputWindow) {
+ process.setStdErrBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool)));
+ }
+
+ // connect stdout to the output window if desired
+ if (showStdOutInOutputWindow) {
+ process.setStdOutBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool)));
+ }
+
+ const Core::Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command, actualArgs);
+ if (Perforce::Constants::debug)
+ qDebug() << sp_resp;
+
+ response.error = true;
+ response.stdErr = sp_resp.stdErr;
+ response.stdOut = sp_resp.stdOut;
+ switch (sp_resp.result) {
+ case Core::Utils::SynchronousProcessResponse::Finished:
+ response.error = false;
+ break;
+ case Core::Utils::SynchronousProcessResponse::FinishedError:
+ response.message = tr("The process terminated with exit code %1.").arg(sp_resp.exitCode);
+ break;
+ case Core::Utils::SynchronousProcessResponse::TerminatedAbnormally:
+ response.message = tr("The process terminated abnormally.");
+ break;
+ case Core::Utils::SynchronousProcessResponse::StartFailed:
+ response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command);
+ break;
+ case Core::Utils::SynchronousProcessResponse::Hang:
+ response.message = tr("Subversion did not respond within timeout limit (%1 ms).").arg(p4Timeout );
+ break;
+ }
+ if (response.error)
+ m_perforceOutputWindow->append(response.message, true);
+
+
+ return response;
+}
+
+Core::IEditor * PerforcePlugin::showOutputInEditor(const QString& title, const QString output,
+ int editorType, QTextCodec *codec)
+{
+ const VCSBase::VCSBaseEditorParameters *params = findType(editorType);
+ Q_ASSERT(params);
+ const QString kind = QLatin1String(params->kind);
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforcePlugin::showOutputInEditor" << title << kind << "Size= " << output.size() << " Type=" << editorType << debugCodec(codec);
+ QString s = title;
+ Core::IEditor *ediface = m_coreInstance->editorManager()->
+ newFile(kind, &s, output.toLocal8Bit());
+ PerforceEditor *e = qobject_cast<PerforceEditor*>(ediface->widget());
+ if (!e)
+ return 0;
+ s.replace(QLatin1Char(' '), QLatin1Char('_'));
+ e->setSuggestedFileName(s);
+ if (codec)
+ e->setCodec(codec);
+ return e->editableInterface();
+}
+
+QStringList PerforcePlugin::environment() const
+{
+ QStringList newEnv = QProcess::systemEnvironment();
+ const QString name = "P4DIFF";
+ for (int i=0; i<newEnv.count(); ++i) {
+ if (newEnv.at(i).startsWith(name)) {
+ newEnv.removeAt(i);
+ return newEnv;
+ }
+ }
+ return newEnv;
+}
+
+void PerforcePlugin::slotDiff(const QStringList &files)
+{
+ p4Diff(files);
+}
+
+void PerforcePlugin::p4Diff(const QStringList &files, QString diffname)
+{
+ Core::IEditor *editor = 0;
+ bool displayInEditor = true;
+ Core::IEditor *existingEditor = 0;
+ QTextCodec *codec = files.empty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, files.front());
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << files << debugCodec(codec);
+
+ // diff of a single file? re-use an existing view if possible to support the common
+ // usage pattern of continuously changing and diffing a file
+ if (files.count() == 1) {
+ const QString fileName = files.at(0);
+ if (diffname.isEmpty()) {
+ const QFileInfo fi(fileName);
+ diffname = fi.fileName();
+ }
+
+ foreach (Core::IEditor *ed, m_coreInstance->editorManager()->openedEditors()) {
+ if (ed->property("originalFileName").toString() == fileName) {
+ existingEditor = ed;
+ displayInEditor = false;
+ break;
+ }
+ }
+ }
+
+ const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, false, codec);
+ if (result.error)
+ return;
+
+ if (displayInEditor)
+ editor = showOutputInEditor(tr("p4 diff %1").arg(diffname), result.stdOut, VCSBase::DiffOutput, codec);
+
+
+ if (files.count() == 1) {
+ if (displayInEditor && editor != 0) {
+ editor->setProperty("originalFileName", files.at(0));
+ } else if (!displayInEditor && existingEditor) {
+ if (existingEditor) {
+ existingEditor->createNew(result.stdOut);
+ m_coreInstance->editorManager()->setCurrentEditor(existingEditor);
+ }
+ }
+ }
+}
+
+void PerforcePlugin::describe(const QString & source, const QString &n)
+{
+ QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, source);
+ QStringList args;
+ args << QLatin1String("describe") << QLatin1String("-du") << n;
+ const PerforceResponse result = runP4Cmd(args, QStringList(), codec);
+ if (!result.error)
+ showOutputInEditor(tr("p4 describe %1").arg(n), result.stdOut, VCSBase::DiffOutput, codec);
+}
+
+void PerforcePlugin::submitCurrentLog()
+{
+ m_coreInstance->editorManager()->closeEditors(QList<Core::IEditor*>()
+ << m_coreInstance->editorManager()->currentEditor());
+}
+
+bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
+{
+ if (!m_changeTmpFile || !editor)
+ return true;
+ Core::IFile *fileIFace = editor->file();
+ if (!fileIFace)
+ return true;
+ QFileInfo editorFile(fileIFace->fileName());
+ QFileInfo changeFile(m_changeTmpFile->fileName());
+ if (editorFile.absoluteFilePath() == changeFile.absoluteFilePath()) {
+ const QMessageBox::StandardButton answer = QMessageBox::question(m_coreInstance->mainWindow(), tr("Closing p4 Editor"), tr("Do you want to submit this change list?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ if (answer == QMessageBox::Cancel) {
+ return false;
+ }
+
+ m_coreInstance->fileManager()->blockFileChange(fileIFace);
+ fileIFace->save();
+ m_coreInstance->fileManager()->unblockFileChange(fileIFace);
+ if (answer == QMessageBox::Yes) {
+ QByteArray change = m_changeTmpFile->readAll();
+ m_changeTmpFile->close();
+ if (!checkP4Command()) {
+ showOutput(tr("No p4 executable specified!"));
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return false;
+ }
+ QProcess proc;
+ proc.setEnvironment(environment());
+
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("submit") << QLatin1String("-i"));
+ if (!proc.waitForStarted(3000)) {
+ showOutput(tr("Cannot execute p4 submit."));
+ QApplication::restoreOverrideCursor();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return false;
+ }
+ proc.write(change);
+ proc.closeWriteChannel();
+
+ if (!proc.waitForFinished()) {
+ showOutput(tr("Cannot execute p4 submit."));
+ QApplication::restoreOverrideCursor();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return false;
+ }
+ QString output = QString::fromUtf8(proc.readAll());
+ showOutput(output);
+ if (output.contains("Out of date files must be resolved or reverted")) {
+ QMessageBox::warning(editor->widget(), "Pending change", "Could not submit the change, because your workspace was out of date. Created a pending submit instead.");
+ }
+ QApplication::restoreOverrideCursor();
+ }
+ m_changeTmpFile->close();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ }
+ return true;
+}
+
+void PerforcePlugin::openFiles(const QStringList &files)
+{
+ foreach (QString s, files) {
+ m_coreInstance->editorManager()->openEditor(clientFilePath(s));
+ }
+ m_coreInstance->editorManager()->ensureEditorManagerVisible();
+}
+
+QString PerforcePlugin::clientFilePath(const QString &serverFilePath)
+{
+ QString path;
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command())
+ return path;
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ QProcess proc;
+ proc.setEnvironment(environment());
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("fstat") << serverFilePath);
+
+ if (proc.waitForFinished(3000)) {
+ QString output = QString::fromUtf8(proc.readAllStandardOutput());
+ if (!output.isEmpty()) {
+ QRegExp r(QLatin1String("\\.\\.\\.\\sclientFile\\s(.+)\n"));
+ r.setMinimal(true);
+ if (r.indexIn(output) != -1)
+ path = r.cap(1).trimmed();
+ }
+ }
+ QApplication::restoreOverrideCursor();
+ return path;
+}
+
+QString PerforcePlugin::currentFileName()
+{
+ QString fileName = m_coreInstance->fileManager()->currentFile();
+
+ // TODO: Use FileManager::fixPath
+ const QFileInfo fileInfo(fileName);
+ if (fileInfo.exists())
+ fileName = fileInfo.absoluteFilePath();
+ fileName = QDir::toNativeSeparators(fileName);
+ return fileName;
+}
+
+QStringList PerforcePlugin::basicP4Args() const
+{
+ QStringList lst;
+ if (!m_settings.defaultEnv) {
+ lst << QLatin1String("-c") << m_settings.p4Client;
+ lst << QLatin1String("-p") << m_settings.p4Port;
+ lst << QLatin1String("-u") << m_settings.p4User;
+ }
+ return lst;
+}
+
+bool PerforcePlugin::checkP4Command() const
+{
+ if (m_settings.p4Command.isEmpty())
+ return false;
+ return true;
+}
+
+#ifdef USE_P4_API
+void PerforcePlugin::runP4APICmd(const QString &cmd, const QStringList &args)
+{
+ m_enableP4APIActions = false;
+ updateActions();
+
+ ClientApi client;
+ if (!m_settings.defaultEnv) {
+ client.SetClient(m_settings.p4Client.toLatin1().constData());
+ client.SetPort(m_settings.p4Port.toLatin1().constData());
+ client.SetUser(m_settings.p4User.toLatin1().constData());
+ }
+
+ Error err;
+ m_coreInstance->messageManager()->displayStatusBarMessage(tr("Connecting to p4 server..."));
+ client.SetProtocol("api", "56");
+ client.Init(&err);
+ if (err.Test()) {
+ StrBuf msg;
+ err.Fmt(&msg);
+ QMessageBox::critical(m_coreInstance->mainWindow(), tr("Perforce Plugin"), tr("Failed to connect to p4 server <b>%1</b>!").arg(msg.Text()));
+ client.Final(&err);
+ m_coreInstance->messageManager()->displayStatusBarMessage(tr("Connection to p4 server failed!"), 3000);
+ return;
+ }
+ m_coreInstance->messageManager()->displayStatusBarMessage(tr("Connection to p4 server established."), 3000);
+
+ // ????
+ //client.SetCwd("c:\\depot\\research\\qworkbench\\src");
+
+ int argc = args.count();
+ char **argv = (char**)malloc(argc*sizeof(char*));
+ int i = 0;
+ foreach (QString s, args)
+ argv[i++] = qstrdup(s.toLatin1().constData());
+
+ client.SetArgv( argc, argv );
+ try {
+ client.Run(cmd.toLatin1().constData(), m_workbenchClientUser);
+ } catch (...) {
+ QMessageBox::critical(m_coreInstance->mainWindow(), tr("Perforce Plugin"), tr("Failed to run command <b>%1</b>!").arg(cmd));
+ }
+ client.Final(&err);
+ i = 0;
+ while (i<argc)
+ free(argv[i++]);
+ free(argv);
+
+ m_enableP4APIActions = true;
+ updateActions();
+
+ Core::IEditor *edt = m_coreInstance->editorManager()->currentEditor();
+ if (edt && edt->widget())
+ edt->widget()->setFocus();
+}
+#endif
+
+QString PerforcePlugin::pendingChangesData()
+{
+ QString data;
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command())
+ return data;
+
+ QString user;
+ QProcess proc;
+ proc.setEnvironment(environment());
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("info"));
+ if (proc.waitForFinished(3000)) {
+ QString output = QString::fromUtf8(proc.readAllStandardOutput());
+ if (!output.isEmpty()) {
+ QRegExp r(QLatin1String("User\\sname:\\s(\\S+)\\s*\n"));
+ r.setMinimal(true);
+ if (r.indexIn(output) != -1)
+ user = r.cap(1).trimmed();
+ }
+ }
+ if (user.isEmpty())
+ return data;
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("changes") << QLatin1String("-s") << QLatin1String("pending") << QLatin1String("-u") << user);
+ if (proc.waitForFinished(3000))
+ data = QString::fromUtf8(proc.readAllStandardOutput());
+ return data;
+}
+
+void PerforcePlugin::showOutput(const QString &output, bool popup) const
+{
+ m_perforceOutputWindow->append(output, popup);
+}
+
+PerforcePlugin::~PerforcePlugin()
+{
+ if (m_settingsPage) {
+ removeObject(m_settingsPage);
+ delete m_settingsPage;
+ m_settingsPage = 0;
+ }
+
+#ifdef USE_P4_API
+ if (m_workbenchClientUser) {
+ delete m_workbenchClientUser;
+ m_workbenchClientUser = 0;
+ }
+#endif
+ if (m_perforceOutputWindow) {
+ removeObject(m_perforceOutputWindow);
+ delete m_perforceOutputWindow;
+ m_perforceOutputWindow = 0;
+ }
+ if (m_submitEditorFactory) {
+ removeObject(m_submitEditorFactory);
+ delete m_submitEditorFactory;
+ m_submitEditorFactory = 0;
+ }
+ if (m_versionControl) {
+ removeObject(m_versionControl);
+ delete m_versionControl;
+ m_versionControl = 0;
+ }
+
+ if (!m_editorFactories.empty()) {
+ foreach(Core::IEditorFactory* pf, m_editorFactories)
+ removeObject(pf);
+ qDeleteAll(m_editorFactories);
+ m_editorFactories.clear();
+ }
+
+ if (m_coreListener) {
+ removeObject(m_coreListener);
+ delete m_coreListener;
+ m_coreListener = 0;
+ }
+}
+
+PerforceSettings PerforcePlugin::settings() const
+{
+ return m_settings;
+}
+
+void PerforcePlugin::setSettings(const PerforceSettings &s)
+{
+ if (s != m_settings) {
+ m_settings = s;
+ if (QSettings *settings = m_coreInstance->settings())
+ m_settings.toSettings(settings);
+ }
+}
+
+// Map a perforce name "//xx" to its real name in the file system
+QString PerforcePlugin::fileNameFromPerforceName(const QString& perforceName,
+ QString *errorMessage) const
+{
+ // All happy, already mapped
+ if (!perforceName.startsWith(QLatin1String("//")))
+ return perforceName;
+ // "where" remaps the file to client file tree
+ QProcess proc;
+ QStringList args(basicP4Args());
+ args << QLatin1String("where") << perforceName;
+ proc.start(m_settings.p4Command, args);
+ if (!proc.waitForFinished()) {
+ *errorMessage = tr("Timeout waiting for \"where\" (%1).").arg(perforceName);
+ return QString();
+ }
+
+ QString output = QString::fromLocal8Bit(proc.readAllStandardOutput());
+ if (output.endsWith(QLatin1Char('\r')))
+ output.chop(1);
+ if (output.endsWith(QLatin1Char('\n')))
+ output.chop(1);
+
+ if (output.isEmpty()) {
+ *errorMessage = tr("Error running \"where\" on %1: The file is not mapped").arg(perforceName);
+ return QString();
+ }
+ const QString rc = output.mid(output.lastIndexOf(QLatin1Char(' ')) + 1);
+ if (Perforce::Constants::debug)
+ qDebug() << "fileNameFromPerforceName" << perforceName << rc;
+ return rc;
+}
+
+Q_EXPORT_PLUGIN(PerforcePlugin)
+
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
new file mode 100644
index 0000000000..d03d24515f
--- /dev/null
+++ b/src/plugins/perforce/perforceplugin.h
@@ -0,0 +1,250 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCEPLUGIN_H
+#define PERFORCEPLUGIN_H
+
+#include "perforcesettings.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/icorelistener.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <extensionsystem/iplugin.h>
+
+#ifdef USE_P4_API
+#include "workbenchclientuser.h"
+#else
+
+#endif
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QAction;
+class QTemporaryFile;
+class QTextCodec;
+QT_END_NAMESPACE
+
+namespace Core {
+ class IEditorFactory;
+}
+
+namespace Perforce {
+namespace Internal {
+class PerforceOutputWindow;
+class SettingsPage;
+class PerforceVersionControl;
+class PerforcePlugin;
+
+// Just a proxy for PerforcePlugin
+class CoreListener : public Core::ICoreListener
+{
+ Q_OBJECT
+public:
+ CoreListener(PerforcePlugin *plugin) : m_plugin(plugin) { }
+ bool editorAboutToClose(Core::IEditor *editor);
+ bool coreAboutToClose() { return true; }
+private:
+ PerforcePlugin *m_plugin;
+};
+
+struct PerforceResponse
+{
+ bool error;
+ QString command;
+ QString stdOut;
+ QString stdErr;
+ QString message;
+};
+
+class PerforcePlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ PerforcePlugin();
+ ~PerforcePlugin();
+
+ QStringList basicP4Args() const;
+ inline SettingsPage *settingsPage() const { return m_settingsPage; }
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+ bool managesDirectory(const QString &directory) const;
+ QString findTopLevelForDirectory(const QString &directory) const;
+ bool vcsOpen(const QString &fileName);
+ bool vcsAdd(const QString &fileName);
+ bool vcsDelete(const QString &filename);
+ // Displays the message for the submit mesage
+ bool editorAboutToClose(Core::IEditor *editor);
+
+ void p4Diff(const QStringList &files, QString diffname = QString());
+
+ Core::IEditor *openPerforceSubmitEditor(const QString &fileName, const QStringList &depotFileNames);
+
+ static Core::ICore *coreInstance() {Q_ASSERT(m_coreInstance); return m_coreInstance;}
+ static PerforcePlugin *perforcePluginInstance() {Q_ASSERT(m_perforcePluginInstance); return m_perforcePluginInstance;}
+
+ PerforceSettings settings() const;
+ void setSettings(const PerforceSettings &s);
+
+ // Map a perforce name "//xx" to its real name in the file system
+ QString fileNameFromPerforceName(const QString& perforceName, QString *errorMessage) const;
+
+public slots:
+ void describe(const QString &source, const QString &n);
+
+private slots:;
+ void openCurrentFile();
+ void addCurrentFile();
+ void deleteCurrentFile();
+ void revertCurrentFile();
+ void printOpenedFileList();
+ void diffCurrentFile();
+ void diffCurrentProject();
+ void diffAllOpened();
+ void submit();
+ void describeChange();
+ void annotateCurrentFile();
+ void annotate();
+ void filelogCurrentFile();
+ void filelog();
+
+ void updateActions();
+ void submitCurrentLog();
+ void printPendingChanges();
+ void slotDiff(const QStringList &files);
+
+#ifdef USE_P4_API
+ void resolve();
+#endif
+
+private:
+ QStringList environment() const;
+
+ Core::IEditor *showOutputInEditor(const QString& title, const QString output,
+ int editorType,
+ QTextCodec *codec = 0);
+ // args are passed as command line arguments
+ // extra args via a tempfile and the option -x "temp-filename"
+ PerforceResponse runP4Cmd(const QStringList &args,
+ const QStringList &extraArgs = QStringList(),
+ bool showStdOutInOutputWindow = false,
+ bool showStdErrInOutputWindow = true,
+ QTextCodec *outputCodec = 0) const;
+
+ void openFiles(const QStringList &files);
+
+ QString clientFilePath(const QString &serverFilePath);
+ QString currentFileName();
+ bool checkP4Command() const;
+ void showOutput(const QString &output, bool popup = false) const;
+ void annotate(const QString &fileName);
+ void filelog(const QString &fileName);
+
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ PerforceOutputWindow *m_perforceOutputWindow;
+ SettingsPage *m_settingsPage;
+ QList<Core::IEditorFactory*> m_editorFactories;
+
+ QAction *m_editAction;
+ QAction *m_addAction;
+ QAction *m_deleteAction;
+ QAction *m_openedAction;
+ QAction *m_revertAction;
+ QAction *m_diffCurrentAction;
+ QAction *m_diffProjectAction;
+ QAction *m_diffAllAction;
+ QAction *m_resolveAction;
+ QAction *m_submitAction;
+ QAction *m_pendingAction;
+ QAction *m_describeAction;
+ QAction *m_annotateCurrentAction;
+ QAction *m_annotateAction;
+ QAction *m_filelogCurrentAction;
+ QAction *m_filelogAction;
+ QAction *m_submitCurrentLogAction;
+ QAction *m_diffSelectedFiles;
+
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+
+ QTemporaryFile *m_changeTmpFile;
+
+ static const char * const PERFORCE_MENU;
+ static const char * const EDIT;
+ static const char * const ADD;
+ static const char * const DELETE_FILE;
+ static const char * const OPENED;
+ static const char * const REVERT;
+ static const char * const DIFF_ALL;
+ static const char * const DIFF_PROJECT;
+ static const char * const DIFF_CURRENT;
+ static const char * const RESOLVE;
+ static const char * const SUBMIT;
+ static const char * const PENDING_CHANGES;
+ static const char * const DESCRIBE;
+ static const char * const ANNOTATE_CURRENT;
+ static const char * const ANNOTATE;
+ static const char * const FILELOG_CURRENT;
+ static const char * const FILELOG;
+ static const char * const SEPARATOR1;
+ static const char * const SEPARATOR2;
+ static const char * const SEPARATOR3;
+
+ static Core::ICore *m_coreInstance;
+ static PerforcePlugin *m_perforcePluginInstance;
+ QString pendingChangesData();
+
+#ifdef USE_P4_API
+ void runP4APICmd(const QString &cmd, const QStringList &args = QStringList());
+ WorkbenchClientUser *m_workbenchClientUser;
+ bool m_enableP4APIActions;
+#endif
+
+ CoreListener *m_coreListener;
+ Core::IEditorFactory *m_submitEditorFactory;
+ PerforceVersionControl *m_versionControl;
+ PerforceSettings m_settings;
+
+ friend class PerforceOutputWindow;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif // PERFORCEPLUGIN_H
diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp
new file mode 100644
index 0000000000..d01df8a545
--- /dev/null
+++ b/src/plugins/perforce/perforcesettings.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "perforcesettings.h"
+
+#include <QtCore/QSettings>
+
+static const char *groupC = "Perforce";
+static const char *commandKeyC = "Command";
+static const char *defaultKeyC = "Default";
+static const char *portKeyC = "Port";
+static const char *clientKeyC = "Client";
+static const char *userKeyC = "User";
+
+static QString defaultCommand()
+{
+ QString rc;
+ rc = QLatin1String("p4");
+#if defined(Q_OS_WIN32)
+ rc.append(QLatin1String(".exe"));
+#endif
+ return rc;
+}
+
+namespace Perforce {
+namespace Internal {
+
+PerforceSettings::PerforceSettings() :
+ p4Command(defaultCommand()),
+ defaultEnv(true)
+{
+}
+
+void PerforceSettings::fromSettings(QSettings *settings)
+{
+ settings->beginGroup(QLatin1String(groupC));
+ p4Command = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString();
+ defaultEnv = settings->value(QLatin1String(defaultKeyC), true).toBool();
+ p4Port = settings->value(QLatin1String(portKeyC), QString()).toString();
+ p4Client = settings->value(QLatin1String(clientKeyC), QString()).toString();
+ p4User = settings->value(QLatin1String(userKeyC), QString()).toString();
+ settings->endGroup();
+
+}
+
+void PerforceSettings::toSettings(QSettings *settings) const
+{
+ settings->beginGroup(QLatin1String(groupC));
+ settings->setValue(commandKeyC, p4Command);
+ settings->setValue(defaultKeyC, defaultEnv);
+ settings->setValue(portKeyC, p4Port);
+ settings->setValue(clientKeyC, p4Client);
+ settings->setValue(userKeyC, p4User);
+ settings->endGroup();
+}
+
+bool PerforceSettings::equals(const PerforceSettings &s) const
+{
+ return p4Command == s.p4Command && p4Port == s.p4Port
+ && p4Client == s.p4Client && p4User == s.p4User
+ && defaultEnv == s.defaultEnv;
+}
+
+}
+}
+
diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h
new file mode 100644
index 0000000000..aa2782e47b
--- /dev/null
+++ b/src/plugins/perforce/perforcesettings.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFOCESETTINGS_H
+#define PERFOCESETTINGS_H
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Perforce {
+namespace Internal {
+
+struct PerforceSettings {
+ PerforceSettings();
+ void fromSettings(QSettings *);
+ void toSettings(QSettings *) const;
+ bool equals(const PerforceSettings &s) const;
+
+ QString p4Command;
+ QString p4Port;
+ QString p4Client;
+ QString p4User;
+ bool defaultEnv;
+};
+
+inline bool operator==(const PerforceSettings &p1, const PerforceSettings &p2)
+ { return p1.equals(p2); }
+inline bool operator!=(const PerforceSettings &p1, const PerforceSettings &p2)
+ { return !p1.equals(p2); }
+}
+}
+
+#endif
diff --git a/src/plugins/perforce/perforcesubmiteditor.cpp b/src/plugins/perforce/perforcesubmiteditor.cpp
new file mode 100644
index 0000000000..3e5188e5d8
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditor.cpp
@@ -0,0 +1,194 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "perforcesubmiteditor.h"
+#include "perforcesubmiteditorwidget.h"
+#include "perforceplugin.h"
+#include "perforceconstants.h"
+
+#include <QtCore/QDebug>
+
+namespace Perforce {
+namespace Internal {
+
+PerforceSubmitEditor::PerforceSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent) :
+ VCSBaseSubmitEditor(parameters, new PerforceSubmitEditorWidget(parent))
+{
+ setDisplayName(tr("Perforce Submit"));
+}
+
+PerforceSubmitEditorWidget *PerforceSubmitEditor::submitEditorWidget()
+{
+ return static_cast<PerforceSubmitEditorWidget *>(widget());
+}
+
+QStringList PerforceSubmitEditor::vcsFileListToFileList(const QStringList &rawList) const
+{
+ QStringList rc;
+ foreach (const QString &rf, rawList)
+ rc.push_back(fileFromChangeLine(rf));
+ return rc;
+}
+
+QString PerforceSubmitEditor::fileContents() const
+{
+ const_cast<PerforceSubmitEditor*>(this)->updateEntries();
+ QString text;
+ QTextStream out(&text);
+ QMapIterator<QString, QString> it(m_entries);
+ while (it.hasNext()) {
+ it.next();
+ out << it.key() << ":" << it.value();
+ }
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << text;
+ return text;
+}
+
+bool PerforceSubmitEditor::setFileContents(const QString &contents)
+{
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << contents;
+ if (!parseText(contents))
+ return false;
+ updateFields();
+ return true;
+}
+
+bool PerforceSubmitEditor::parseText(QString text)
+{
+ const QRegExp formField(QLatin1String("^\\S+:"));
+ const QString newLine = QString(QLatin1Char('\n'));
+
+ int match;
+ int matchLen;
+ QTextStream stream(&text, QIODevice::ReadOnly);
+ QString line;
+ QString key;
+ QString value;
+ line = stream.readLine();
+ while (!stream.atEnd()) {
+ match = formField.indexIn(line);
+ if (match == 0) {
+ matchLen = formField.matchedLength();
+ key = line.left(matchLen-1);
+ value = line.mid(matchLen) + newLine;
+ while (!stream.atEnd()) {
+ line = stream.readLine();
+ if (formField.indexIn(line) != -1)
+ break;
+ value += line + newLine;
+ }
+ m_entries.insert(key, value);
+ } else {
+ line = stream.readLine();
+ }
+ }
+ return true;
+}
+
+void PerforceSubmitEditor::restrictToProjectFiles(const QStringList &knownProjectFiles)
+{
+ QStringList allFiles = submitEditorWidget()->fileList();
+ const int oldSize = allFiles.size();
+ for (int i = oldSize - 1; i >= 0; i--)
+ if (!knownProjectFiles.contains(fileFromChangeLine(allFiles.at(i))))
+ allFiles.removeAt(i);
+ if (allFiles.size() != oldSize)
+ submitEditorWidget()->setFileList(allFiles);
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << oldSize << "->" << allFiles.size();
+}
+
+QString PerforceSubmitEditor::fileFromChangeLine(const QString &line)
+{
+ QString rc = line;
+ // " foo.cpp#add"
+ const int index = rc.lastIndexOf(QLatin1Char('#'));
+ if (index != -1)
+ rc.truncate(index);
+ return rc.trimmed();
+}
+
+void PerforceSubmitEditor::updateFields()
+{
+ PerforceSubmitEditorWidget *widget = submitEditorWidget();
+ widget->setData(m_entries.value(QLatin1String("Change")).trimmed(),
+ m_entries.value(QLatin1String("Client")).trimmed(),
+ m_entries.value(QLatin1String("User")).trimmed());
+
+ const QString newLine = QString(QLatin1Char('\n'));
+ QStringList lines = m_entries.value(QLatin1String("Description")).split(newLine);
+ lines.removeFirst(); // that is the line break after 'Description:'
+ lines.removeLast(); // that is the empty line at the end
+
+ const QRegExp leadingTabPattern = QRegExp(QLatin1String("^\\t"));
+ Q_ASSERT(leadingTabPattern.isValid());
+
+ lines.replaceInStrings(leadingTabPattern, QString());
+ widget->setDescriptionText(lines.join(newLine));
+
+ lines = m_entries.value(QLatin1String("Files")).split(newLine);
+ lines.replaceInStrings(leadingTabPattern, QString());
+ QStringList fileList;
+ foreach (const QString &line, lines)
+ if (!line.isEmpty())
+ fileList.push_back(line);
+ widget->setFileList(fileList);
+}
+
+void PerforceSubmitEditor::updateEntries()
+{
+ const QString newLine = QString(QLatin1Char('\n'));
+ const QString tab = QString(QLatin1Char('\t'));
+
+ QStringList lines = submitEditorWidget()->trimmedDescriptionText().split(newLine);
+ while (lines.last().isEmpty())
+ lines.removeLast();
+ // Description
+ lines.replaceInStrings(QRegExp(QLatin1String("^")), tab);
+ m_entries.insert(QLatin1String("Description"), newLine + lines.join(newLine) + QLatin1String("\n\n"));
+ QString files = newLine;
+ // Files
+ const QStringList fileList = submitEditorWidget()->fileList();
+ const int count = fileList.size();
+ for (int i = 0; i < count; i++) {
+ files += tab;
+ files += fileList.at(i);
+ files += newLine;
+ }
+ files += newLine;
+ m_entries.insert(QLatin1String("Files"), files);
+}
+
+}
+}
diff --git a/src/plugins/perforce/perforcesubmiteditor.h b/src/plugins/perforce/perforcesubmiteditor.h
new file mode 100644
index 0000000000..af0d3d0e2c
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditor.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCESUBMITEDITOR_H
+#define PERFORCESUBMITEDITOR_H
+
+#include <vcsbase/vcsbasesubmiteditor.h>
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+
+namespace Perforce {
+namespace Internal {
+
+class PerforceSubmitEditorWidget;
+class PerforcePlugin;
+
+/* PerforceSubmitEditor: In p4, the file list is contained in the
+ * submit message file (change list). On setting the file contents,
+ * it is split apart in message and file list and re-assembled
+ * when retrieving the file list.
+ * As a p4 submit starts with all opened files, there is API to restrict
+ * the file list to current project files in question
+ * (restrictToProjectFiles()). */
+class PerforceSubmitEditor : public VCSBase::VCSBaseSubmitEditor
+{
+ Q_OBJECT
+
+public:
+ explicit PerforceSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent);
+
+ /* The p4 submit starts with all opened files. Restrict
+ * it to the current project files in question. */
+ void restrictToProjectFiles(const QStringList &files);
+
+ static QString fileFromChangeLine(const QString &line);
+
+protected:
+ virtual QStringList vcsFileListToFileList(const QStringList &) const;
+ virtual QString fileContents() const;
+ virtual bool setFileContents(const QString &contents);
+
+private:
+ inline PerforceSubmitEditorWidget *submitEditorWidget();
+ bool parseText(QString text);
+ void updateFields();
+ void updateEntries();
+
+ QMap<QString, QString> m_entries;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // PERFORCESUBMITEDITOR_H
diff --git a/src/plugins/perforce/perforcesubmiteditorwidget.cpp b/src/plugins/perforce/perforcesubmiteditorwidget.cpp
new file mode 100644
index 0000000000..1a4c8251b1
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditorwidget.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "perforcesubmiteditorwidget.h"
+
+namespace Perforce {
+namespace Internal {
+
+PerforceSubmitEditorWidget::PerforceSubmitEditorWidget(QWidget *parent) :
+ Core::Utils::SubmitEditorWidget(parent),
+ m_submitPanel(new QGroupBox)
+{
+ m_submitPanelUi.setupUi(m_submitPanel);
+ insertTopWidget(m_submitPanel);
+}
+
+void PerforceSubmitEditorWidget::setData(const QString &change,
+ const QString &client,
+ const QString &userName)
+{
+ m_submitPanelUi.changeNumber->setText(change);
+ m_submitPanelUi.clientName->setText(client);
+ m_submitPanelUi.userName->setText(userName);
+}
+}
+}
diff --git a/src/plugins/perforce/perforcesubmiteditorwidget.h b/src/plugins/perforce/perforcesubmiteditorwidget.h
new file mode 100644
index 0000000000..fe79f65da2
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditorwidget.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCESUBMITEDITORWIDGET_H
+#define PERFORCESUBMITEDITORWIDGET_H
+
+#include "ui_submitpanel.h"
+#include <utils/submiteditorwidget.h>
+
+namespace Perforce {
+namespace Internal {
+
+/* Submit editor widget with additional information pane
+ * at the top. */
+class PerforceSubmitEditorWidget : public Core::Utils::SubmitEditorWidget
+{
+
+public:
+ explicit PerforceSubmitEditorWidget(QWidget *parent = 0);
+
+ void setData(const QString &change, const QString &client, const QString &userName);
+
+private:
+ QGroupBox *m_submitPanel;
+ Ui::SubmitPanel m_submitPanelUi;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // PERFORCESUBMITEDITORWIDGET_H
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
new file mode 100644
index 0000000000..5cbc8e4880
--- /dev/null
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "perforceversioncontrol.h"
+#include "perforceplugin.h"
+
+namespace Perforce {
+namespace Internal {
+
+PerforceVersionControl::PerforceVersionControl(PerforcePlugin *plugin) :
+ m_plugin(plugin)
+{
+}
+
+bool PerforceVersionControl::vcsOpen(const QString &fileName)
+{
+ return m_plugin->vcsOpen(fileName);
+}
+
+bool PerforceVersionControl::vcsAdd(const QString &fileName)
+{
+ return m_plugin->vcsAdd(fileName);
+}
+
+bool PerforceVersionControl::vcsDelete(const QString &fileName)
+{
+ return m_plugin->vcsDelete(fileName);
+}
+
+bool PerforceVersionControl::managesDirectory(const QString &directory) const
+{
+ return m_plugin->managesDirectory(directory);
+}
+
+QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const
+{
+ return m_plugin->findTopLevelForDirectory(directory);
+}
+}
+}
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
new file mode 100644
index 0000000000..5f10935749
--- /dev/null
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERFORCEVERSIONCONTROL_H
+#define PERFORCEVERSIONCONTROL_H
+
+#include <coreplugin/iversioncontrol.h>
+
+namespace Perforce {
+namespace Internal {
+class PerforcePlugin;
+
+// Just a proxy for PerforcePlugin
+class PerforceVersionControl : public Core::IVersionControl
+{
+ Q_OBJECT
+public:
+ explicit PerforceVersionControl(PerforcePlugin *plugin);
+ bool managesDirectory(const QString &directory) const;
+ virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool vcsOpen(const QString &fileName);
+ virtual bool vcsAdd(const QString &fileName);
+ virtual bool vcsDelete(const QString &filename);
+
+private:
+ PerforcePlugin *m_plugin;
+};
+
+}
+}
+#endif
diff --git a/src/plugins/perforce/promptdialog.ui b/src/plugins/perforce/promptdialog.ui
new file mode 100644
index 0000000000..aecf8d3337
--- /dev/null
+++ b/src/plugins/perforce/promptdialog.ui
@@ -0,0 +1,128 @@
+<ui version="4.0" >
+ <class>Perforce::Internal::PromptDialog</class>
+ <widget class="QDialog" name="Perforce::Internal::PromptDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>308</width>
+ <height>113</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Perforce Prompt</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="msgLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::AutoText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>okButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Perforce::Internal::PromptDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>278</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>96</x>
+ <y>254</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/settingspage.cpp b/src/plugins/perforce/settingspage.cpp
new file mode 100644
index 0000000000..7413e9526c
--- /dev/null
+++ b/src/plugins/perforce/settingspage.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+#include "perforcesettings.h"
+#include "perforceplugin.h"
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QFileDialog>
+
+using namespace Perforce::Internal;
+
+SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.browseButton, SIGNAL(clicked()), this, SLOT(browseForCommand()));
+}
+
+PerforceSettings SettingsPageWidget::settings() const
+{
+ PerforceSettings rc;
+ rc.p4Command = m_ui.p4CmdLineEdit->text();
+ rc.defaultEnv = m_ui.defaultCheckBox->isChecked();
+ rc.p4Port = m_ui.portLineEdit->text();
+ rc.p4Client = m_ui.clientLineEdit->text();
+ rc.p4User = m_ui.userLineEdit->text();
+ return rc;
+}
+
+void SettingsPageWidget::setSettings(const PerforceSettings &s)
+{
+ m_ui.p4CmdLineEdit->setText(s.p4Command);
+ m_ui.defaultCheckBox->setChecked(s.defaultEnv);
+ m_ui.portLineEdit->setText(s.p4Port);
+ m_ui.clientLineEdit->setText(s.p4Client);
+ m_ui.userLineEdit->setText(s.p4User);
+}
+
+void SettingsPageWidget::browseForCommand()
+{
+ const QString cmd = QFileDialog::getOpenFileName(window(), tr("Perforce Command"));
+ if (!cmd.isEmpty())
+ m_ui.p4CmdLineEdit->setText(cmd);
+}
+
+
+SettingsPage::SettingsPage()
+{
+}
+
+QString SettingsPage::name() const
+{
+ return tr("General");
+}
+
+QString SettingsPage::category() const
+{
+ return QLatin1String("Perforce");
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("Perforce");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ if (!m_widget)
+ m_widget = new SettingsPageWidget(parent);
+ m_widget->setSettings(PerforcePlugin::perforcePluginInstance()->settings());
+ return m_widget;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted || !m_widget)
+ return;
+
+ PerforcePlugin::perforcePluginInstance()->setSettings(m_widget->settings());
+}
diff --git a/src/plugins/perforce/settingspage.h b/src/plugins/perforce/settingspage.h
new file mode 100644
index 0000000000..bbbbce923c
--- /dev/null
+++ b/src/plugins/perforce/settingspage.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSPAGE_H
+#define SETTINGSPAGE_H
+
+#include <QtCore/QPointer>
+#include <QtGui/QWidget>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_settingspage.h"
+
+namespace Perforce {
+namespace Internal {
+
+struct PerforceSettings;
+
+class SettingsPageWidget : public QWidget {
+ Q_OBJECT
+public:
+ explicit SettingsPageWidget(QWidget *parent);
+
+ PerforceSettings settings() const;
+ void setSettings(const PerforceSettings &);
+
+private slots:;
+ void browseForCommand();
+
+private:
+ Ui::SettingsPage m_ui;
+};
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+private:
+ QPointer<SettingsPageWidget> m_widget;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // SETTINGSPAGE_H
diff --git a/src/plugins/perforce/settingspage.ui b/src/plugins/perforce/settingspage.ui
new file mode 100644
index 0000000000..1379b7b666
--- /dev/null
+++ b/src/plugins/perforce/settingspage.ui
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Perforce::Internal::SettingsPage</class>
+ <widget class="QWidget" name="Perforce::Internal::SettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>276</width>
+ <height>198</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>P4 Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="p4CmdLineEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="browseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="defaultCheckBox">
+ <property name="text">
+ <string>Use default P4 environment variables</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Environment variables</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="clientLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>P4 Client:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>P4 User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>P4 Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="userLineEdit"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="portLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>portLineEdit</tabstop>
+ <tabstop>clientLineEdit</tabstop>
+ <tabstop>userLineEdit</tabstop>
+ <tabstop>p4CmdLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>defaultCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>groupBox</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>134</x>
+ <y>51</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>139</x>
+ <y>65</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/submitpanel.ui b/src/plugins/perforce/submitpanel.ui
new file mode 100644
index 0000000000..5ce1f259f3
--- /dev/null
+++ b/src/plugins/perforce/submitpanel.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Perforce::Internal::SubmitPanel</class>
+ <widget class="QGroupBox" name="Perforce::Internal::SubmitPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>-2</y>
+ <width>402</width>
+ <height>134</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Submit</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="horizontalSpacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Change:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="changeNumber">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Client:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="clientName">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="userName">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/perforce/workbenchclientuser.cpp b/src/plugins/perforce/workbenchclientuser.cpp
new file mode 100644
index 0000000000..084a31e5a0
--- /dev/null
+++ b/src/plugins/perforce/workbenchclientuser.cpp
@@ -0,0 +1,285 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "workbenchclientuser.h"
+#include "perforceoutputwindow.h"
+#include "perforceplugin.h"
+
+#include <coreplugin/filemanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QTemporaryFile>
+#include <QtGui/QMessageBox>
+#include <QtGui/QRadioButton>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+
+using namespace Perforce::Internal;
+
+PromptDialog::PromptDialog(const QString &choice, const QString &text,
+ QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ m_ui.msgLabel->setText(text);
+
+ const QChar closingParenthesis = QLatin1Char(')');
+ const QStringList opts = choice.split(QString(closingParenthesis));
+ int row = 0;
+ int column = 0;
+ QString opt;
+ QRadioButton *rb = 0;
+ for (int i=0; i<opts.count(); ++i) {
+ opt = opts.at(i).trimmed();
+ if (opt.isEmpty() || opt.startsWith(QLatin1String("Help")))
+ continue;
+ if (i == opts.count()-1)
+ opt = QLatin1String("Default(") + opt.left(opt.length()-1);
+ opt.append(QLatin1String(")"));
+ rb = new QRadioButton(opt, this);
+ rb->setChecked(true);
+ if (column>0 && column%3==0)
+ ++row;
+ m_ui.gridLayout->addWidget(rb, row, column%3, 1, 1);
+ ++column;
+
+ const int j = opt.lastIndexOf(QLatin1Char('('));
+ opt = opt.mid(j+1, opt.lastIndexOf(closingParenthesis)-j-1);
+ m_optionsMap.insert(rb, opt);
+ }
+}
+
+QString PromptDialog::input() const
+{
+ QMapIterator<QRadioButton*, QString> it(m_optionsMap);
+ while (it.hasNext()) {
+ it.next();
+ if (it.key()->isChecked())
+ return it.value();
+ }
+ return QString();
+}
+
+WorkbenchClientUser::WorkbenchClientUser(PerforceOutputWindow *out, PerforcePlugin *plugin) :
+ QObject(out),
+ m_plugin(plugin),
+ m_coreIFace(PerforcePlugin::coreInstance()),
+ m_currentEditorIface(0),
+ m_userCancelled(false),
+ m_mode(Submit),
+ m_perforceOutputWindow(out),
+ m_skipNextMsg(false),
+ m_eventLoop(new QEventLoop(this))
+{
+ connect(m_coreIFace, SIGNAL(coreAboutToClose()),
+ this, SLOT(cancelP4Command()));
+}
+
+WorkbenchClientUser::~WorkbenchClientUser()
+{
+}
+
+void WorkbenchClientUser::setMode(WorkbenchClientUser::Mode mode)
+{
+ m_mode = mode;
+}
+
+void WorkbenchClientUser::cancelP4Command()
+{
+ m_userCancelled = true;
+ m_eventLoop->quit();
+}
+
+void WorkbenchClientUser::Message(Error* err)
+{
+ StrBuf buf;
+ err->Fmt(&buf);
+ QString s = buf.Text();
+ m_perforceOutputWindow->append(s);
+ if (!m_skipNextMsg) {
+ if (err->GetSeverity() == E_FAILED || err->GetSeverity() == E_FATAL) {
+ if (!s.startsWith("Client side operation(s) failed."))
+ m_errMsg.append(s);
+ } else {
+ m_msg.append(s);
+ }
+ }
+ m_skipNextMsg = false;
+}
+
+void WorkbenchClientUser::displayErrorMsg(const QString &msg)
+{
+ if (msg.isEmpty())
+ return;
+
+ const QString title = tr("Perforce Error");
+ switch (m_mode) {
+ case Submit: {
+ QMessageBox msgBox(QMessageBox::Critical, title, msg, QMessageBox::Ok, m_coreIFace->mainWindow());
+ msgBox.setDetailedText(m_msg);
+ msgBox.exec();
+ }
+ break;
+ default:
+ QMessageBox::critical(m_coreIFace->mainWindow(), title, msg);
+ break;
+ }
+ m_errMsg.clear();
+}
+
+void WorkbenchClientUser::OutputError(const char *errBuf)
+{
+ QString s(errBuf);
+ s = s.trimmed();
+ m_perforceOutputWindow->append(s);
+ displayErrorMsg(s);
+}
+
+void WorkbenchClientUser::Finished()
+{
+ m_errMsg = m_errMsg.trimmed();
+ displayErrorMsg(m_errMsg);
+ m_msg.clear();
+ m_currentEditorIface = 0;
+ m_userCancelled = false;
+ m_skipNextMsg = false;
+}
+
+bool WorkbenchClientUser::editorAboutToClose(Core::IEditor *editor)
+{
+ if (editor && editor == m_currentEditorIface) {
+ if (m_mode == WorkbenchClientUser::Submit) {
+ const QMessageBox::StandardButton answer =
+ QMessageBox::question(m_coreIFace->mainWindow(),
+ tr("Closing p4 Editor"),
+ tr("Do you want to submit this change list?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ if (answer == QMessageBox::Cancel)
+ return false;
+ if (answer == QMessageBox::No)
+ m_userCancelled = true;
+ m_coreIFace->fileManager()->blockFileChange(m_currentEditorIface->file());
+ m_currentEditorIface->file()->save();
+ m_coreIFace->fileManager()->unblockFileChange(m_currentEditorIface->file());
+ }
+ m_eventLoop->quit();
+ m_currentEditorIface = 0;
+ }
+ return true;
+}
+
+void WorkbenchClientUser::Diff(FileSys *f1, FileSys *f2, int, char *, Error *err)
+{
+ if (!f1->IsTextual() || !f2->IsTextual())
+ return;
+
+ FileSys *file1 = File(FST_BINARY);
+ file1->Set(f1->Name());
+
+ FileSys *file2 = File(FST_BINARY);
+ file2->Set(f2->Name());
+
+ QTemporaryFile tmp;
+ tmp.open();
+ QString fileName = tmp.fileName();
+
+ {
+ ::Diff d;
+ d.SetInput(file1, file2, DiffFlags(), err);
+ if (!err->Test())
+ d.SetOutput(fileName.toLatin1().constData(), err);
+ if (!err->Test())
+ d.DiffUnified();
+ d.CloseOutput(err);
+ }
+ delete file1;
+ delete file2;
+
+ QString title = QString("diff %1").arg(f1->Name());
+ m_currentEditorIface = m_coreIFace->editorManager()->newFile("Perforce Editor", &title, tmp.readAll());
+ if (!m_currentEditorIface) {
+ err->Set(E_FAILED, "p4 data could not be opened!");
+ return;
+ }
+ m_userCancelled = false;
+ m_eventLoop->exec();
+ if (m_userCancelled)
+ err->Set(E_FAILED, "");
+}
+
+void WorkbenchClientUser::Edit(FileSys *f, Error *err)
+{
+ QString fileName(f->Name());
+ if (m_mode == Submit) {
+ m_currentEditorIface = m_plugin->openPerforceSubmitEditor(fileName, QStringList());
+ }
+ else {
+ m_currentEditorIface = m_coreIFace->editorManager()->openEditor(fileName);
+ m_coreIFace->editorManager()->ensureEditorManagerVisible();
+ }
+ if (!m_currentEditorIface) {
+ err->Set(E_FAILED, "p4 data could not be opened!");
+ return;
+ }
+ m_userCancelled = false;
+ m_eventLoop->exec();
+ if (m_userCancelled)
+ err->Set(E_FAILED, "");
+}
+
+void WorkbenchClientUser::Prompt(const StrPtr &msg, StrBuf &answer, int , Error *err)
+{
+ if (m_userCancelled) {
+ err->Set(E_FATAL, "");
+ return;
+ }
+ PromptDialog dia(msg.Text(), m_msg, qobject_cast<QWidget*>(m_coreIFace));
+ dia.exec();
+ answer = qstrdup(dia.input().toLatin1().constData());
+ if (m_mode == WorkbenchClientUser::Resolve) {
+ if (strcmp(answer.Text(), "e") == 0) {
+ ;
+ } else if (strcmp(answer.Text(), "d") == 0) {
+ ;
+ } else {
+ m_msg.clear();
+ m_skipNextMsg = true;
+ }
+ }
+}
+
+void WorkbenchClientUser::ErrorPause(char *msg, Error *)
+{
+ QMessageBox::warning(m_coreIFace->mainWindow(), tr("Perforce Error"), QString::fromUtf8(msg));
+}
diff --git a/src/plugins/perforce/workbenchclientuser.h b/src/plugins/perforce/workbenchclientuser.h
new file mode 100644
index 0000000000..9ee25e1857
--- /dev/null
+++ b/src/plugins/perforce/workbenchclientuser.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WORKBENCHCLIENTUSER_H
+#define WORKBENCHCLIENTUSER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <coreplugin/icorelistener.h>
+#include "p4.h"
+
+#include "ui_promptdialog.h"
+
+QT_BEGIN_NAMESPACE
+class QRadioButton;
+class QEventLoop;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace Perforce {
+namespace Internal {
+
+class PerforceOutputWindow;
+class PerforcePlugin;
+
+class PromptDialog : public QDialog
+{
+public:
+ PromptDialog(const QString &choice, const QString &text,
+ QWidget *parent = 0);
+ QString input() const;
+
+private:
+ Ui::PromptDialog m_ui;
+ QMap<QRadioButton*, QString> m_optionsMap;
+};
+
+class WorkbenchClientUser : public QObject, public ClientUser
+{
+ Q_OBJECT
+
+public:
+ enum Mode {Submit, Resolve};
+ WorkbenchClientUser(PerforceOutputWindow *out, PerforcePlugin *plugin);
+ ~WorkbenchClientUser();
+ void setMode(WorkbenchClientUser::Mode mode);
+
+ void Message(Error* err);
+ void OutputError(const char *errBuf);
+ void Finished();
+ void Diff(FileSys *f1, FileSys *f2, int, char *, Error *err);
+ void Edit( FileSys *f, Error *err);
+ void Prompt(const StrPtr &msg, StrBuf &answer, int , Error *err);
+ void ErrorPause(char *msg, Error *);
+ bool editorAboutToClose(Core::IEditor *editor);
+
+private slots:
+ void cancelP4Command();
+
+private:
+ void displayErrorMsg(const QString &msg);
+
+ PerforcePlugin *m_plugin;
+ Core::ICore *m_coreIFace;
+ Core::IEditor *m_currentEditorIface;
+ bool m_userCancelled;
+ Mode m_mode;
+ PerforceOutputWindow *m_perforceOutputWindow;
+ QString m_msg;
+ QString m_errMsg;
+ bool m_skipNextMsg;
+ QEventLoop *m_eventLoop;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
new file mode 100644
index 0000000000..4af2af4195
--- /dev/null
+++ b/src/plugins/plugins.pro
@@ -0,0 +1,150 @@
+# USE .subdir AND .depends !
+# OTHERWISE PLUGINS WILL BUILD IN WRONG ORDER (DIRECTORIES ARE COMPILED IN PARALLEL)
+
+TEMPLATE = subdirs
+
+SUBDIRS = plugin_coreplugin \
+ plugin_find \
+ plugin_texteditor \
+ plugin_cppeditor \
+ plugin_bineditor \
+ plugin_bookmarks \
+ plugin_projectexplorer \
+ plugin_vcsbase \
+ plugin_perforce \
+ plugin_subversion \
+ plugin_git \
+ plugin_cpptools \
+ plugin_qt4projectmanager \
+# plugin_snippets \ # buggy and annoying
+ plugin_quickopen \
+ plugin_debugger \
+# plugin_qtestlib \ # this seems to be dead
+# plugin_helloworld \ # sample plugin
+ plugin_help \
+# plugin_regexp \ # don't know what to do with this
+ plugin_qtscripteditor \
+ plugin_cpaster \
+ plugin_cmakeprojectmanager
+
+# These two plugins require private headers from Qt and therefore don't work
+# with an installed/released version of Qt.
+exists($$(QTDIR)/.qmake.cache) {
+ SUBDIRS += plugin_designer plugin_resourceeditor
+} else {
+ message(Designer and Resource Editor plugins are not build! They require private headers and do not compile with your released/installed version of Qt)
+}
+
+plugin_coreplugin.subdir = coreplugin
+
+plugin_find.subdir = find
+plugin_find.depends += plugin_coreplugin
+
+plugin_texteditor.subdir = texteditor
+plugin_texteditor.depends = plugin_find
+plugin_texteditor.depends += plugin_quickopen
+plugin_texteditor.depends += plugin_coreplugin
+
+plugin_cppeditor.subdir = cppeditor
+plugin_cppeditor.depends = plugin_texteditor
+plugin_cppeditor.depends += plugin_coreplugin
+plugin_cppeditor.depends += plugin_cpptools
+
+plugin_bineditor.subdir = bineditor
+plugin_bineditor.depends = plugin_texteditor
+plugin_bineditor.depends += plugin_coreplugin
+
+plugin_designer.subdir = designer
+plugin_designer.depends = plugin_coreplugin plugin_cppeditor plugin_projectexplorer
+
+plugin_vcsbase.subdir = vcsbase
+plugin_vcsbase.depends = plugin_find
+plugin_vcsbase.depends += plugin_texteditor
+plugin_vcsbase.depends += plugin_coreplugin
+plugin_vcsbase.depends += plugin_projectexplorer
+
+plugin_perforce.subdir = perforce
+plugin_perforce.depends = plugin_vcsbase
+plugin_perforce.depends += plugin_projectexplorer
+plugin_perforce.depends += plugin_coreplugin
+
+plugin_git.subdir = git
+plugin_git.depends = plugin_texteditor
+plugin_git.depends = plugin_vcsbase
+plugin_git.depends += plugin_projectexplorer
+plugin_git.depends += plugin_coreplugin
+
+plugin_subversion.subdir = subversion
+plugin_subversion.depends = plugin_vcsbase
+plugin_subversion.depends += plugin_projectexplorer
+plugin_subversion.depends += plugin_coreplugin
+
+plugin_projectexplorer.subdir = projectexplorer
+plugin_projectexplorer.depends = plugin_quickopen
+plugin_projectexplorer.depends += plugin_find
+plugin_projectexplorer.depends += plugin_coreplugin
+plugin_projectexplorer.depends += plugin_texteditor
+
+plugin_qt4projectmanager.subdir = qt4projectmanager
+plugin_qt4projectmanager.depends = plugin_texteditor
+plugin_qt4projectmanager.depends += plugin_projectexplorer
+plugin_qt4projectmanager.depends += plugin_cpptools
+plugin_qt4projectmanager.depends += plugin_cppeditor
+plugin_qt4projectmanager.depends += plugin_help
+
+plugin_quickopen.subdir = quickopen
+plugin_quickopen.depends = plugin_coreplugin
+
+plugin_cpptools.subdir = cpptools
+plugin_cpptools.depends = plugin_projectexplorer
+plugin_cpptools.depends += plugin_coreplugin
+plugin_cpptools.depends += plugin_texteditor
+
+plugin_bookmarks.subdir = bookmarks
+plugin_bookmarks.depends = plugin_projectexplorer
+plugin_bookmarks.depends += plugin_coreplugin
+plugin_bookmarks.depends += plugin_texteditor
+
+plugin_snippets.subdir = snippets
+plugin_snippets.depends = plugin_projectexplorer
+plugin_snippets.depends += plugin_coreplugin
+plugin_snippets.depends += plugin_texteditor
+
+plugin_debugger.subdir = debugger
+plugin_debugger.depends = plugin_projectexplorer
+plugin_debugger.depends += plugin_coreplugin
+plugin_debugger.depends += plugin_cppeditor
+
+plugin_qtestlib.subdir = qtestlib
+plugin_qtestlib.depends = plugin_projectexplorer
+plugin_qtestlib.depends += plugin_coreplugin
+
+plugin_helloworld.subdir = helloworld
+plugin_helloworld.depends += plugin_coreplugin
+
+plugin_help.subdir = help
+plugin_help.depends = plugin_find
+plugin_help.depends += plugin_quickopen
+plugin_help.depends += plugin_coreplugin
+
+plugin_resourceeditor.subdir = resourceeditor
+plugin_resourceeditor.depends = plugin_coreplugin
+
+plugin_regexp.subdir = regexp
+plugin_regexp.depends = plugin_coreplugin
+
+plugin_qtscripteditor.subdir = qtscripteditor
+plugin_qtscripteditor.depends = plugin_texteditor
+plugin_qtscripteditor.depends += plugin_coreplugin
+
+plugin_cpaster.subdir = cpaster
+plugin_cpaster.depends += plugin_texteditor
+plugin_cpaster.depends += plugin_coreplugin
+plugin_cpaster.depends += plugin_projectexplorer
+
+plugin_cmakeprojectmanager.subdir = cmakeprojectmanager
+plugin_cmakeprojectmanager.depends = plugin_texteditor
+plugin_cmakeprojectmanager.depends += plugin_projectexplorer
+plugin_cmakeprojectmanager.depends += plugin_cpptools
+plugin_cmakeprojectmanager.depends += plugin_cppeditor
+plugin_cmakeprojectmanager.depends += plugin_help
diff --git a/src/plugins/projectexplorer/ProjectExplorer.pluginspec b/src/plugins/projectexplorer/ProjectExplorer.pluginspec
new file mode 100644
index 0000000000..1673c3f399
--- /dev/null
+++ b/src/plugins/projectexplorer/ProjectExplorer.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="ProjectExplorer" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>ProjectExplorer framework that can be extended with different kind of project types.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="Find" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ <dependency name="TextEditor" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/projectexplorer/ProjectExplorerInterfaces b/src/plugins/projectexplorer/ProjectExplorerInterfaces
new file mode 100644
index 0000000000..6f1c8840fe
--- /dev/null
+++ b/src/plugins/projectexplorer/ProjectExplorerInterfaces
@@ -0,0 +1,11 @@
+#include "projectexplorer/buildparserinterface.h"
+#include "projectexplorer/projectexplorerconstants.h"
+#include "projectexplorer/project.h"
+#include "projectexplorer/buildstep.h"
+#include "projectexplorer/buildconfiguration.h"
+#include "projectexplorer/buildmanager.h"
+#include "projectexplorer/projectexplorer.h"
+#include "projectexplorer/persistentsettings.h"
+#include "projectexplorer/environment.h"
+#include "projectexplorer/environmenteditmodel.h"
+#include "projectexplorer/abstractprocessstep.h"
diff --git a/src/plugins/projectexplorer/abstractprocess.h b/src/plugins/projectexplorer/abstractprocess.h
new file mode 100644
index 0000000000..10d0e984b7
--- /dev/null
+++ b/src/plugins/projectexplorer/abstractprocess.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ABSTRACTPROCESS_H
+#define ABSTRACTPROCESS_H
+
+#include <QtCore/QStringList>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class AbstractProcess
+{
+public:
+ AbstractProcess() {}
+ virtual ~AbstractProcess() {}
+
+ QString workingDirectory() const { return m_workingDir; }
+ void setWorkingDirectory(const QString &dir) { m_workingDir = dir; }
+
+ QStringList environment() const { return m_environment; }
+ void setEnvironment(const QStringList &env) { m_environment = env; }
+
+ virtual bool start(const QString &program, const QStringList &args) = 0;
+ virtual void stop() = 0;
+
+ virtual bool isRunning() const = 0;
+ virtual qint64 applicationPID() const = 0;
+ virtual int exitCode() const = 0;
+
+//signals:
+ virtual void processError(const QString &error) = 0;
+
+private:
+ QString m_workingDir;
+ QStringList m_environment;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif
+
diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp
new file mode 100644
index 0000000000..2c089b3e5b
--- /dev/null
+++ b/src/plugins/projectexplorer/abstractprocessstep.cpp
@@ -0,0 +1,237 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "abstractprocessstep.h"
+#include "buildstep.h"
+#include "project.h"
+#include <QtCore/QProcess>
+#include <QtCore/QEventLoop>
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+
+using namespace ProjectExplorer;
+
+AbstractProcessStep::AbstractProcessStep(Project *pro)
+ : BuildStep(pro)
+{
+}
+
+void AbstractProcessStep::setCommand(const QString &buildConfiguration, const QString &cmd)
+{
+ setValue(buildConfiguration, "abstractProcess.command", cmd);
+}
+
+QString AbstractProcessStep::command(const QString &buildConfiguration) const
+{
+ return value(buildConfiguration, "abstractProcess.command").toString();
+}
+
+void AbstractProcessStep::setWorkingDirectory(const QString &buildConfiguration, const QString &workingDirectory)
+{
+ setValue(buildConfiguration, "abstractProcess.workingDirectory", workingDirectory);
+}
+
+QString AbstractProcessStep::workingDirectory(const QString &buildConfiguration) const
+{
+ return value(buildConfiguration, "abstractProcess.workingDirectory").toString();
+}
+
+void AbstractProcessStep::setArguments(const QString &buildConfiguration, const QStringList &arguments)
+{
+ setValue(buildConfiguration, "abstractProcess.arguments", arguments);
+}
+
+QStringList AbstractProcessStep::arguments(const QString &buildConfiguration) const
+{
+ return value(buildConfiguration, "abstractProcess.arguments").toStringList();
+}
+
+void AbstractProcessStep::setEnabled(const QString &buildConfiguration, bool b)
+{
+ setValue(buildConfiguration, "abstractProcess.enabled", b);
+}
+
+bool AbstractProcessStep::enabled(const QString &buildConfiguration) const
+{
+ return value(buildConfiguration, "abstractProcess.enabled").toBool();
+}
+
+void AbstractProcessStep::setEnvironment(const QString &buildConfiguration, Environment env)
+{
+ setValue(buildConfiguration, "abstractProcess.Environment", env.toStringList());
+}
+
+Environment AbstractProcessStep::environment(const QString &buildConfiguration) const
+{
+ return Environment(value(buildConfiguration, "abstractProcess.Environment").toStringList());
+}
+
+bool AbstractProcessStep::init(const QString &name)
+{
+ m_command = value(name, "abstractProcess.command").toString();
+ m_arguments = value(name, "abstractProcess.arguments").toStringList();
+ QVariant var = value(name, "abstractProcess.enabled");
+ m_enabled = var.isValid() && var.toBool();
+ m_workingDirectory = value(name, "abstractProcess.workingDirectory").toString();
+ m_environment = Environment(value(name, "abstractProcess.Environment").toStringList());
+ return true;
+}
+
+void AbstractProcessStep::run(QFutureInterface<bool> & fi)
+{
+ m_futureInterface = &fi;
+ if(!m_enabled) {
+ fi.reportResult(true);
+ return;
+ }
+ QDir wd(m_workingDirectory);
+ if (!wd.exists())
+ wd.mkpath(wd.absolutePath());
+
+ m_process = new QProcess();
+ m_process->setWorkingDirectory(m_workingDirectory);
+ m_process->setEnvironment(m_environment.toStringList());
+
+ connect(m_process, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(processReadyReadStdOutput()),
+ Qt::DirectConnection);
+ connect(m_process, SIGNAL(readyReadStandardError()),
+ this, SLOT(processReadyReadStdError()),
+ Qt::DirectConnection);
+
+ connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(slotProcessFinished(int, QProcess::ExitStatus)),
+ Qt::DirectConnection);
+
+ m_process->start(m_command, m_arguments);
+ if(!m_process->waitForStarted()) {
+ processStartupFailed();
+ delete m_process;
+ m_process = 0;
+ fi.reportResult(false);
+ return;
+ }
+ processStarted();
+
+ m_timer = new QTimer();
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(checkForCancel()), Qt::DirectConnection);
+ m_timer->start(500);
+ m_eventLoop = new QEventLoop;
+ m_eventLoop->exec();
+ m_timer->stop();
+ delete m_timer;
+
+ // The process has finished, leftover data is read in processFinished
+ bool returnValue = processFinished(m_process->exitCode(), m_process->exitStatus());
+
+ delete m_process;
+ m_process = 0;
+ delete m_eventLoop;
+ m_eventLoop = 0;
+ fi.reportResult(returnValue);
+ return;
+}
+
+void AbstractProcessStep::processStarted()
+{
+ emit addToOutputWindow(tr("<font color=\"#0000ff\">Starting: %1 %2</font>\n").arg(m_command, m_arguments.join(" ")));
+}
+
+bool AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
+{
+ const bool ok = (status == QProcess::NormalExit && exitCode == 0);
+ if (ok) {
+ emit addToOutputWindow(tr("<font color=\"#0000ff\">Exited with code %1.</font>").arg(m_process->exitCode()));
+ } else {
+ emit addToOutputWindow(tr("<font color=\"#ff0000\"><b>Exited with code %1.</b></font>").arg(m_process->exitCode()));
+ }
+ return ok;
+}
+
+void AbstractProcessStep::processStartupFailed()
+{
+ emit addToOutputWindow(tr("<font color=\"#ff0000\">Could not start process %1 </b></font>").arg(m_command));
+}
+
+void AbstractProcessStep::processReadyReadStdOutput()
+{
+ m_process->setReadChannel(QProcess::StandardOutput);
+ while(m_process->canReadLine())
+ {
+ QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
+ stdOut(line);
+ }
+}
+
+void AbstractProcessStep::stdOut(const QString &line)
+{
+ emit addToOutputWindow(line);
+}
+
+void AbstractProcessStep::processReadyReadStdError()
+{
+ m_process->setReadChannel(QProcess::StandardError);
+ while (m_process->canReadLine())
+ {
+ QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
+ stdError(line);
+ }
+}
+
+void AbstractProcessStep::stdError(const QString &line)
+{
+ emit addToOutputWindow(QLatin1String("<font color=\"#ff0000\">") + line + QLatin1String("</font>"));
+}
+
+void AbstractProcessStep::checkForCancel()
+{
+ if(m_futureInterface->isCanceled() && m_timer->isActive()) {
+ m_timer->stop();
+ m_process->terminate();
+ m_process->waitForFinished(5000);
+ m_process->kill();
+ }
+}
+
+void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
+{
+ QString line = QString::fromLocal8Bit(m_process->readAllStandardError()).trimmed();
+ if (!line.isEmpty()) {
+ stdOut(line);
+ }
+
+ line = QString::fromLocal8Bit(m_process->readAllStandardOutput()).trimmed();
+ if (!line.isEmpty()) {
+ stdError(line);
+ }
+ m_eventLoop->exit(0);
+}
diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h
new file mode 100644
index 0000000000..33ddcbe6e5
--- /dev/null
+++ b/src/plugins/projectexplorer/abstractprocessstep.h
@@ -0,0 +1,141 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ABSTRACTPROCESSSTEP_H
+#define ABSTRACTPROCESSSTEP_H
+
+#include "buildstep.h"
+#include "environment.h"
+#include <QtCore/QString>
+#include <QtCore/QProcess>
+
+QT_BEGIN_NAMESPACE
+class QEventLoop;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+
+/*!
+ AbstractProcessStep is a convenience class, which can be used as a base class instead of BuildStep.
+ It should be used as a base class if your buildstep just needs to run a process.
+
+ Usage:
+ Use setCommand(), setArguments(), setWorkingDirectory() to specify the process you want to run.
+ (You need to do that before calling AbstractProcess::init())
+ Inside YourBuildStep::init() call AbstractProcessStep::init()
+ Inside YourBuildStep::run() call AbstractProcessStep::run(), which automatically starts the proces
+ and by default adds the output on stdOut and stdErr to the OutputWindow.
+ If you need to process the process output override stdOut() and/or stdErr.
+ The two functions processStarted() and processFinished() are called after starting/finishing the process.
+ By default they add a message to the output window.
+
+ Use setEnabled() to control wheter the BuildStep needs to run. (A disabled BuildStep immediately returns true,
+ from the run function.)
+
+*/
+
+class PROJECTEXPLORER_EXPORT AbstractProcessStep : public BuildStep
+{
+ Q_OBJECT
+public:
+ AbstractProcessStep(Project *pro);
+ // reimplemented from BuildStep::init()
+ // You need to call this from YourBuildStep::init()
+ virtual bool init(const QString & name);
+ // reimplemented from BuildStep::init()
+ // You need to call this from YourBuildStep::run()
+ virtual void run(QFutureInterface<bool> &);
+
+ // pure virtual functions inheritated from BuildStep
+ virtual QString name() = 0;
+ virtual QString displayName() = 0;
+ virtual BuildStepConfigWidget *createConfigWidget() = 0;
+ virtual bool immutable() const = 0;
+
+ // setCommand() sets the executable to run in the \p buildConfiguration
+ void setCommand(const QString &buildConfiguration, const QString &cmd);
+ // returns the executable that is run for the \p buildConfiguration
+ QString command(const QString &buildConfiguration) const;
+
+ // sets the workingDirectory for the process for a buildConfiguration
+ // if no workingDirectory is set, it falls back to the projects workingDirectory TODO remove that magic, thats bad
+ void setWorkingDirectory(const QString &buildConfiguration, const QString &workingDirectory);
+ //returns the workingDirectory for a \p buildConfiguration
+ QString workingDirectory(const QString &buildConfiguration) const;
+
+ // sets the command line arguments used by the process for a \p buildConfiguration
+ void setArguments(const QString &buildConfiguration, const QStringList &arguments);
+ // returns the arguments used in the \p buildCOnfiguration
+ QStringList arguments(const QString &buildConfiguration) const;
+
+ // enables or disables a BuildStep
+ // Disabled BuildSteps immediately return true from their run method
+ void setEnabled(const QString &buildConfiguration, bool b);
+ // returns wheter the BuildStep is disabled
+ bool enabled(const QString &buildConfiguration) const;
+
+ void setEnvironment(const QString &buildConfiguration, Environment env);
+ Environment environment(const QString &buildConfiguration) const;
+
+protected:
+ // Called after the process is started
+ // the default implementation adds a process started message to the output message
+ virtual void processStarted();
+ // Called after the process Finished
+ // the default implementation adds a line to the output window
+ virtual bool processFinished(int exitCode, QProcess::ExitStatus status);
+ // Called if the process could not be started,
+ // by default adds a message to the output window
+ virtual void processStartupFailed();
+ virtual void stdOut(const QString &line);
+ virtual void stdError(const QString &line);
+private slots:
+ void processReadyReadStdOutput();
+ void processReadyReadStdError();
+ void slotProcessFinished(int, QProcess::ExitStatus);
+ void checkForCancel();
+private:
+
+ QTimer *m_timer;
+ QFutureInterface<bool> *m_futureInterface;
+ QString m_workingDirectory;
+ QString m_command;
+ QStringList m_arguments;
+ bool m_enabled;
+ QProcess *m_process;
+ QEventLoop *m_eventLoop;
+ ProjectExplorer::Environment m_environment;
+};
+
+}
+
+#endif // ABSTRACTPROCESSSTEP_H
diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp
new file mode 100644
index 0000000000..7bed021323
--- /dev/null
+++ b/src/plugins/projectexplorer/allprojectsfilter.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "allprojectsfilter.h"
+#include "projectexplorer.h"
+#include "session.h"
+#include "project.h"
+
+#include <QtCore/QVariant>
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+AllProjectsFilter::AllProjectsFilter(ProjectExplorerPlugin *pe,
+ ICore *core)
+ : BaseFileFilter(core)
+{
+ m_projectExplorer = pe;
+ connect(m_projectExplorer, SIGNAL(fileListChanged()),
+ this, SLOT(refreshInternally()));
+ setShortcutString("a");
+ setIncludedByDefault(true);
+}
+
+void AllProjectsFilter::refreshInternally()
+{
+ m_files.clear();
+ SessionManager *session = m_projectExplorer->session();
+ if (!session)
+ return;
+ foreach (Project *project, session->projects())
+ m_files += project->files(Project::AllFiles);
+ qSort(m_files);
+ generateFileNames();
+}
+
+void AllProjectsFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+ // invokeAsyncronouslyOnGuiThread
+ connect(this, SIGNAL(invokeRefresh()), this, SLOT(refreshInternally()));
+ emit invokeRefresh();
+ disconnect(this, SIGNAL(invokeRefresh()), this, SLOT(refreshInternally()));
+}
diff --git a/src/plugins/projectexplorer/allprojectsfilter.h b/src/plugins/projectexplorer/allprojectsfilter.h
new file mode 100644
index 0000000000..673c5da99e
--- /dev/null
+++ b/src/plugins/projectexplorer/allprojectsfilter.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ALLPROJECTSFILTER_H
+#define ALLPROJECTSFILTER_H
+
+#include <quickopen/basefilefilter.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+#include <QtGui/QWidget>
+
+
+namespace ProjectExplorer {
+
+class ProjectExplorerPlugin;
+
+namespace Internal {
+
+class AllProjectsFilter : public QuickOpen::BaseFileFilter
+{
+ Q_OBJECT
+
+public:
+ AllProjectsFilter(ProjectExplorerPlugin *pe, Core::ICore *core);
+ QString trName() const { return tr("File in any project"); }
+ QString name() const { return "File in any project"; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::Low; }
+ void refresh(QFutureInterface<void> &future);
+
+private slots:
+ void refreshInternally();
+signals:
+ void invokeRefresh();
+private:
+ ProjectExplorerPlugin *m_projectExplorer;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // ALLPROJECTSFILTER_H
diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp
new file mode 100644
index 0000000000..2c9c3875f0
--- /dev/null
+++ b/src/plugins/projectexplorer/allprojectsfind.cpp
@@ -0,0 +1,133 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "allprojectsfind.h"
+#include "projectexplorer.h"
+#include "project.h"
+
+#include <QtDebug>
+#include <QtCore/QRegExp>
+#include <QtGui/QGridLayout>
+
+using namespace Find;
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+using namespace TextEditor;
+
+AllProjectsFind::AllProjectsFind(ProjectExplorerPlugin *plugin, Core::ICore *core, SearchResultWindow *resultWindow)
+ : BaseFileFind(core, resultWindow),
+ m_plugin(plugin),
+ m_configWidget(0)
+{
+ connect(m_plugin, SIGNAL(fileListChanged()), this, SIGNAL(changed()));
+}
+
+QString AllProjectsFind::name() const
+{
+ return tr("All Projects");
+}
+
+bool AllProjectsFind::isEnabled() const
+{
+ return BaseFileFind::isEnabled()
+ && m_plugin->session() != 0
+ && m_plugin->session()->projects().count() > 0;
+}
+
+QKeySequence AllProjectsFind::defaultShortcut() const
+{
+ return QKeySequence("Ctrl+Shift+F");
+}
+
+QStringList AllProjectsFind::files()
+{
+ Q_ASSERT(m_plugin->session());
+ if (!m_plugin->session())
+ return QStringList();
+ QList<QRegExp> filterRegs;
+ QStringList nameFilters = fileNameFilters();
+ foreach (const QString &filter, nameFilters) {
+ filterRegs << QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard);
+ }
+ QStringList files;
+ QStringList projectFiles;
+ foreach (const Project *project, m_plugin->session()->projects()) {
+ projectFiles = project->files(Project::AllFiles);
+ if (!filterRegs.isEmpty()) {
+ foreach (const QString &file, projectFiles) {
+ foreach (const QRegExp &reg, filterRegs) {
+ if (reg.exactMatch(file)) {
+ files.append(file);
+ break;
+ }
+ }
+ }
+ } else {
+ files += projectFiles;
+ }
+ }
+ files.removeDuplicates();
+ return files;
+}
+
+QWidget *AllProjectsFind::createConfigWidget()
+{
+ if (!m_configWidget) {
+ m_configWidget = new QWidget;
+ QGridLayout * const gridLayout = new QGridLayout(m_configWidget);
+ gridLayout->setMargin(0);
+ m_configWidget->setLayout(gridLayout);
+ gridLayout->addWidget(createRegExpWidget(), 0, 1);
+ QLabel * const filePatternLabel = new QLabel(tr("File pattern:"));
+ filePatternLabel->setMinimumWidth(80);
+ filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ gridLayout->addWidget(filePatternLabel, 1, 0, Qt::AlignRight);
+ gridLayout->addWidget(createPatternWidget(), 1, 1);
+ m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ }
+ return m_configWidget;
+}
+
+void AllProjectsFind::writeSettings(QSettings *settings)
+{
+ settings->beginGroup("AllProjectsFind");
+ writeCommonSettings(settings);
+ settings->endGroup();
+}
+
+void AllProjectsFind::readSettings(QSettings *settings)
+{
+ settings->beginGroup("AllProjectsFind");
+ readCommonSettings(settings, "*");
+ settings->endGroup();
+}
diff --git a/src/plugins/projectexplorer/allprojectsfind.h b/src/plugins/projectexplorer/allprojectsfind.h
new file mode 100644
index 0000000000..f5bba54a03
--- /dev/null
+++ b/src/plugins/projectexplorer/allprojectsfind.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ALLPROJECTSFIND_H
+#define ALLPROJECTSFIND_H
+
+#include <coreplugin/icore.h>
+#include <find/ifindfilter.h>
+#include <find/searchresultwindow.h>
+#include <texteditor/basefilefind.h>
+
+#include <QtCore/QPointer>
+#include <QtGui/QLabel>
+#include <QtGui/QComboBox>
+#include <QtGui/QStringListModel>
+
+
+namespace ProjectExplorer {
+
+class ProjectExplorerPlugin;
+
+namespace Internal {
+
+class AllProjectsFind : public TextEditor::BaseFileFind
+{
+ Q_OBJECT
+
+public:
+ AllProjectsFind(ProjectExplorerPlugin *plugin, Core::ICore *core, Find::SearchResultWindow *resultWindow);
+
+ QString name() const;
+
+ bool isEnabled() const;
+ QKeySequence defaultShortcut() const;
+
+ QWidget *createConfigWidget();
+ void writeSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+protected:
+ QStringList files();
+
+private:
+ ProjectExplorerPlugin *m_plugin;
+ QPointer<QWidget> m_configWidget;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // ALLPROJECTSFIND_H
diff --git a/src/plugins/projectexplorer/applicationlauncher.h b/src/plugins/projectexplorer/applicationlauncher.h
new file mode 100644
index 0000000000..6c4e6a2a86
--- /dev/null
+++ b/src/plugins/projectexplorer/applicationlauncher.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef APPLICATIONLAUNCHER_H
+#define APPLICATIONLAUNCHER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QProcess>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class ConsoleProcess;
+class WinGuiProcess;
+
+class ApplicationLauncher : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Mode {
+ Console,
+ Gui
+ };
+
+ ApplicationLauncher(QObject *parent = 0);
+ void setWorkingDirectory(const QString &dir);
+ void setEnvironment(const QStringList &env);
+
+ void start(Mode mode, const QString &program,
+ const QStringList &args = QStringList());
+ void stop();
+ bool isRunning() const;
+ qint64 applicationPID() const;
+
+signals:
+ void applicationError(const QString &error);
+ void appendOutput(const QString &line);
+ void processExited(int exitCode);
+ void bringToForegroundRequested(qint64 pid);
+
+private slots:
+ void processStopped();
+#ifdef Q_OS_WIN
+ void readWinDebugOutput(const QString &output);
+ void processFinished(int exitCode);
+#else
+ void guiProcessError();
+ void readStandardOutput();
+ void processDone(int, QProcess::ExitStatus);
+#endif
+
+ void bringToForeground();
+
+private:
+ QProcess *m_guiProcess;
+ ConsoleProcess *m_consoleProcess;
+ Mode m_currentMode;
+
+ WinGuiProcess *m_winGuiProcess;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // APPLICATIONLAUNCHER_H
diff --git a/src/plugins/projectexplorer/applicationlauncher_win.cpp b/src/plugins/projectexplorer/applicationlauncher_win.cpp
new file mode 100644
index 0000000000..b7cac9a743
--- /dev/null
+++ b/src/plugins/projectexplorer/applicationlauncher_win.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+#include <QDebug>
+#include "applicationlauncher.h"
+#include "consoleprocess.h"
+#include "winguiprocess.h"
+
+using namespace ProjectExplorer::Internal;
+
+ApplicationLauncher::ApplicationLauncher(QObject *parent)
+ : QObject(parent)
+{
+ m_currentMode = Gui;
+
+ m_consoleProcess = new ConsoleProcess(this);
+ connect(m_consoleProcess, SIGNAL(processError(const QString&)),
+ this, SIGNAL(applicationError(const QString&)));
+ connect(m_consoleProcess, SIGNAL(processStopped()),
+ this, SLOT(processStopped()));
+
+ m_winGuiProcess = new WinGuiProcess(this);
+ connect(m_winGuiProcess, SIGNAL(processError(const QString&)),
+ this, SIGNAL(applicationError(const QString&)));
+ connect(m_winGuiProcess, SIGNAL(receivedDebugOutput(const QString&)),
+ this, SLOT(readWinDebugOutput(const QString&)));
+ connect(m_winGuiProcess, SIGNAL(processFinished(int)),
+ this, SLOT(processFinished(int)));
+
+}
+
+void ApplicationLauncher::setWorkingDirectory(const QString &dir)
+{
+ m_winGuiProcess->setWorkingDirectory(dir);
+ m_consoleProcess->setWorkingDirectory(dir);
+}
+
+void ApplicationLauncher::setEnvironment(const QStringList &env)
+{
+ m_winGuiProcess->setEnvironment(env);
+ m_consoleProcess->setEnvironment(env);
+}
+
+void ApplicationLauncher::start(Mode mode, const QString &program, const QStringList &args)
+{
+ qDebug()<<"ApplicationLauncher::start"<<program<<args;
+ m_currentMode = mode;
+ if (mode == Gui) {
+ m_winGuiProcess->start(program, args);
+ } else {
+ m_consoleProcess->start(program, args);
+ }
+}
+
+void ApplicationLauncher::stop()
+{
+ if (m_currentMode == Gui) {
+ m_winGuiProcess->stop();
+ } else {
+ m_consoleProcess->stop();
+ }
+}
+
+bool ApplicationLauncher::isRunning() const
+{
+ if (m_currentMode == Gui)
+ return m_winGuiProcess->isRunning();
+ else
+ return m_consoleProcess->isRunning();
+}
+
+qint64 ApplicationLauncher::applicationPID() const
+{
+ qint64 result = 0;
+ if (!isRunning())
+ return result;
+
+ if (m_currentMode == Console) {
+ result = m_consoleProcess->applicationPID();
+ } else {
+ result = m_winGuiProcess->applicationPID();
+ }
+ return result;
+}
+
+void ApplicationLauncher::readWinDebugOutput(const QString &output)
+{
+ QString s = output;
+ if (s.endsWith(QLatin1Char('\n')))
+ s.chop(1);
+ emit appendOutput(s);
+}
+
+void ApplicationLauncher::processStopped()
+{
+ emit processExited(0);
+}
+
+void ApplicationLauncher::processFinished(int exitCode)
+{
+ emit processExited(exitCode);
+}
+
+void ApplicationLauncher::bringToForeground()
+{
+}
diff --git a/src/plugins/projectexplorer/applicationlauncher_x11.cpp b/src/plugins/projectexplorer/applicationlauncher_x11.cpp
new file mode 100644
index 0000000000..84054271d0
--- /dev/null
+++ b/src/plugins/projectexplorer/applicationlauncher_x11.cpp
@@ -0,0 +1,159 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "applicationlauncher.h"
+#include "consoleprocess.h"
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+#include <QtCore/QTimer>
+#include <QtDebug>
+
+using namespace ProjectExplorer::Internal;
+
+ApplicationLauncher::ApplicationLauncher(QObject *parent)
+ : QObject(parent)
+{
+ m_currentMode = Gui;
+ m_guiProcess = new QProcess(this);
+ m_guiProcess->setReadChannelMode(QProcess::MergedChannels);
+ connect(m_guiProcess, SIGNAL(error(QProcess::ProcessError)),
+ this, SLOT(guiProcessError()));
+ connect(m_guiProcess, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(readStandardOutput()));
+ connect(m_guiProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(processDone(int, QProcess::ExitStatus)));
+ connect(m_guiProcess, SIGNAL(started()),
+ this, SLOT(bringToForeground()));
+
+ m_consoleProcess = new ConsoleProcess(this);
+ connect(m_consoleProcess, SIGNAL(processError(const QString&)),
+ this, SIGNAL(applicationError(const QString&)));
+ connect(m_consoleProcess, SIGNAL(processStopped()),
+ this, SLOT(processStopped()));
+}
+
+void ApplicationLauncher::setWorkingDirectory(const QString &dir)
+{
+ m_guiProcess->setWorkingDirectory(dir);
+ m_consoleProcess->setWorkingDirectory(dir);
+}
+
+void ApplicationLauncher::setEnvironment(const QStringList &env)
+{
+ m_guiProcess->setEnvironment(env);
+ m_consoleProcess->setEnvironment(env);
+}
+
+void ApplicationLauncher::start(Mode mode, const QString &program, const QStringList &args)
+{
+ m_currentMode = mode;
+ if (mode == Gui) {
+ m_guiProcess->start(program, args);
+ } else {
+ m_consoleProcess->start(program, args);
+ }
+}
+
+void ApplicationLauncher::stop()
+{
+ if (m_currentMode == Gui) {
+ m_guiProcess->terminate();
+ m_guiProcess->waitForFinished();
+ } else {
+ m_consoleProcess->stop();
+ }
+}
+
+bool ApplicationLauncher::isRunning() const
+{
+ if (m_currentMode == Gui)
+ return m_guiProcess->state() != QProcess::NotRunning;
+ else
+ return m_consoleProcess->isRunning();
+}
+
+qint64 ApplicationLauncher::applicationPID() const
+{
+ qint64 result = 0;
+ if (!isRunning())
+ return result;
+
+ if (m_currentMode == Console) {
+ result = m_consoleProcess->applicationPID();
+ } else {
+ result = (qint64)m_guiProcess->pid();
+ }
+ return result;
+}
+
+void ApplicationLauncher::guiProcessError()
+{
+ QString error;
+ switch (m_guiProcess->error()) {
+ case QProcess::FailedToStart:
+ error = tr("Failed to start program. Path or permissions wrong?");
+ break;
+ case QProcess::Crashed:
+ error = tr("The program has unexpectedly finished.");
+ break;
+ default:
+ error = tr("Some error has occurred while running the program.");
+ }
+ emit applicationError(error);
+}
+
+void ApplicationLauncher::readStandardOutput()
+{
+ m_guiProcess->setReadChannel(QProcess::StandardOutput);
+ while (m_guiProcess->canReadLine()) {
+ QString line = QString::fromLocal8Bit(m_guiProcess->readLine());
+ if (line.endsWith(QLatin1Char('\n')))
+ line.chop(1);
+ emit appendOutput(line);
+ }
+}
+
+void ApplicationLauncher::processStopped()
+{
+ emit processExited(0);
+}
+
+void ApplicationLauncher::processDone(int exitCode, QProcess::ExitStatus)
+{
+ emit processExited(exitCode);
+}
+
+void ApplicationLauncher::bringToForeground()
+{
+ emit bringToForegroundRequested(applicationPID());
+}
diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.cpp b/src/plugins/projectexplorer/applicationrunconfiguration.cpp
new file mode 100644
index 0000000000..9f4cca193b
--- /dev/null
+++ b/src/plugins/projectexplorer/applicationrunconfiguration.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "applicationrunconfiguration.h"
+#include "persistentsettings.h"
+#include "environment.h"
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <QtGui/QLabel>
+#include <QDebug>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+/// ApplicationRunConfiguration
+
+ApplicationRunConfiguration::ApplicationRunConfiguration(Project *pro)
+ : RunConfiguration(pro)
+{
+}
+
+ApplicationRunConfiguration::~ApplicationRunConfiguration()
+{
+}
+
+QString ApplicationRunConfiguration::type() const
+{
+ return "ProjectExplorer.ApplicationRunConfiguration";
+}
+
+void ApplicationRunConfiguration::save(PersistentSettingsWriter &writer) const
+{
+ RunConfiguration::save(writer);
+}
+
+void ApplicationRunConfiguration::restore(const PersistentSettingsReader &reader)
+{
+ RunConfiguration::restore(reader);
+}
+
+/// ApplicationRunConfigurationRunner
+
+ApplicationRunConfigurationRunner::ApplicationRunConfigurationRunner()
+{
+}
+
+ApplicationRunConfigurationRunner::~ApplicationRunConfigurationRunner()
+{
+}
+
+bool ApplicationRunConfigurationRunner::canRun(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode)
+{
+ return (mode == ProjectExplorer::Constants::RUNMODE)
+ && (!qSharedPointerCast<ApplicationRunConfiguration>(runConfiguration).isNull());
+}
+
+QString ApplicationRunConfigurationRunner::displayName() const
+{
+ return QObject::tr("Run");
+}
+
+RunControl* ApplicationRunConfigurationRunner::run(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode)
+{
+ QSharedPointer<ApplicationRunConfiguration> rc = qSharedPointerCast<ApplicationRunConfiguration>(runConfiguration);
+ Q_ASSERT(rc);
+ Q_ASSERT(mode == ProjectExplorer::Constants::RUNMODE);
+
+ ApplicationRunControl *runControl = new ApplicationRunControl(rc);
+ return runControl;
+}
+
+QWidget *ApplicationRunConfigurationRunner::configurationWidget(QSharedPointer<RunConfiguration> runConfiguration)
+{
+ Q_UNUSED(runConfiguration);
+ return new QLabel("TODO add Configuration widget");
+}
+
+// ApplicationRunControl
+
+ApplicationRunControl::ApplicationRunControl(QSharedPointer<ApplicationRunConfiguration> runConfiguration)
+ : RunControl(runConfiguration), m_applicationLauncher()
+{
+ connect(&m_applicationLauncher, SIGNAL(applicationError(const QString &)),
+ this, SLOT(slotError(const QString &)));
+ connect(&m_applicationLauncher, SIGNAL(appendOutput(const QString &)),
+ this, SLOT(slotAddToOutputWindow(const QString &)));
+ connect(&m_applicationLauncher, SIGNAL(processExited(int)),
+ this, SLOT(processExited(int)));
+ connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
+ this, SLOT(bringApplicationToForeground(qint64)));
+}
+
+ApplicationRunControl::~ApplicationRunControl()
+{
+}
+
+void ApplicationRunControl::start()
+{
+ QSharedPointer<ApplicationRunConfiguration> rc = qSharedPointerCast<ApplicationRunConfiguration>(runConfiguration());
+ Q_ASSERT(rc);
+
+ m_applicationLauncher.setEnvironment(rc->environment().toStringList());
+ m_applicationLauncher.setWorkingDirectory(rc->workingDirectory());
+
+ m_executable = rc->executable();
+
+ m_applicationLauncher.start(static_cast<Internal::ApplicationLauncher::Mode>(rc->runMode()),
+ m_executable, rc->commandLineArguments());
+ emit started();
+
+ emit addToOutputWindow(this, tr("Starting %1").arg(m_executable));
+}
+
+void ApplicationRunControl::stop()
+{
+ m_applicationLauncher.stop();
+}
+
+bool ApplicationRunControl::isRunning() const
+{
+ return m_applicationLauncher.isRunning();
+}
+
+void ApplicationRunControl::slotError(const QString & err)
+{
+ emit error(this, err);
+ emit finished();
+}
+
+void ApplicationRunControl::slotAddToOutputWindow(const QString &line)
+{
+ emit addToOutputWindow(this, line);
+}
+
+void ApplicationRunControl::processExited(int exitCode)
+{
+ emit addToOutputWindow(this, tr("%1 exited with code %2").arg(m_executable).arg(exitCode));
+ emit finished();
+}
+
diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.h b/src/plugins/projectexplorer/applicationrunconfiguration.h
new file mode 100644
index 0000000000..e837869185
--- /dev/null
+++ b/src/plugins/projectexplorer/applicationrunconfiguration.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef APPLICATIONRUNCONFIGURATION_H
+#define APPLICATIONRUNCONFIGURATION_H
+
+#include "runconfiguration.h"
+#include "applicationlauncher.h"
+
+namespace ProjectExplorer {
+
+class Environment;
+
+class PROJECTEXPLORER_EXPORT ApplicationRunConfiguration : public RunConfiguration
+{
+ Q_OBJECT
+public:
+ enum RunMode {
+ Console = Internal::ApplicationLauncher::Console,
+ Gui
+ };
+
+ ApplicationRunConfiguration(Project *pro);
+ virtual ~ApplicationRunConfiguration();
+ virtual QString type() const;
+ virtual QString executable() const = 0;
+ virtual RunMode runMode() const = 0;
+ virtual QString workingDirectory() const = 0;
+ virtual QStringList commandLineArguments() const = 0;
+ virtual Environment environment() const = 0;
+
+ virtual void save(PersistentSettingsWriter &writer) const;
+ virtual void restore(const PersistentSettingsReader &reader);
+};
+
+namespace Internal {
+
+class ApplicationRunConfigurationRunner : public IRunConfigurationRunner
+{
+ Q_OBJECT
+public:
+ ApplicationRunConfigurationRunner();
+ virtual ~ApplicationRunConfigurationRunner();
+ virtual bool canRun(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode);
+ virtual QString displayName() const;
+ virtual RunControl* run(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode);
+ virtual QWidget *configurationWidget(QSharedPointer<RunConfiguration> runConfiguration);
+};
+
+class ApplicationRunControl : public RunControl
+{
+ Q_OBJECT
+public:
+ ApplicationRunControl(QSharedPointer<ApplicationRunConfiguration> runConfiguration);
+ virtual ~ApplicationRunControl();
+ virtual void start();
+ virtual void stop();
+ virtual bool isRunning() const;
+private slots:
+ void processExited(int exitCode);
+ void slotAddToOutputWindow(const QString &line);
+ void slotError(const QString & error);
+private:
+ ApplicationLauncher m_applicationLauncher;
+ QString m_executable;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // APPLICATIONRUNCONFIGURATION_H
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
new file mode 100644
index 0000000000..a886af0460
--- /dev/null
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildconfiguration.h"
+
+using namespace ProjectExplorer;
+
+BuildConfiguration::BuildConfiguration(const QString &name)
+ : m_name(name)
+{
+ setDisplayName(name);
+}
+
+BuildConfiguration::BuildConfiguration(const QString &name, BuildConfiguration *source)
+ :m_values(source->m_values), m_name(name)
+{
+
+}
+
+QString BuildConfiguration::name() const
+{
+ return m_name;
+}
+
+QString BuildConfiguration::displayName()
+{
+ QVariant v = getValue("ProjectExplorer.BuildConfiguration.DisplayName");
+ if (v.isValid()) {
+ return v.toString();
+ } else {
+ setDisplayName(m_name);
+ return m_name;
+ }
+}
+
+void BuildConfiguration::setDisplayName(const QString &name)
+{
+ setValue("ProjectExplorer.BuildConfiguration.DisplayName", name);
+}
+
+QVariant BuildConfiguration::getValue(const QString & key) const
+{
+ QHash<QString, QVariant>::const_iterator it = m_values.find(key);
+ if(it != m_values.constEnd())
+ return *it;
+ else
+ return QVariant();
+}
+
+void BuildConfiguration::setValue(const QString & key, QVariant value)
+{
+ m_values[key] = value;
+}
+
+void BuildConfiguration::setValuesFromMap(QMap<QString, QVariant> map)
+{
+ QMap<QString, QVariant>::const_iterator it, end;
+ end = map.constEnd();
+ for(it = map.constBegin(); it != end; ++it)
+ setValue(it.key(), it.value());
+}
+
+QMap<QString, QVariant> BuildConfiguration::toMap() const
+{
+ QMap<QString, QVariant> result;
+ QHash<QString, QVariant>::const_iterator it, end;
+ end = m_values.constEnd();
+ for(it = m_values.constBegin(); it != end; ++it)
+ result.insert(it.key(), it.value());
+ return result;
+}
+
diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h
new file mode 100644
index 0000000000..a9e41e039e
--- /dev/null
+++ b/src/plugins/projectexplorer/buildconfiguration.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDCONFIGURATION_H
+#define BUILDCONFIGURATION_H
+
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QHash>
+
+namespace ProjectExplorer {
+
+class BuildConfiguration
+{
+public:
+ BuildConfiguration(const QString &name);
+ BuildConfiguration(const QString &name, BuildConfiguration *source);
+ QString name() const;
+ QVariant getValue(const QString & key) const;
+ void setValue(const QString & key, QVariant value);
+
+ QString displayName();
+ void setDisplayName(const QString &name);
+
+ QMap<QString, QVariant> toMap() const;
+ void setValuesFromMap(QMap<QString, QVariant> map);
+
+private:
+ QHash<QString, QVariant> m_values;
+ QString m_name;
+};
+
+}
+
+#endif
diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp
new file mode 100644
index 0000000000..87bc38aa86
--- /dev/null
+++ b/src/plugins/projectexplorer/buildmanager.cpp
@@ -0,0 +1,385 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildmanager.h"
+#include "buildstep.h"
+#include "compileoutputwindow.h"
+#include "taskwindow.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+#include "buildprogress.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <coreplugin/progressmanager/futureprogress.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTimer>
+#include <QtGui/QHeaderView>
+#include <QtGui/QIcon>
+#include <QtGui/QLabel>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+BuildManager::BuildManager(ProjectExplorerPlugin *parent)
+ : QObject(parent)
+ , m_running(false)
+ , m_previousBuildStepProject(0)
+ , m_canceling(false)
+ , m_maxProgress(0)
+ , m_progressFutureInterface(0)
+{
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ m_projectExplorerPlugin = parent;
+
+ connect(&m_watcher, SIGNAL(finished()),
+ this, SLOT(nextBuildQueue()));
+
+ m_outputWindow = new CompileOutputWindow(this);
+ pm->addObject(m_outputWindow);
+
+ m_taskWindow = new TaskWindow;
+ pm->addObject(m_taskWindow);
+
+ connect(m_taskWindow, SIGNAL(tasksChanged()),
+ this, SIGNAL(tasksChanged()));
+
+ connect(&m_progressWatcher, SIGNAL(canceled()),
+ this, SLOT(cancel()));
+}
+
+BuildManager::~BuildManager()
+{
+ cancel();
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+
+ pm->removeObject(m_taskWindow);
+ delete m_taskWindow;
+
+ pm->removeObject(m_outputWindow);
+ delete m_outputWindow;
+}
+
+bool BuildManager::isBuilding() const
+{
+ // we are building even if we are not running yet
+ return !m_buildQueue.isEmpty() || m_running;
+}
+
+void BuildManager::cancel()
+{
+ if (m_running) {
+ m_canceling = true;
+ m_watcher.cancel();
+ m_watcher.waitForFinished();
+
+ // The cancel message is added to the output window via a single shot timer
+ // since the canceling is likely to have generated new addToOutputWindow signals
+ // which are waiting in the event queue to be processed
+ // (And we want those to be before the cancel message.)
+ QTimer::singleShot(0, this, SLOT(emitCancelMessage()));
+
+ disconnect(m_currentBuildStep, SIGNAL(addToTaskWindow(QString, int, int, QString)),
+ this, SLOT(addToTaskWindow(QString, int, int, QString)));
+ disconnect(m_currentBuildStep, SIGNAL(addToOutputWindow(QString)),
+ this, SLOT(addToOutputWindow(QString)));
+ decrementActiveBuildSteps(m_currentBuildStep->project());
+
+ m_progressFutureInterface->setProgressValueAndText(m_progress, "Build canceled"); //TODO NBS fix in qtconcurrent
+ clearBuildQueue();
+ }
+ return;
+}
+
+void BuildManager::emitCancelMessage()
+{
+ emit addToOutputWindow(tr("<font color=\"#ff0000\">Canceled build.</font>"));
+}
+
+void BuildManager::clearBuildQueue()
+{
+ foreach (BuildStep * bs, m_buildQueue)
+ decrementActiveBuildSteps(bs->project());
+
+ m_buildQueue.clear();
+ m_configurations.clear();
+ m_running = false;
+ m_previousBuildStepProject = 0;
+
+ m_progressFutureInterface->reportCanceled();
+ m_progressFutureInterface->reportFinished();
+ delete m_progressFutureInterface;
+ m_progressFutureInterface = 0;
+ m_maxProgress = 0;
+
+ emit buildQueueFinished(false);
+}
+
+
+void BuildManager::toggleOutputWindow()
+{
+ m_outputWindow->toggle(false);
+}
+
+void BuildManager::showTaskWindow()
+{
+ m_taskWindow->popup(false);
+}
+
+void BuildManager::toggleTaskWindow()
+{
+ m_taskWindow->toggle(false);
+}
+
+bool BuildManager::tasksAvailable() const
+{
+ return m_taskWindow->numberOfTasks() > 0;
+}
+
+void BuildManager::gotoTaskWindow()
+{
+ m_taskWindow->popup(true);
+}
+
+void BuildManager::startBuildQueue()
+{
+ if (!m_running) {
+ // Progress Reporting
+ Core::ProgressManagerInterface *progressManager =
+ ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->progressManager();
+ m_progressFutureInterface = new QFutureInterface<void>;
+ m_progressWatcher.setFuture(m_progressFutureInterface->future());
+ Core::FutureProgress *progress = progressManager->addTask(m_progressFutureInterface->future(),
+ tr("Build"),
+ Constants::TASK_BUILD);
+ connect(progress, SIGNAL(clicked()), this, SLOT(showBuildResults()));
+ progress->setWidget(new BuildProgress(m_taskWindow));
+ m_progress = 0;
+ m_progressFutureInterface->setProgressRange(0, m_maxProgress);
+
+ m_running = true;
+ m_canceling = false;
+ m_progressFutureInterface->reportStarted();
+ m_outputWindow->clearContents();
+ m_taskWindow->clearContents();
+ nextStep();
+ } else {
+ // Already running
+ m_progressFutureInterface->setProgressRange(0, m_maxProgress);
+ const QString &progressText = tr("Finished %1 of %2 build steps").arg(m_progress).arg(m_maxProgress);
+ m_progressFutureInterface->setProgressValueAndText(m_progress, progressText);
+ }
+}
+
+void BuildManager::showBuildResults()
+{
+ if (m_taskWindow->numberOfTasks() != 0)
+ toggleTaskWindow();
+ else
+ toggleOutputWindow();
+ //toggleTaskWindow();
+}
+
+void BuildManager::addToTaskWindow(const QString &file, int type, int line, const QString &description)
+{
+ m_taskWindow->addItem(BuildParserInterface::PatternType(type), description, file, line);
+}
+
+void BuildManager::addToOutputWindow(const QString &string)
+{
+ m_outputWindow->appendText(string);
+}
+
+void BuildManager::nextBuildQueue()
+{
+ if (m_canceling)
+ return;
+
+ disconnect(m_currentBuildStep, SIGNAL(addToTaskWindow(QString, int, int, QString)),
+ this, SLOT(addToTaskWindow(QString, int, int, QString)));
+ disconnect(m_currentBuildStep, SIGNAL(addToOutputWindow(QString)),
+ this, SLOT(addToOutputWindow(QString)));
+
+ ++m_progress;
+ const QString &progressText = tr("Finished %1 of %2 build steps").arg(m_progress).arg(m_maxProgress);
+ m_progressFutureInterface->setProgressValueAndText(m_progress, progressText);
+
+ bool result = m_watcher.result();
+ if (!result) {
+ // Build Failure
+ addToOutputWindow(tr("<font color=\"#ff0000\">Error while building project %1</font>").arg(m_currentBuildStep->project()->name()));
+ addToOutputWindow(tr("<font color=\"#ff0000\">When executing build step '%1'</font>").arg(m_currentBuildStep->displayName()));
+ // NBS TODO fix in qtconcurrent
+ m_progressFutureInterface->setProgressValueAndText(m_progress, tr("Error while building project %1").arg(m_currentBuildStep->project()->name()));
+ }
+
+ decrementActiveBuildSteps(m_currentBuildStep->project());
+ if (result)
+ nextStep();
+ else
+ clearBuildQueue();
+}
+
+void BuildManager::nextStep()
+{
+ if (!m_buildQueue.empty()) {
+ m_currentBuildStep = m_buildQueue.front();
+ m_currentConfiguration = m_configurations.front();
+ m_buildQueue.pop_front();
+ m_configurations.pop_front();
+
+ connect(m_currentBuildStep, SIGNAL(addToTaskWindow(QString, int, int, QString)),
+ this, SLOT(addToTaskWindow(QString, int, int, QString)));
+ connect(m_currentBuildStep, SIGNAL(addToOutputWindow(QString)),
+ this, SLOT(addToOutputWindow(QString)));
+
+ bool init = m_currentBuildStep->init(m_currentConfiguration);
+ if (!init) {
+ addToOutputWindow(tr("<font color=\"#ff0000\">Error while building project %1</font>").arg(m_currentBuildStep->project()->name()));
+ addToOutputWindow(tr("<font color=\"#ff0000\">When executing build step '%1'</font>").arg(m_currentBuildStep->displayName()));
+ cancel();
+ return;
+ }
+
+ if (m_currentBuildStep->project() != m_previousBuildStepProject) {
+ const QString projectName = m_currentBuildStep->project()->name();
+ addToOutputWindow(tr("<b>Running build steps for project %2...</b>")
+ .arg(projectName));
+ m_previousBuildStepProject = m_currentBuildStep->project();
+ }
+ m_watcher.setFuture(QtConcurrent::run(&BuildStep::run, m_currentBuildStep));
+ } else {
+ m_running = false;
+ m_previousBuildStepProject = 0;
+ m_progressFutureInterface->reportFinished();
+ delete m_progressFutureInterface;
+ m_progressFutureInterface = 0;
+ m_maxProgress = 0;
+ emit buildQueueFinished(true);
+ }
+}
+
+void BuildManager::buildQueueAppend(BuildStep * bs, const QString &configuration)
+{
+ m_buildQueue.append(bs);
+ ++m_maxProgress;
+ incrementActiveBuildSteps(bs->project());
+ m_configurations.append(configuration);
+}
+
+void BuildManager::buildProjects(const QList<Project *> &projects, const QList<QString> &configurations)
+{
+ Q_ASSERT(projects.count() == configurations.count());
+ QList<QString>::const_iterator cit = configurations.constBegin();
+ QList<Project *>::const_iterator it, end;
+ end = projects.constEnd();
+
+ for (it = projects.constBegin(); it != end; ++it, ++cit) {
+ QList<BuildStep *> buildSteps = (*it)->buildSteps();
+ foreach (BuildStep *bs, buildSteps) {
+ buildQueueAppend(bs, *cit);
+ }
+ }
+ startBuildQueue();
+}
+
+void BuildManager::cleanProjects(const QList<Project *> &projects, const QList<QString> &configurations)
+{
+ Q_ASSERT(projects.count() == configurations.count());
+ QList<QString>::const_iterator cit = configurations.constBegin();
+ QList<Project *>::const_iterator it, end;
+ end = projects.constEnd();
+
+ for (it = projects.constBegin(); it != end; ++it, ++cit) {
+ QList<BuildStep *> cleanSteps = (*it)->cleanSteps();
+ foreach (BuildStep *bs, cleanSteps) {
+ buildQueueAppend(bs, *cit);
+ }
+ }
+ startBuildQueue();
+}
+
+void BuildManager::buildProject(Project *p, const QString &configuration)
+{
+ buildProjects(QList<Project *>() << p, QList<QString>() << configuration);
+}
+
+void BuildManager::cleanProject(Project *p, const QString &configuration)
+{
+ cleanProjects(QList<Project *>() << p, QList<QString>() << configuration);
+}
+
+void BuildManager::appendStep(BuildStep *step, const QString &configuration)
+{
+ buildQueueAppend(step, configuration);
+ startBuildQueue();
+}
+
+bool BuildManager::isBuilding(Project *pro)
+{
+ QHash<Project *, int>::iterator it = m_activeBuildSteps.find(pro);
+ QHash<Project *, int>::iterator end = m_activeBuildSteps.end();
+ if (it == end || *it == 0)
+ return false;
+ else
+ return true;
+}
+
+void BuildManager::incrementActiveBuildSteps(Project *pro)
+{
+ QHash<Project *, int>::iterator it = m_activeBuildSteps.find(pro);
+ QHash<Project *, int>::iterator end = m_activeBuildSteps.end();
+ if (it == end) {
+ m_activeBuildSteps.insert(pro, 1);
+ emit buildStateChanged(pro);
+ } else if (*it == 0) {
+ ++*it;
+ emit buildStateChanged(pro);
+ } else {
+ ++*it;
+ }
+}
+
+void BuildManager::decrementActiveBuildSteps(Project *pro)
+{
+ QHash<Project *, int>::iterator it = m_activeBuildSteps.find(pro);
+ QHash<Project *, int>::iterator end = m_activeBuildSteps.end();
+ if (it == end) {
+ Q_ASSERT(false && "BuildManager m_activeBuildSteps says project is not building, but apparently a build step was still in the queue.");
+ } else if (*it == 1) {
+ --*it;
+ emit buildStateChanged(pro);
+ } else {
+ --*it;
+ }
+}
diff --git a/src/plugins/projectexplorer/buildmanager.h b/src/plugins/projectexplorer/buildmanager.h
new file mode 100644
index 0000000000..b3754358e0
--- /dev/null
+++ b/src/plugins/projectexplorer/buildmanager.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDMANAGER_H
+#define BUILDMANAGER_H
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QFutureWatcher>
+#include <qtconcurrent/QtConcurrentTools>
+
+namespace ProjectExplorer {
+
+namespace Internal {
+ class CompileOutputWindow;
+ class TaskWindow;
+ class BuildProgressFuture;
+}
+
+class BuildStep;
+class Project;
+class ProjectExplorerPlugin;
+
+class PROJECTEXPLORER_EXPORT BuildManager
+ : public QObject
+{
+ Q_OBJECT
+
+ //NBS TODO this class has to many different variables which hold state:
+ // m_buildQueue, m_running, m_canceled, m_progress, m_maxProgress, m_activeBuildSteps and ...
+ // I might need to reduce that
+
+public:
+ BuildManager(ProjectExplorerPlugin *parent);
+ ~BuildManager();
+
+ bool isBuilding() const;
+
+ bool tasksAvailable() const;
+ //shows with focus
+ void gotoTaskWindow();
+
+ void buildProject(Project *p, const QString &configuration);
+ void buildProjects(const QList<Project *> &projects, const QList<QString> &configurations);
+ void cleanProject(Project *p, const QString &configuration);
+ void cleanProjects(const QList<Project *> &projects, const QList<QString> &configurations);
+ bool isBuilding(Project *p);
+
+ // Append any build step to the list of build steps (currently only used to add the QMakeStep)
+ void appendStep(BuildStep *step, const QString& configuration);
+
+public slots:
+ void cancel();
+ // Shows without focus
+ void showTaskWindow();
+ void toggleTaskWindow();
+ void toggleOutputWindow();
+
+signals:
+ void buildStateChanged(ProjectExplorer::Project *pro);
+ void buildQueueFinished(bool success);
+ void tasksChanged();
+
+private slots:
+ void addToTaskWindow(const QString &file, int type, int line, const QString &description);
+ void addToOutputWindow(const QString &string);
+
+ void nextBuildQueue();
+ void emitCancelMessage();
+ void showBuildResults();
+
+private:
+ void startBuildQueue();
+ void nextStep();
+ void clearBuildQueue();
+ void buildQueueAppend(BuildStep * bs, const QString &configuration);
+ void incrementActiveBuildSteps(Project *pro);
+ void decrementActiveBuildSteps(Project *pro);
+
+ Internal::CompileOutputWindow *m_outputWindow;
+ Internal::TaskWindow *m_taskWindow;
+
+ QList<BuildStep *> m_buildQueue;
+ QStringList m_configurations; // the corresponding configuration to the m_buildQueue
+ ProjectExplorerPlugin *m_projectExplorerPlugin;
+ bool m_running;
+ QFutureWatcher<bool> m_watcher;
+ BuildStep *m_currentBuildStep;
+ QString m_currentConfiguration;
+ // used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
+ QHash<Project *, int> m_activeBuildSteps;
+ Project *m_previousBuildStepProject;
+ // is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling
+ bool m_canceling;
+
+ // Progress reporting to the progress manager
+ int m_progress;
+ int m_maxProgress;
+ QFutureInterface<void> *m_progressFutureInterface;
+ QFutureWatcher<void> m_progressWatcher;
+};
+
+} // namespace ProjectExplorer
+
+#endif // BUILDMANAGER_H
diff --git a/src/plugins/projectexplorer/buildparserinterface.cpp b/src/plugins/projectexplorer/buildparserinterface.cpp
new file mode 100644
index 0000000000..5824fbbd60
--- /dev/null
+++ b/src/plugins/projectexplorer/buildparserinterface.cpp
@@ -0,0 +1,41 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildparserinterface.h"
+
+using namespace ProjectExplorer;
+
+IBuildParserFactory::~IBuildParserFactory()
+{
+}
+
+
diff --git a/src/plugins/projectexplorer/buildparserinterface.h b/src/plugins/projectexplorer/buildparserinterface.h
new file mode 100644
index 0000000000..e75ba2f2b4
--- /dev/null
+++ b/src/plugins/projectexplorer/buildparserinterface.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDPARSERINTERFACE_H
+#define BUILDPARSERINTERFACE_H
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QStack>
+
+namespace ProjectExplorer {
+
+class PROJECTEXPLORER_EXPORT BuildParserInterface : public QObject
+{
+ Q_OBJECT
+public:
+ enum PatternType { Unknown, Warning, Error };
+
+ virtual ~BuildParserInterface() {}
+ virtual QString name() const = 0;
+
+ virtual void stdOutput(const QString & line) = 0;
+ virtual void stdError(const QString & line) = 0;
+
+Q_SIGNALS:
+ void enterDirectory(const QString &dir);
+ void leaveDirectory(const QString &dir);
+ void addToOutputWindow(const QString & string);
+ void addToTaskWindow(const QString & filename, int type, int lineNumber, const QString & description);
+};
+
+class PROJECTEXPLORER_EXPORT IBuildParserFactory
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ IBuildParserFactory() {};
+ virtual ~IBuildParserFactory();
+ virtual bool canCreate(const QString & name) const = 0;
+ virtual BuildParserInterface * create(const QString & name) const = 0;
+};
+
+} // namespace ProjectExplorer
+
+#endif // BUILDPARSERINTERFACE_H
diff --git a/src/plugins/projectexplorer/buildprogress.cpp b/src/plugins/projectexplorer/buildprogress.cpp
new file mode 100644
index 0000000000..d8222903c0
--- /dev/null
+++ b/src/plugins/projectexplorer/buildprogress.cpp
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildprogress.h"
+
+#include <coreplugin/stylehelper.h>
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QFont>
+#include <QtGui/QPixmap>
+
+using namespace ProjectExplorer::Internal;
+
+BuildProgress::BuildProgress(TaskWindow *taskWindow)
+ : m_errorIcon(new QLabel),
+ m_warningIcon(new QLabel),
+ m_errorLabel(new QLabel),
+ m_warningLabel(new QLabel),
+ m_taskWindow(taskWindow)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ setLayout(layout);
+ QHBoxLayout *errorLayout = new QHBoxLayout;
+ errorLayout->setSpacing(4);
+ layout->addLayout(errorLayout);
+ errorLayout->addWidget(m_errorIcon);
+ errorLayout->addWidget(m_errorLabel);
+ QHBoxLayout *warningLayout = new QHBoxLayout;
+ warningLayout->setSpacing(4);
+ layout->addLayout(warningLayout);
+ warningLayout->addWidget(m_warningIcon);
+ warningLayout->addWidget(m_warningLabel);
+
+ // ### TODO this setup should be done by style
+ QFont f = this->font();
+ f.setPointSizeF(StyleHelper::sidebarFontSize());
+ f.setBold(true);
+ m_errorLabel->setFont(f);
+ m_warningLabel->setFont(f);
+ m_errorLabel->setPalette(StyleHelper::sidebarFontPalette(m_errorLabel->palette()));
+ m_warningLabel->setPalette(StyleHelper::sidebarFontPalette(m_warningLabel->palette()));
+
+ m_errorIcon->setAlignment(Qt::AlignRight);
+ m_warningIcon->setAlignment(Qt::AlignRight);
+ m_errorIcon->setPixmap(QPixmap(":/projectexplorer/images/compile_error.png"));
+ m_warningIcon->setPixmap(QPixmap(":/projectexplorer/images/compile_warning.png"));
+
+ connect(m_taskWindow, SIGNAL(tasksChanged()), this, SLOT(updateState()));
+ updateState();
+}
+
+void BuildProgress::updateState()
+{
+ if (!m_taskWindow)
+ return;
+ int errors = m_taskWindow->numberOfErrors();
+ bool haveErrors = (errors > 0);
+ m_errorIcon->setEnabled(haveErrors);
+ m_errorLabel->setEnabled(haveErrors);
+ m_errorLabel->setText(QString("%1").arg(errors));
+ int warnings = m_taskWindow->numberOfTasks()-errors;
+ bool haveWarnings = (warnings > 0);
+ m_warningIcon->setEnabled(haveWarnings);
+ m_warningLabel->setEnabled(haveWarnings);
+ m_warningLabel->setText(QString("%1").arg(warnings));
+}
diff --git a/src/plugins/projectexplorer/buildprogress.h b/src/plugins/projectexplorer/buildprogress.h
new file mode 100644
index 0000000000..1b93dd50fc
--- /dev/null
+++ b/src/plugins/projectexplorer/buildprogress.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDPROGRESS_H
+#define BUILDPROGRESS_H
+
+#include "taskwindow.h"
+
+#include <QtCore/QPointer>
+#include <QtGui/QWidget>
+#include <QtGui/QLabel>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class BuildProgress : public QWidget
+{
+ Q_OBJECT
+public:
+ BuildProgress(TaskWindow *taskWindow);
+
+private slots:
+ void updateState();
+
+private:
+ QLabel *m_errorIcon;
+ QLabel *m_warningIcon;
+ QLabel *m_errorLabel;
+ QLabel *m_warningLabel;
+ QPointer<TaskWindow> m_taskWindow;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // BUILDPROGRESS_H
diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp
new file mode 100644
index 0000000000..335dc78626
--- /dev/null
+++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp
@@ -0,0 +1,464 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildsettingspropertiespage.h"
+#include "buildstep.h"
+#include "buildstepspage.h"
+#include "project.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+#include <QtCore/QPair>
+#include <QtGui/QInputDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QMenu>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+///
+/// BuildSettingsPanelFactory
+///
+
+bool BuildSettingsPanelFactory::supports(Project * /* project */)
+{
+ return true;
+}
+
+PropertiesPanel *BuildSettingsPanelFactory::createPanel(Project *project)
+{
+ return new BuildSettingsPanel(project);
+}
+
+///
+/// BuildSettingsPanel
+///
+
+BuildSettingsPanel::BuildSettingsPanel(Project *project)
+ : PropertiesPanel(),
+ m_widget(new BuildSettingsWidget(project))
+{
+}
+
+BuildSettingsPanel::~BuildSettingsPanel()
+{
+ delete m_widget;
+}
+
+QString BuildSettingsPanel::name() const
+{
+ return tr("Build Settings");
+}
+
+QWidget *BuildSettingsPanel::widget()
+{
+ return m_widget;
+}
+
+///
+/// BuildSettingsWidget
+///
+
+BuildSettingsWidget::~BuildSettingsWidget()
+{
+}
+
+BuildSettingsWidget::BuildSettingsWidget(Project *project)
+ : m_project(project)
+{
+ m_ui.setupUi(this);
+ m_ui.splitter->setStretchFactor(1,10);
+ m_ui.buildSettingsList->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ m_ui.addButton->setIcon(QIcon(":/qworkbench/images/plus.png"));
+ m_ui.addButton->setText("");
+ m_ui.removeButton->setIcon(QIcon(":/qworkbench/images/minus.png"));
+ m_ui.removeButton->setText("");
+
+ QMenu *addButtonMenu = new QMenu(this);
+ addButtonMenu->addAction(tr("Create &New"),
+ this, SLOT(createConfiguration()));
+ addButtonMenu->addAction(tr("&Clone Selected"),
+ this, SLOT(cloneConfiguration()));
+ m_ui.addButton->setMenu(addButtonMenu);
+
+
+ connect(m_ui.buildSettingsList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(updateSettingsWidget(QTreeWidgetItem *, QTreeWidgetItem *)));
+ connect(m_ui.buildSettingsList, SIGNAL(customContextMenuRequested (const QPoint &) ),
+ this, SLOT(showContextMenu(const QPoint &)));
+ connect(m_ui.buildSettingsList, SIGNAL(itemChanged(QTreeWidgetItem*,int) ),
+ this, SLOT(itemChanged(QTreeWidgetItem*)), Qt::QueuedConnection);
+
+ connect(m_ui.removeButton, SIGNAL(clicked()),
+ this, SLOT(deleteConfiguration()));
+ connect(m_project, SIGNAL(activeBuildConfigurationChanged()),
+ this, SLOT(updateBuildSettings()));
+ connect(m_project, SIGNAL(buildConfigurationDisplayNameChanged(const QString &)),
+ this, SLOT(buildConfigurationDisplayNameChanged(const QString &)));
+
+
+ // remove dummy designer widget
+ while (QWidget *widget = m_ui.buildSettingsWidgets->currentWidget()) {
+ m_ui.buildSettingsWidgets->removeWidget(widget);
+ delete widget;
+ }
+
+ updateBuildSettings();
+}
+
+void BuildSettingsWidget::buildConfigurationDisplayNameChanged(const QString &buildConfiguration)
+{
+ QTreeWidgetItem *rootItem = m_ui.buildSettingsList->invisibleRootItem();
+ for(int i = 0; i < rootItem->childCount(); ++i) {
+ QTreeWidgetItem *child = rootItem->child(i);
+ if (child->data(0, Qt::UserRole).toString() == buildConfiguration) {
+ child->setText(0, m_project->displayNameFor(buildConfiguration));
+ if (m_ui.buildSettingsList->currentItem() == child) {
+ QWidget *widget = m_itemToWidget.value(child);
+ if (BuildStepConfigWidget *buildStepWidget = qobject_cast<BuildStepConfigWidget*>(widget)) {
+ QString title;
+ title = buildStepWidget->displayName();
+ m_ui.titleLabel->setText(tr("%1 - %2").arg(m_project->displayNameFor(buildConfiguration)).arg(title));
+ }
+ }
+ }
+ }
+}
+
+
+void BuildSettingsWidget::updateBuildSettings()
+{
+ QTreeWidgetItem *rootItem = m_ui.buildSettingsList->invisibleRootItem();
+
+ // update buttons
+ m_ui.removeButton->setEnabled(m_project->buildConfigurations().size() > 1);
+
+ // Save current selection
+ QString lastCurrentItem;
+ if (m_ui.buildSettingsList->currentItem())
+ lastCurrentItem = m_ui.buildSettingsList->currentItem()->text(0);
+
+ m_itemToWidget.clear();
+
+ // Delete old tree items
+ while (rootItem->childCount()) {
+ QTreeWidgetItem *configPageItem = rootItem->child(0);
+ rootItem->removeChild(configPageItem);
+ delete configPageItem; // does that delete also subitems?
+ }
+
+ // Delete old pages
+ while (m_ui.buildSettingsWidgets->count()) {
+ QWidget *w = m_ui.buildSettingsWidgets->widget(0);
+ m_ui.buildSettingsWidgets->removeWidget(w);
+ delete w;
+ }
+
+ // Add pages
+ QWidget *dummyWidget = new QWidget(this);
+ QWidget *buildStepsWidget = new BuildStepsPage(m_project);
+ BuildStepConfigWidget *generalConfigWidget = m_project->createConfigWidget();
+ QList<BuildStepConfigWidget *> subConfigWidgets = m_project->subConfigWidgets();
+
+ m_ui.buildSettingsWidgets->addWidget(dummyWidget);
+ m_ui.buildSettingsWidgets->addWidget(buildStepsWidget);
+ m_ui.buildSettingsWidgets->addWidget(generalConfigWidget);
+ foreach (BuildStepConfigWidget *subConfigWidget, subConfigWidgets)
+ m_ui.buildSettingsWidgets->addWidget(subConfigWidget);
+
+ // Add tree items
+ QTreeWidgetItem *activeConfigurationItem = 0;
+ QString activeBuildConfiguration = m_project->activeBuildConfiguration();
+ foreach (const QString &buildConfiguration, m_project->buildConfigurations()) {
+ QString displayName = m_project->displayNameFor(buildConfiguration);
+ QTreeWidgetItem *buildConfigItem = new QTreeWidgetItem();
+ m_itemToWidget.insert(buildConfigItem, generalConfigWidget);
+ buildConfigItem->setText(0, displayName);
+ buildConfigItem->setData(0, Qt::UserRole, buildConfiguration);
+ buildConfigItem->setCheckState(0, Qt::Unchecked);
+ if (activeBuildConfiguration == buildConfiguration) {
+ QFont font = buildConfigItem->font(0);
+ font.setBold(true);
+ buildConfigItem->setFont(0, font);
+ buildConfigItem->setCheckState(0, Qt::Checked);
+
+ activeConfigurationItem = buildConfigItem;
+ }
+ rootItem->addChild(buildConfigItem);
+
+ QTreeWidgetItem *generalItem = new QTreeWidgetItem();
+ m_itemToWidget.insert(generalItem, generalConfigWidget);
+ generalItem->setText(0, tr("General"));
+ buildConfigItem->addChild(generalItem);
+
+ foreach (BuildStepConfigWidget *subConfigWidget, subConfigWidgets) {
+ QTreeWidgetItem *subConfigItem = new QTreeWidgetItem();
+ m_itemToWidget.insert(subConfigItem, subConfigWidget);
+ subConfigItem->setText(0, subConfigWidget->displayName());
+ buildConfigItem->addChild(subConfigItem);
+ }
+
+ QTreeWidgetItem *buildStepsItem = new QTreeWidgetItem();
+ m_itemToWidget.insert(buildStepsItem, buildStepsWidget);
+ buildStepsItem->setText(0, tr("Build Steps"));
+ buildConfigItem->addChild(buildStepsItem);
+ }
+
+ m_ui.buildSettingsList->expandAll();
+
+ // Restore selection
+ if (!lastCurrentItem.isEmpty()) {
+ for (int i = rootItem->childCount() - 1; i >= 0; --i) {
+ if (rootItem->child(i)->text(0) == lastCurrentItem) {
+ m_ui.buildSettingsList->setCurrentItem(rootItem->child(i));
+ break;
+ }
+ }
+ }
+
+ if (!m_ui.buildSettingsList->currentItem()) {
+ if (activeConfigurationItem)
+ m_ui.buildSettingsList->setCurrentItem(activeConfigurationItem);
+ else
+ m_ui.buildSettingsList->setCurrentItem(m_ui.buildSettingsList->invisibleRootItem()->child(0));
+ }
+}
+
+/* switch from one tree item / build step to another */
+void BuildSettingsWidget::updateSettingsWidget(QTreeWidgetItem *newItem, QTreeWidgetItem *oldItem)
+{
+ if (oldItem == newItem)
+ return;
+
+ if (!newItem) {
+ QWidget *dummyWidget = m_ui.buildSettingsWidgets->widget(0);
+ m_ui.buildSettingsWidgets->setCurrentWidget(dummyWidget);
+ m_ui.titleLabel->clear();
+ return;
+ }
+
+ if (QWidget *widget = m_itemToWidget.value(newItem)) {
+ QString buildConfiguration;
+ {
+ QTreeWidgetItem *configurationItem = newItem;
+ while (configurationItem && configurationItem->parent())
+ configurationItem = configurationItem->parent();
+ if (configurationItem)
+ buildConfiguration = configurationItem->data(0, Qt::UserRole).toString();
+ }
+
+ QString title;
+ if (BuildStepConfigWidget *buildStepWidget = qobject_cast<BuildStepConfigWidget*>(widget)) {
+ title = buildStepWidget->displayName();
+ buildStepWidget->init(buildConfiguration);
+ }
+
+ m_ui.titleLabel->setText(tr("%1 - %2").arg(m_project->displayNameFor(buildConfiguration)).arg(title));
+ m_ui.buildSettingsWidgets->setCurrentWidget(widget);
+ }
+}
+
+
+void BuildSettingsWidget::showContextMenu(const QPoint &point)
+{
+ if (QTreeWidgetItem *item = m_ui.buildSettingsList->itemAt(point)) {
+ if (!item->parent()) {
+ const QString buildConfiguration = item->data(0, Qt::UserRole).toString();
+
+ QMenu menu;
+ QAction *setAsActiveAction = new QAction(tr("Set as Active"), &menu);
+ QAction *cloneAction = new QAction(tr("Clone"), &menu);
+ QAction *deleteAction = new QAction(tr("Delete"), &menu);
+
+ if (m_project->activeBuildConfiguration() == buildConfiguration)
+ setAsActiveAction->setEnabled(false);
+ if (m_project->buildConfigurations().size() < 2)
+ deleteAction->setEnabled(false);
+
+ menu.addActions(QList<QAction*>() << setAsActiveAction << cloneAction << deleteAction);
+ QPoint globalPoint = m_ui.buildSettingsList->mapToGlobal(point);
+ QAction *action = menu.exec(globalPoint);
+ if (action == setAsActiveAction) {
+ setActiveConfiguration(buildConfiguration);
+ } else if (action == cloneAction) {
+ cloneConfiguration(buildConfiguration);
+ } else if (action == deleteAction) {
+ deleteConfiguration(buildConfiguration);
+ }
+
+ updateBuildSettings();
+ }
+ }
+}
+
+void BuildSettingsWidget::setActiveConfiguration()
+{
+ const QString configuration = m_ui.buildSettingsList->currentItem()->data(0, Qt::UserRole).toString();
+ setActiveConfiguration(configuration);
+}
+
+void BuildSettingsWidget::createConfiguration()
+{
+ bool ok;
+ QString newBuildConfiguration = QInputDialog::getText(this, tr("New configuration"), tr("New Configuration Name:"), QLineEdit::Normal, QString(), &ok);
+ if(!ok || newBuildConfiguration.isEmpty())
+ return;
+
+ QString newDisplayName = newBuildConfiguration;
+ // Check that the internal name is not taken and use a different one otherwise
+ const QStringList &buildConfigurations = m_project->buildConfigurations();
+ if (buildConfigurations.contains(newBuildConfiguration)) {
+ int i = 2;
+ while(buildConfigurations.contains(newBuildConfiguration + QString::number(i))) {
+ ++i;
+ }
+ newBuildConfiguration += QString::number(i);
+ }
+
+ // Check that we don't have a configuration with the same displayName
+ QStringList displayNames;
+ foreach(const QString &bc, buildConfigurations)
+ displayNames << m_project->displayNameFor(bc);
+
+ if (displayNames.contains(newDisplayName)) {
+ int i = 2;
+ while(displayNames.contains(newDisplayName + QString::number(i))) {
+ ++i;
+ }
+ newDisplayName += QString::number(i);
+ }
+
+ m_project->addBuildConfiguration(newBuildConfiguration);
+ m_project->setDisplayNameFor(newBuildConfiguration, newDisplayName);
+ m_project->newBuildConfiguration(newBuildConfiguration);
+ m_project->setActiveBuildConfiguration(newBuildConfiguration);
+
+ updateBuildSettings();
+}
+
+void BuildSettingsWidget::cloneConfiguration()
+{
+ QTreeWidgetItem *configItem = m_ui.buildSettingsList->currentItem();
+ while (configItem->parent())
+ configItem = configItem->parent();
+ const QString configuration = configItem->data(0, Qt::UserRole).toString();
+ cloneConfiguration(configuration);
+}
+
+void BuildSettingsWidget::deleteConfiguration()
+{
+ QTreeWidgetItem *configItem = m_ui.buildSettingsList->currentItem();
+ while (configItem->parent())
+ configItem = configItem->parent();
+ const QString configuration = configItem->data(0, Qt::UserRole).toString();
+ deleteConfiguration(configuration);
+}
+
+void BuildSettingsWidget::itemChanged(QTreeWidgetItem *item)
+{
+ // do not allow unchecking
+ if (item->checkState(0) == Qt::Unchecked)
+ item->setCheckState(0, Qt::Checked);
+ else {
+ setActiveConfiguration(item->data(0, Qt::UserRole).toString());
+ }
+}
+
+void BuildSettingsWidget::setActiveConfiguration(const QString &configuration)
+{
+ if (configuration.isEmpty())
+ return;
+
+ m_project->setActiveBuildConfiguration(configuration);
+}
+
+void BuildSettingsWidget::cloneConfiguration(const QString &sourceConfiguration)
+{
+ if(sourceConfiguration.isEmpty())
+ return;
+
+ QString newBuildConfiguration = QInputDialog::getText(this, tr("Clone configuration"), tr("New Configuration Name:"));
+ if(newBuildConfiguration.isEmpty())
+ return;
+
+ QString newDisplayName = newBuildConfiguration;
+ // Check that the internal name is not taken and use a different one otherwise
+ const QStringList &buildConfigurations = m_project->buildConfigurations();
+ if (buildConfigurations.contains(newBuildConfiguration)) {
+ int i = 2;
+ while(buildConfigurations.contains(newBuildConfiguration + QString::number(i))) {
+ ++i;
+ }
+ newBuildConfiguration += QString::number(i);
+ }
+
+ // Check that we don't have a configuration with the same displayName
+ QStringList displayNames;
+ foreach(const QString &bc, buildConfigurations)
+ displayNames << m_project->displayNameFor(bc);
+
+ if (displayNames.contains(newDisplayName)) {
+ int i = 2;
+ while(displayNames.contains(newDisplayName + QString::number(i))) {
+ ++i;
+ }
+ newDisplayName += QString::number(i);
+ }
+
+ m_project->copyBuildConfiguration(sourceConfiguration, newBuildConfiguration);
+ m_project->setDisplayNameFor(newBuildConfiguration, newDisplayName);
+ m_project->setActiveBuildConfiguration(newBuildConfiguration);
+
+ updateBuildSettings();
+}
+
+void BuildSettingsWidget::deleteConfiguration(const QString &deleteConfiguration)
+{
+ if (deleteConfiguration.isEmpty() || m_project->buildConfigurations().size() <= 1)
+ return;
+
+ if (m_project->activeBuildConfiguration() == deleteConfiguration) {
+ foreach (const QString &otherConfiguration, m_project->buildConfigurations()) {
+ if (otherConfiguration != deleteConfiguration) {
+ m_project->setActiveBuildConfiguration(otherConfiguration);
+ break;
+ }
+ }
+ }
+
+ m_project->removeBuildConfiguration(deleteConfiguration);
+
+ updateBuildSettings();
+}
diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.h b/src/plugins/projectexplorer/buildsettingspropertiespage.h
new file mode 100644
index 0000000000..012ff67c21
--- /dev/null
+++ b/src/plugins/projectexplorer/buildsettingspropertiespage.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDSETTINGSPROPERTIESPAGE_H
+#define BUILDSETTINGSPROPERTIESPAGE_H
+
+#include "iprojectproperties.h"
+#include "ui_buildsettingspropertiespage.h"
+
+namespace ProjectExplorer {
+
+class IBuildStepFactory;
+
+namespace Internal {
+
+class BuildSettingsPanelFactory : public IPanelFactory
+{
+public:
+ bool supports(Project *project);
+ PropertiesPanel *createPanel(Project *project);
+};
+
+class BuildSettingsWidget;
+
+class BuildSettingsPanel : public PropertiesPanel
+{
+ Q_OBJECT
+public:
+ BuildSettingsPanel(Project *project);
+ ~BuildSettingsPanel();
+ QString name() const;
+ QWidget *widget();
+
+private:
+ BuildSettingsWidget *m_widget;
+};
+
+class BuildConfigurationsWidget;
+
+class BuildSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ BuildSettingsWidget(Project *project);
+ ~BuildSettingsWidget();
+
+private slots:
+ void buildConfigurationDisplayNameChanged(const QString &buildConfiguration);
+ void updateBuildSettings();
+ void updateSettingsWidget(QTreeWidgetItem *newItem, QTreeWidgetItem *oldItem);
+ void showContextMenu(const QPoint & pos);
+
+ void setActiveConfiguration();
+ void createConfiguration();
+ void cloneConfiguration();
+ void deleteConfiguration();
+
+ void itemChanged(QTreeWidgetItem *item);
+
+private:
+ void setActiveConfiguration(const QString &configuration);
+ void cloneConfiguration(const QString &toClone);
+ void deleteConfiguration(const QString &toDelete);
+
+ Ui::BuildSettingsPropertiesPage m_ui;
+ Project *m_project;
+ QHash<QTreeWidgetItem*, QWidget*> m_itemToWidget;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // BUILDSETTINGSPROPERTIESPAGE_H
diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.ui b/src/plugins/projectexplorer/buildsettingspropertiespage.ui
new file mode 100644
index 0000000000..819f17da58
--- /dev/null
+++ b/src/plugins/projectexplorer/buildsettingspropertiespage.ui
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::BuildSettingsPropertiesPage</class>
+ <widget class="QWidget" name="ProjectExplorer::Internal::BuildSettingsPropertiesPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>799</width>
+ <height>525</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QWidget" name="layoutWidget1">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="100,1,0">
+ <item>
+ <widget class="QTreeWidget" name="buildSettingsList">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>800</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="headerHidden">
+ <bool>true</bool>
+ </property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Configurations</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="text">
+ <string>+</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="text">
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="layoutWidget2">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
+ <item>
+ <widget class="QLabel" name="titleLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>16</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="buildSettingsWidgets">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="page_2"/>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../libs/cplusplus/cplusplus.qrc"/>
+ <include location="../../libs/extensionsystem/pluginview.qrc"/>
+ <include location="../bookmarks/bookmarks.qrc"/>
+ <include location="../coreplugin/core.qrc"/>
+ <include location="../coreplugin/fancyactionbar.qrc"/>
+ <include location="../cppeditor/cppeditor.qrc"/>
+ <include location="../cpptools/cpptools.qrc"/>
+ <include location="../designer/designer.qrc"/>
+ <include location="../find/find.qrc"/>
+ <include location="../gdbdebugger/gdbdebugger.qrc"/>
+ <include location="../help/help.qrc"/>
+ <include location="../perforce/perforce.qrc"/>
+ <include location="projectexplorer.qrc"/>
+ <include location="../../../shared/proparser/proparser.qrc"/>
+ <include location="../qt4projectmanager/qt4projectmanager.qrc"/>
+ <include location="../qt4projectmanager/wizards/wizards.qrc"/>
+ <include location="../quickopen/quickopen.qrc"/>
+ <include location="../resourceeditor/resourceeditor.qrc"/>
+ <include location="../texteditor/texteditor.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp
new file mode 100644
index 0000000000..76ab3f65f4
--- /dev/null
+++ b/src/plugins/projectexplorer/buildstep.cpp
@@ -0,0 +1,146 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildstep.h"
+#include "buildconfiguration.h"
+
+namespace ProjectExplorer {
+
+BuildStep::BuildStep(Project * pro)
+ : m_project(pro)
+{
+ m_configuration = new BuildConfiguration("");
+}
+
+BuildStep::~BuildStep()
+{
+ qDeleteAll(m_buildConfigurations);
+ delete m_configuration;
+}
+
+Project * BuildStep::project() const
+{
+ return m_project;
+}
+
+void BuildStep::addBuildConfiguration(const QString &name)
+{
+ m_buildConfigurations.push_back(new BuildConfiguration(name));
+}
+
+void BuildStep::removeBuildConfiguration(const QString &name)
+{
+ for(int i = 0; i != m_buildConfigurations.size(); ++i)
+ if(m_buildConfigurations.at(i)->name() == name) {
+ delete m_buildConfigurations.at(i);
+ m_buildConfigurations.removeAt(i);
+ break;
+ }
+}
+
+void BuildStep::copyBuildConfiguration(const QString &source, const QString &dest)
+{
+ for(int i = 0; i != m_buildConfigurations.size(); ++i)
+ if(m_buildConfigurations.at(i)->name() == source)
+ m_buildConfigurations.push_back(new BuildConfiguration(dest, m_buildConfigurations.at(i)));
+}
+
+void BuildStep::setValue(const QString &buildConfiguration, const QString &name, const QVariant &value)
+{
+ BuildConfiguration *bc = getBuildConfiguration(buildConfiguration);
+ Q_ASSERT(bc);
+ bc->setValue(name, value);
+}
+
+void BuildStep::setValue(const QString &name, const QVariant &value)
+{
+ m_configuration->setValue(name, value);
+}
+
+QVariant BuildStep::value(const QString &buildConfiguration, const QString &name) const
+{
+ BuildConfiguration *bc = getBuildConfiguration(buildConfiguration);
+ if (bc)
+ return bc->getValue(name);
+ else
+ return QVariant();
+}
+
+QVariant BuildStep::value(const QString &name) const
+{
+ return m_configuration->getValue(name);
+}
+
+void BuildStep::setValuesFromMap(const QMap<QString, QVariant> & values)
+{
+ m_configuration->setValuesFromMap(values);
+}
+
+void BuildStep::setValuesFromMap(const QString & buildConfiguration, const QMap<QString, QVariant> & values)
+{
+ getBuildConfiguration(buildConfiguration)->setValuesFromMap(values);
+}
+
+QMap<QString, QVariant> BuildStep::valuesToMap()
+{
+ return m_configuration->toMap();
+}
+
+QMap<QString, QVariant> BuildStep::valuesToMap(const QString & buildConfiguration)
+{
+ return getBuildConfiguration(buildConfiguration)->toMap();
+}
+
+BuildConfiguration * BuildStep::getBuildConfiguration(const QString & name) const
+{
+ for (int i = 0; i != m_buildConfigurations.size(); ++i)
+ if (m_buildConfigurations.at(i)->name() == name)
+ return m_buildConfigurations.at(i);
+ return 0;
+}
+
+bool BuildStep::immutable() const
+{
+ return false;
+}
+
+IBuildStepFactory::IBuildStepFactory()
+{
+
+}
+
+IBuildStepFactory::~IBuildStepFactory()
+{
+
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h
new file mode 100644
index 0000000000..32f37fff8c
--- /dev/null
+++ b/src/plugins/projectexplorer/buildstep.h
@@ -0,0 +1,181 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDSTEP_H
+#define BUILDSTEP_H
+
+#include "buildparserinterface.h"
+#include "project.h"
+#include "projectexplorer_export.h"
+
+#include <QtGui/QWidget>
+#include <QtCore/QFutureInterface>
+
+namespace ProjectExplorer {
+
+class BuildConfiguration;
+
+/*
+// BuildSteps are the primary way plugin developers can customize
+// how their projects (or projects from other plugins) are build.
+//
+// Building a project, is done by taking the list of buildsteps
+// from the project and calling first init() than run() on them.
+//
+// That means to change the way your project is build, reimplemnt
+// this class and add your Step to the buildStep list of the project.
+//
+// Note: The projects own the buildstep, do not delete them yourself.
+//
+// init() is called in the GUI thread and can be used to query the
+// project for any information you need.
+//
+// run() is run via QtConccurrent in a own thread, if you need an
+// eventloop you need to create it yourself!
+//
+// You can use setValue() to store settings which a specific
+// to your buildstep. (You can set settings to apply only
+// to one buildconfiguration.
+// And later retrieve the same information with value()
+
+*/
+
+class BuildStepConfigWidget;
+
+class PROJECTEXPLORER_EXPORT BuildStep : public QObject
+{
+ Q_OBJECT
+ friend class Project; //for managing BuildConfigurations
+public:
+ BuildStep(Project *p);
+ virtual ~BuildStep();
+
+ // This function is run in the gui thread,
+ // use it to retrieve any information that you need in run()
+ virtual bool init(const QString &buildConfiguration) = 0;
+
+ // Reimplement this. This function is called when the project is build.
+ // This function is NOT run in the gui thread. It runs in its own thread
+ // If you need an event loop, you need to create one.
+ // The absolute minimal implementation is:
+ // fi.reportResult(true);
+ virtual void run(QFutureInterface<bool> &fi) = 0;
+
+ // The internal name
+ virtual QString name() = 0;
+ // The name shown to the user
+ virtual QString displayName() = 0;
+
+ // sets a value, which can be retrieved with value()
+ // these values are automatically saved and restored when qt creator is quit and restarted
+ void setValue(const QString &name, const QVariant &value);
+ // sets a value specific to a buildConfiguration
+ void setValue(const QString &buildConfiguration, const QString &name, const QVariant &value);
+
+ // retrieves a value
+ QVariant value(const QString &name) const;
+ // retrieves a value specific to a buildConfiguration
+ QVariant value(const QString &buildConfiguration, const QString & name) const;
+
+ // the Widget shown in the project settings dialog for this buildStep
+ // ownership is transfered to the caller
+ virtual BuildStepConfigWidget *createConfigWidget() = 0;
+
+ // if this function returns true, the user can't delete this BuildStep for this project
+ // and the user is prevented from changing the order immutable steps are run
+ // the default implementation returns false
+ virtual bool immutable() const;
+
+ Project *project() const;
+
+protected:
+ // internal function for restoring the configuration
+ void setValuesFromMap(const QMap<QString, QVariant> &values);
+ // internal function for restoring the configuration
+ void setValuesFromMap(const QString &buildConfiguration, const QMap<QString, QVariant> &values);
+
+ // internal function for storing the configuration
+ QMap<QString, QVariant> valuesToMap();
+ // internal function for storing the configuration
+ QMap<QString, QVariant> valuesToMap(const QString & buildConfiguration);
+
+Q_SIGNALS:
+ void addToTaskWindow(const QString &filename, int type, int linenumber, const QString &description);
+ void addToOutputWindow(const QString &string);
+
+ void displayNameChanged(BuildStep *, const QString &displayName);
+
+private:
+ QList<BuildConfiguration *> buildConfigurations();
+ void addBuildConfiguration(const QString & name);
+ void removeBuildConfiguration(const QString & name);
+ BuildConfiguration *getBuildConfiguration(const QString & name) const;
+ void copyBuildConfiguration(const QString &source, const QString &dest);
+
+ QList<BuildConfiguration *> m_buildConfigurations;
+ BuildConfiguration *m_configuration;
+ Project *m_project;
+};
+
+class PROJECTEXPLORER_EXPORT IBuildStepFactory
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ IBuildStepFactory();
+ virtual ~IBuildStepFactory();
+ virtual bool canCreate(const QString &name) const = 0;
+ virtual BuildStep *create(Project *pro, const QString &name) const = 0;
+ virtual QStringList canCreateForProject(Project *pro) const = 0;
+ virtual QString displayNameForName(const QString &name) const = 0;
+};
+
+class PROJECTEXPLORER_EXPORT BuildStepConfigWidget
+ : public QWidget
+{
+ Q_OBJECT
+public:
+ BuildStepConfigWidget()
+ :QWidget(0)
+ {}
+
+ virtual QString displayName() const = 0;
+
+ // This is called to set up the config widget before showing it
+ // buildConfiguration is QString::null for the non buildConfiguration specific page
+ virtual void init(const QString &buildConfiguration) = 0;
+};
+
+} // namespace ProjectExplorer
+
+#endif // BUILDSTEP_H
diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp
new file mode 100644
index 0000000000..3777281dcc
--- /dev/null
+++ b/src/plugins/projectexplorer/buildstepspage.cpp
@@ -0,0 +1,266 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildstepspage.h"
+#include "ui_buildstepspage.h"
+#include "project.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+BuildStepsPage::BuildStepsPage(Project *project) :
+ BuildStepConfigWidget(),
+ m_ui(new Ui::BuildStepsPage),
+ m_pro(project)
+{
+ m_ui->setupUi(this);
+
+ m_ui->buildStepAddButton->setMenu(new QMenu(this));
+ m_ui->buildStepAddButton->setIcon(QIcon(":/qworkbench/images/plus.png"));
+ m_ui->buildStepRemoveToolButton->setIcon(QIcon(":/qworkbench/images/minus.png"));
+ m_ui->buildStepUpToolButton->setArrowType(Qt::UpArrow);
+ m_ui->buildStepDownToolButton->setArrowType(Qt::DownArrow);
+
+ connect(m_ui->buildSettingsList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(updateBuildStepWidget(QTreeWidgetItem *, QTreeWidgetItem *)));
+
+ connect(m_ui->buildStepAddButton->menu(), SIGNAL(aboutToShow()),
+ this, SLOT(updateAddBuildStepMenu()));
+
+ connect(m_ui->buildStepAddButton, SIGNAL(clicked()),
+ this, SLOT(addBuildStep()));
+ connect(m_ui->buildStepRemoveToolButton, SIGNAL(clicked()),
+ this, SLOT(removeBuildStep()));
+ connect(m_ui->buildStepUpToolButton, SIGNAL(clicked()),
+ this, SLOT(upBuildStep()));
+ connect(m_ui->buildStepDownToolButton, SIGNAL(clicked()),
+ this, SLOT(downBuildStep()));
+
+ // Remove dummy pages
+ while (QWidget *widget = m_ui->buildSettingsWidget->currentWidget()) {
+ m_ui->buildSettingsWidget->removeWidget(widget);
+ delete widget;
+ }
+
+ // Add buildsteps
+ foreach (BuildStep *bs, m_pro->buildSteps()) {
+
+ connect(bs, SIGNAL(displayNameChanged(BuildStep *, QString)),
+ this, SLOT(displayNameChanged(BuildStep *,QString)));
+
+ QTreeWidgetItem *buildStepItem = new QTreeWidgetItem();
+ buildStepItem->setText(0, bs->displayName());
+ m_ui->buildSettingsWidget->addWidget(bs->createConfigWidget());
+ m_ui->buildSettingsList->invisibleRootItem()->addChild(buildStepItem);
+ }
+}
+
+BuildStepsPage::~BuildStepsPage()
+{
+ // Also deletes all added widgets
+ delete m_ui;
+}
+
+void BuildStepsPage::displayNameChanged(BuildStep *bs, const QString &displayName)
+{
+ int index = m_pro->buildSteps().indexOf(bs);
+ m_ui->buildSettingsList->invisibleRootItem()->child(index)->setText(0, bs->displayName());
+}
+
+QString BuildStepsPage::displayName() const
+{
+ return tr("Build Steps");
+}
+
+void BuildStepsPage::init(const QString &buildConfiguration)
+{
+ m_configuration = buildConfiguration;
+
+ m_ui->buildSettingsList->setCurrentItem(m_ui->buildSettingsList->invisibleRootItem()->child(0));
+ // make sure widget is updated
+ BuildStepConfigWidget *widget = qobject_cast<BuildStepConfigWidget *>(m_ui->buildSettingsWidget->currentWidget());
+ widget->init(m_configuration);
+}
+
+/* switch from one tree item / build step to another */
+void BuildStepsPage::updateBuildStepWidget(QTreeWidgetItem *newItem, QTreeWidgetItem *oldItem)
+{
+ if(oldItem == newItem)
+ return;
+ Q_ASSERT(m_pro);
+
+ if(newItem) {
+ int row = m_ui->buildSettingsList->indexOfTopLevelItem(newItem);
+ m_ui->buildSettingsWidget->setCurrentIndex(row);
+ BuildStepConfigWidget *widget = qobject_cast<BuildStepConfigWidget *>(m_ui->buildSettingsWidget->currentWidget());
+ Q_ASSERT(widget);
+ if (widget)
+ widget->init(m_configuration);
+ }
+ updateBuildStepButtonsState();
+}
+
+
+void BuildStepsPage::updateAddBuildStepMenu()
+{
+ QMap<QString, QPair<QString, IBuildStepFactory *> > map;
+ //Build up a list of possible steps and save map the display names to the (internal) name and factories.
+ QList<IBuildStepFactory *> factories = ExtensionSystem::PluginManager::instance()->getObjects<IBuildStepFactory>();
+ foreach (IBuildStepFactory * factory, factories) {
+ QStringList names = factory->canCreateForProject(m_pro);
+ foreach (const QString &name, names) {
+ map.insert(factory->displayNameForName(name), QPair<QString, IBuildStepFactory *>(name, factory));
+ }
+ }
+
+ // Ask the user which one to add
+ QMenu *menu = m_ui->buildStepAddButton->menu();
+ m_addBuildStepHash.clear();
+ menu->clear();
+ if(!map.isEmpty()) {
+ QStringList names;
+ QMap<QString, QPair<QString, IBuildStepFactory *> >::const_iterator it, end;
+ end = map.constEnd();
+ for(it = map.constBegin(); it != end; ++it) {
+ QAction *action = menu->addAction(it.key());
+ connect(action, SIGNAL(triggered()),
+ this, SLOT(addBuildStep()));
+ m_addBuildStepHash.insert(action, it.value());
+ }
+ }
+}
+
+
+void BuildStepsPage::addBuildStep()
+{
+ if(QAction *action = qobject_cast<QAction *>(sender())) {
+ QPair<QString, IBuildStepFactory *> pair = m_addBuildStepHash.value(action);
+ BuildStep *newStep = pair.second->create(m_pro, pair.first);
+ m_pro->insertBuildStep(0, newStep);
+ QTreeWidgetItem *buildStepItem = new QTreeWidgetItem();
+ buildStepItem->setText(0, newStep->displayName());
+ m_ui->buildSettingsList->invisibleRootItem()->insertChild(0, buildStepItem);
+ m_ui->buildSettingsWidget->insertWidget(0, newStep->createConfigWidget());
+ m_ui->buildSettingsList->setCurrentItem(buildStepItem);
+ }
+}
+
+void BuildStepsPage::removeBuildStep()
+{
+ int pos = m_ui->buildSettingsList->currentIndex().row();
+ if(m_pro->buildSteps().at(pos)->immutable())
+ return;
+ bool blockSignals = m_ui->buildSettingsList->blockSignals(true);
+ delete m_ui->buildSettingsList->invisibleRootItem()->takeChild(pos);
+ m_ui->buildSettingsList->blockSignals(blockSignals);
+ QWidget *widget = m_ui->buildSettingsWidget->widget(pos);
+ m_ui->buildSettingsWidget->removeWidget(widget);
+ delete widget;
+ if(pos < m_ui->buildSettingsList->invisibleRootItem()->childCount())
+ m_ui->buildSettingsList->setCurrentItem(m_ui->buildSettingsList->invisibleRootItem()->child(pos));
+ else
+ m_ui->buildSettingsList->setCurrentItem(m_ui->buildSettingsList->invisibleRootItem()->child(pos - 1));
+ m_pro->removeBuildStep(pos);
+ updateBuildStepButtonsState();
+}
+
+void BuildStepsPage::upBuildStep()
+{
+ int pos = m_ui->buildSettingsList->currentIndex().row();
+ if(pos < 1)
+ return;
+ if(pos > m_ui->buildSettingsList->invisibleRootItem()->childCount()-1)
+ return;
+ if(m_pro->buildSteps().at(pos)->immutable() && m_pro->buildSteps().at(pos-1)->immutable())
+ return;
+
+ bool blockSignals = m_ui->buildSettingsList->blockSignals(true);
+ m_pro->moveBuildStepUp(pos);
+ buildStepMoveUp(pos);
+ QTreeWidgetItem *item = m_ui->buildSettingsList->invisibleRootItem()->child(pos - 1);
+ m_ui->buildSettingsList->blockSignals(blockSignals);
+ m_ui->buildSettingsList->setCurrentItem(item);
+ updateBuildStepButtonsState();
+}
+
+void BuildStepsPage::downBuildStep()
+{
+ int pos = m_ui->buildSettingsList->currentIndex().row() + 1;
+ if(pos < 1)
+ return;
+ if(pos > m_ui->buildSettingsList->invisibleRootItem()->childCount() - 1)
+ return;
+ if(m_pro->buildSteps().at(pos)->immutable() && m_pro->buildSteps().at(pos - 1)->immutable())
+ return;
+
+ bool blockSignals = m_ui->buildSettingsList->blockSignals(true);
+ m_pro->moveBuildStepUp(pos);
+ buildStepMoveUp(pos);
+ QTreeWidgetItem *item = m_ui->buildSettingsList->invisibleRootItem()->child(pos);
+ m_ui->buildSettingsList->blockSignals(blockSignals);
+ m_ui->buildSettingsList->setCurrentItem(item);
+ updateBuildStepButtonsState();
+}
+
+void BuildStepsPage::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void BuildStepsPage::buildStepMoveUp(int pos)
+{
+ QWidget *widget = m_ui->buildSettingsWidget->widget(pos);
+ m_ui->buildSettingsWidget->removeWidget(widget);
+ m_ui->buildSettingsWidget->insertWidget(pos -1, widget);
+ QTreeWidgetItem *item = m_ui->buildSettingsList->invisibleRootItem()->takeChild(pos);
+ m_ui->buildSettingsList->invisibleRootItem()->insertChild(pos - 1, item);
+}
+
+void BuildStepsPage::updateBuildStepButtonsState()
+{
+ int pos = m_ui->buildSettingsList->currentIndex().row();
+
+ m_ui->buildStepRemoveToolButton->setEnabled(!m_pro->buildSteps().at(pos)->immutable());
+ bool enableUp = pos>0 && !(m_pro->buildSteps().at(pos)->immutable() && m_pro->buildSteps().at(pos-1)->immutable());
+ m_ui->buildStepUpToolButton->setEnabled(enableUp);
+ bool enableDown = pos < (m_ui->buildSettingsList->invisibleRootItem()->childCount() - 1) &&
+ !(m_pro->buildSteps().at(pos)->immutable() && m_pro->buildSteps().at(pos+1)->immutable());
+ m_ui->buildStepDownToolButton->setEnabled(enableDown);
+}
diff --git a/src/plugins/projectexplorer/buildstepspage.h b/src/plugins/projectexplorer/buildstepspage.h
new file mode 100644
index 0000000000..4af2fde624
--- /dev/null
+++ b/src/plugins/projectexplorer/buildstepspage.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDSTEPSPAGE_H
+#define BUILDSTEPSPAGE_H
+
+#include "buildstep.h"
+
+QT_BEGIN_NAMESPACE
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+
+class Project;
+
+namespace Internal {
+
+namespace Ui {
+ class BuildStepsPage;
+}
+
+class BuildStepsPage : public BuildStepConfigWidget {
+ Q_OBJECT
+ Q_DISABLE_COPY(BuildStepsPage)
+public:
+ explicit BuildStepsPage(Project *project);
+ virtual ~BuildStepsPage();
+
+ QString displayName() const;
+ void init(const QString &buildConfiguration);
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private slots:
+ void displayNameChanged(BuildStep *bs, const QString &displayName);
+ void updateBuildStepWidget(QTreeWidgetItem *newItem, QTreeWidgetItem *oldItem);
+ void updateAddBuildStepMenu();
+ void addBuildStep();
+ void removeBuildStep();
+ void upBuildStep();
+ void downBuildStep();
+
+private:
+ void buildStepMoveUp(int pos);
+ void updateBuildStepButtonsState();
+
+ Ui::BuildStepsPage *m_ui;
+ Project *m_pro;
+ QString m_configuration;
+ QHash<QAction *, QPair<QString, ProjectExplorer::IBuildStepFactory *> > m_addBuildStepHash;
+};
+
+} // Internal
+} // ProjectExplorer
+
+#endif // BUILDSTEPSPAGE_H
diff --git a/src/plugins/projectexplorer/buildstepspage.ui b/src/plugins/projectexplorer/buildstepspage.ui
new file mode 100644
index 0000000000..85267824b0
--- /dev/null
+++ b/src/plugins/projectexplorer/buildstepspage.ui
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::BuildStepsPage</class>
+ <widget class="QWidget" name="ProjectExplorer::Internal::BuildStepsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QTreeWidget" name="buildSettingsList">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>150</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="headerHidden">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buildStepAddButton">
+ <property name="text">
+ <string>+</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buildStepRemoveToolButton">
+ <property name="text">
+ <string>-</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::DelayedPopup</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buildStepUpToolButton">
+ <property name="text">
+ <string>^</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buildStepDownToolButton">
+ <property name="text">
+ <string>v</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1" rowspan="2">
+ <widget class="QStackedWidget" name="buildSettingsWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="page_2"/>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>47</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp
new file mode 100644
index 0000000000..2f138ad857
--- /dev/null
+++ b/src/plugins/projectexplorer/compileoutputwindow.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "compileoutputwindow.h"
+#include "buildmanager.h"
+
+#include <find/basetextfind.h>
+#include <aggregation/aggregate.h>
+
+#include <QtGui/QKeyEvent>
+#include <QtGui/QIcon>
+#include <QtGui/QTextEdit>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+CompileOutputWindow::CompileOutputWindow(BuildManager * /*bm*/)
+{
+ m_textEdit = new QTextEdit();
+ m_textEdit->setWindowTitle(tr("Compile Output"));
+ m_textEdit->setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
+ m_textEdit->setReadOnly(true);
+ m_textEdit->setFrameStyle(QFrame::NoFrame);
+ Aggregation::Aggregate *agg = new Aggregation::Aggregate;
+ agg->add(m_textEdit);
+ agg->add(new Find::BaseTextFind(m_textEdit));
+}
+
+bool CompileOutputWindow::hasFocus()
+{
+ return m_textEdit->hasFocus();
+}
+
+bool CompileOutputWindow::canFocus()
+{
+ return true;
+}
+
+void CompileOutputWindow::setFocus()
+{
+ m_textEdit->setFocus();
+}
+
+QWidget *CompileOutputWindow::outputWidget(QWidget *)
+{
+ return m_textEdit;
+}
+
+void CompileOutputWindow::appendText(const QString &text)
+{
+ m_textEdit->append(text);
+}
+
+void CompileOutputWindow::clearContents()
+{
+ m_textEdit->clear();
+}
+
+void CompileOutputWindow::visibilityChanged(bool /* b */)
+{
+
+}
+
+int CompileOutputWindow::priorityInStatusBar() const
+{
+ return 50;
+}
diff --git a/src/plugins/projectexplorer/compileoutputwindow.h b/src/plugins/projectexplorer/compileoutputwindow.h
new file mode 100644
index 0000000000..aaf90172b3
--- /dev/null
+++ b/src/plugins/projectexplorer/compileoutputwindow.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPILEOUTPUTWINDOW_H
+#define COMPILEOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+#include <QtGui/QTextEdit>
+
+namespace ProjectExplorer {
+
+class BuildManager;
+
+namespace Internal {
+
+class CompileOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ CompileOutputWindow(BuildManager *bm);
+ QWidget *outputWidget(QWidget *);
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+ QString name() const { return tr("Compile"); }
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool visible);
+ void appendText(const QString &text);
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+private:
+ QTextEdit *m_textEdit;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // COMPILEOUTPUTWINDOW_H
diff --git a/src/plugins/projectexplorer/consoleprocess.h b/src/plugins/projectexplorer/consoleprocess.h
new file mode 100644
index 0000000000..0969618b7e
--- /dev/null
+++ b/src/plugins/projectexplorer/consoleprocess.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CONSOLEPROCESS_H
+#define CONSOLEPROCESS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QProcess>
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+class QWinEventNotifier;
+#endif
+
+#include "abstractprocess.h"
+
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class ConsoleProcess : public QObject, public AbstractProcess
+{
+ Q_OBJECT
+
+public:
+ ConsoleProcess(QObject *parent);
+ ~ConsoleProcess();
+
+ bool start(const QString &program, const QStringList &args);
+ void stop();
+
+ bool isRunning() const;
+ qint64 applicationPID() const;
+ int exitCode() const;
+
+signals:
+ void processError(const QString &error);
+ void processStarted();
+ void processStopped();
+
+private:
+ bool m_isRunning;
+
+#ifdef Q_OS_WIN
+public:
+ static QString createCommandline(const QString &program,
+ const QStringList &args);
+ static QByteArray createEnvironment(const QStringList &env);
+
+private slots:
+ void processDied();
+
+private:
+ PROCESS_INFORMATION *m_pid;
+ QWinEventNotifier *processFinishedNotifier;
+#elif defined(Q_OS_UNIX)
+private:
+ QProcess *m_process;
+private slots:
+ void processFinished(int, QProcess::ExitStatus);
+#endif
+
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif
diff --git a/src/plugins/projectexplorer/consoleprocess_unix.cpp b/src/plugins/projectexplorer/consoleprocess_unix.cpp
new file mode 100644
index 0000000000..325df91334
--- /dev/null
+++ b/src/plugins/projectexplorer/consoleprocess_unix.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "consoleprocess.h"
+
+using namespace ProjectExplorer::Internal;
+
+ConsoleProcess::ConsoleProcess(QObject *parent)
+ : QObject(parent)
+{
+ m_isRunning = false;
+ m_process = new QProcess(this);
+}
+
+ConsoleProcess::~ConsoleProcess()
+{
+}
+
+bool ConsoleProcess::start(const QString &program, const QStringList &args)
+{
+ if (m_process->state() != QProcess::NotRunning)
+ return false;
+ QString shellArgs;
+ shellArgs += QLatin1String("cd ");
+ shellArgs += workingDirectory();
+ shellArgs += QLatin1Char(';');
+ shellArgs += program;
+ foreach (const QString &arg, args) {
+ shellArgs += QLatin1Char(' ');
+ shellArgs += QLatin1Char('\'');
+ shellArgs += arg;
+ shellArgs += QLatin1Char('\'');
+ }
+ shellArgs += QLatin1String("; echo; echo \"Press enter to close this window\"; read");
+
+ m_process->setEnvironment(environment());
+
+ connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(processFinished(int, QProcess::ExitStatus)));
+
+ m_process->start(QLatin1String("xterm"), QStringList() << QLatin1String("-e") << shellArgs);
+ if (!m_process->waitForStarted())
+ return false;
+ emit processStarted();
+ return true;
+}
+
+void ConsoleProcess::processFinished(int, QProcess::ExitStatus)
+{
+ emit processStopped();
+}
+
+bool ConsoleProcess::isRunning() const
+{
+ return m_process->state() != QProcess::NotRunning;
+}
+
+void ConsoleProcess::stop()
+{
+ m_process->terminate();
+ m_process->waitForFinished();
+}
+
+qint64 ConsoleProcess::applicationPID() const
+{
+ return m_process->pid();
+}
+
+int ConsoleProcess::exitCode() const
+{
+ return m_process->exitCode();
+}
+
diff --git a/src/plugins/projectexplorer/consoleprocess_win.cpp b/src/plugins/projectexplorer/consoleprocess_win.cpp
new file mode 100644
index 0000000000..4133e15488
--- /dev/null
+++ b/src/plugins/projectexplorer/consoleprocess_win.cpp
@@ -0,0 +1,239 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDir>
+#include <QtCore/private/qwineventnotifier_p.h>
+#include <QtCore/QAbstractEventDispatcher>
+
+#include <Tlhelp32.h>
+
+#include "consoleprocess.h"
+
+using namespace ProjectExplorer::Internal;
+
+ConsoleProcess::ConsoleProcess(QObject *parent)
+ : QObject(parent)
+{
+ m_isRunning = false;
+ m_pid = 0;
+}
+
+ConsoleProcess::~ConsoleProcess()
+{
+ stop();
+}
+
+void ConsoleProcess::stop()
+{
+ if (m_pid)
+ TerminateProcess(m_pid->hProcess, -1);
+ m_isRunning = false;
+}
+
+bool ConsoleProcess::start(const QString &program, const QStringList &args)
+{
+ if (m_isRunning)
+ return false;
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (m_pid) {
+ CloseHandle(m_pid->hThread);
+ CloseHandle(m_pid->hProcess);
+ delete m_pid;
+ m_pid = 0;
+ }
+ m_pid = new PROCESS_INFORMATION;
+ ZeroMemory(m_pid, sizeof(PROCESS_INFORMATION));
+
+ QString cmdLine = QLatin1String("cmd /k ")
+ + createCommandline(program, args)
+ + QLatin1String(" & pause & exit");
+
+ bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
+ 0, 0, TRUE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
+ environment().isEmpty() ? 0
+ : createEnvironment(environment()).data(),
+ workingDirectory().isEmpty() ? 0
+ : (WCHAR*)QDir::convertSeparators(workingDirectory()).utf16(),
+ &si, m_pid);
+
+ if (!success) {
+ emit processError(tr("The process could not be started!"));
+ return false;
+ }
+
+ if (QAbstractEventDispatcher::instance(thread())) {
+ processFinishedNotifier = new QWinEventNotifier(m_pid->hProcess, this);
+ QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), this, SLOT(processDied()));
+ processFinishedNotifier->setEnabled(true);
+ }
+ m_isRunning = true;
+ emit processStarted();
+ return success;
+}
+
+bool ConsoleProcess::isRunning() const
+{
+ return m_isRunning;
+}
+
+void ConsoleProcess::processDied()
+{
+ if (processFinishedNotifier) {
+ processFinishedNotifier->setEnabled(false);
+ delete processFinishedNotifier;
+ processFinishedNotifier = 0;
+ }
+ delete m_pid;
+ m_pid = 0;
+ m_isRunning = false;
+ emit processStopped();
+}
+
+qint64 ConsoleProcess::applicationPID() const
+{
+ if (m_pid) {
+ HANDLE hProcList = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ PROCESSENTRY32 procEntry;
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
+ DWORD procId = 0;
+ BOOL moreProc = Process32First(hProcList, &procEntry);
+ while (moreProc) {
+ if (procEntry.th32ParentProcessID == m_pid->dwProcessId) {
+ procId = procEntry.th32ProcessID;
+ break;
+ }
+ moreProc = Process32Next(hProcList, &procEntry);
+ }
+
+ CloseHandle(hProcList);
+ return procId;
+ }
+ return 0;
+}
+
+int ConsoleProcess::exitCode() const
+{
+ DWORD exitCode;
+ if (GetExitCodeProcess(m_pid->hProcess, &exitCode))
+ return exitCode;
+ return -1;
+}
+
+QByteArray ConsoleProcess::createEnvironment(const QStringList &env)
+{
+ QByteArray envlist;
+ if (!env.isEmpty()) {
+ QStringList envStrings = env;
+ int pos = 0;
+ // add PATH if necessary (for DLL loading)
+ if (envStrings.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty()) {
+ QByteArray path = qgetenv("PATH");
+ if (!path.isEmpty())
+ envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)));
+ }
+ // add systemroot if needed
+ if (envStrings.filter(QRegExp("^SystemRoot=",Qt::CaseInsensitive)).isEmpty()) {
+ QByteArray systemRoot = qgetenv("SystemRoot");
+ if (!systemRoot.isEmpty())
+ envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
+ }
+#ifdef UNICODE
+ if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
+ for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); it++ ) {
+ QString tmp = *it;
+ uint tmpSize = sizeof(TCHAR) * (tmp.length()+1);
+ envlist.resize(envlist.size() + tmpSize);
+ memcpy(envlist.data()+pos, tmp.utf16(), tmpSize);
+ pos += tmpSize;
+ }
+ // add the 2 terminating 0 (actually 4, just to be on the safe side)
+ envlist.resize(envlist.size() + 4);
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ } else
+#endif // UNICODE
+ {
+ for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); it++) {
+ QByteArray tmp = (*it).toLocal8Bit();
+ uint tmpSize = tmp.length() + 1;
+ envlist.resize(envlist.size() + tmpSize);
+ memcpy(envlist.data()+pos, tmp.data(), tmpSize);
+ pos += tmpSize;
+ }
+ // add the terminating 0 (actually 2, just to be on the safe side)
+ envlist.resize(envlist.size() + 2);
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ }
+ }
+ return envlist;
+}
+
+QString ConsoleProcess::createCommandline(const QString &program, const QStringList &args)
+{
+ QString programName = program;
+ if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(" "))
+ programName = "\"" + programName + "\"";
+ programName.replace("/", "\\");
+
+ QString cmdLine;
+ // add the prgram as the first arrg ... it works better
+ cmdLine = programName + " ";
+ for (int i = 0; i < args.size(); ++i) {
+ QString tmp = args.at(i);
+ // in the case of \" already being in the string the \ must also be escaped
+ tmp.replace( "\\\"", "\\\\\"" );
+ // escape a single " because the arguments will be parsed
+ tmp.replace( "\"", "\\\"" );
+ if (tmp.isEmpty() || tmp.contains(' ') || tmp.contains('\t')) {
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ QString endQuote("\"");
+ int i = tmp.length();
+ while (i > 0 && tmp.at(i - 1) == '\\') {
+ --i;
+ endQuote += "\\";
+ }
+ cmdLine += QString(" \"") + tmp.left(i) + endQuote;
+ } else {
+ cmdLine += ' ' + tmp;
+ }
+ }
+ return cmdLine;
+}
diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp
new file mode 100644
index 0000000000..1a029db744
--- /dev/null
+++ b/src/plugins/projectexplorer/currentprojectfilter.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+
+
+#include "currentprojectfilter.h"
+#include "projectexplorer.h"
+#include "project.h"
+#include "session.h"
+
+#include <QtCore/QVariant>
+#include <QtCore/QTimer>
+
+#include <QtCore/QThread>
+#include <QtDebug>
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+CurrentProjectFilter::CurrentProjectFilter(ProjectExplorerPlugin *pe,
+ ICore *core)
+ : BaseFileFilter(core),
+ m_project(0)
+{
+ m_projectExplorer = pe;
+
+ connect(m_projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
+ this, SLOT(currentProjectChanged(ProjectExplorer::Project*)));
+ setShortcutString("p");
+ setIncludedByDefault(false);
+}
+
+void CurrentProjectFilter::refreshInternally()
+{
+ m_files.clear();
+ if (!m_project)
+ return;
+ m_files = m_project->files(Project::AllFiles);
+ qSort(m_files);
+ generateFileNames();
+}
+
+void CurrentProjectFilter::currentProjectChanged(ProjectExplorer::Project *project)
+{
+ if (project == m_project)
+ return;
+ if (m_project) {
+ disconnect(m_project, SIGNAL(fileListChanged()), this, SLOT(refreshInternally()));
+ }
+ if (project) {
+ connect(project, SIGNAL(fileListChanged()), this, SLOT(refreshInternally()));
+ }
+ m_project = project;
+ refreshInternally();
+}
+
+void CurrentProjectFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+ // invokeAsyncronouslyOnGuiThread
+ connect(this, SIGNAL(invokeRefresh()), this, SLOT(refreshInternally()));
+ emit invokeRefresh();
+ disconnect(this, SIGNAL(invokeRefresh()), this, SLOT(refreshInternally()));
+}
diff --git a/src/plugins/projectexplorer/currentprojectfilter.h b/src/plugins/projectexplorer/currentprojectfilter.h
new file mode 100644
index 0000000000..77bbbd1f52
--- /dev/null
+++ b/src/plugins/projectexplorer/currentprojectfilter.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CURRENTPROJECTFILTER_H
+#define CURRENTPROJECTFILTER_H
+
+#include <quickopen/basefilefilter.h>
+
+#include <QtCore/QString>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QTimer>
+#include <QtGui/QWidget>
+
+namespace ProjectExplorer {
+
+class ProjectExplorerPlugin;
+class Project;
+
+namespace Internal {
+
+class CurrentProjectFilter : public QuickOpen::BaseFileFilter
+{
+ Q_OBJECT
+
+public:
+ CurrentProjectFilter(ProjectExplorerPlugin *pe, Core::ICore *core);
+ QString trName() const { return tr("File in current project"); }
+ QString name() const { return "File in current project"; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::Low; }
+ void refresh(QFutureInterface<void> &future);
+
+private slots:
+ void currentProjectChanged(ProjectExplorer::Project *project);
+ void refreshInternally();
+
+signals:
+ void invokeRefresh();
+
+private:
+
+ ProjectExplorerPlugin *m_projectExplorer;
+ Project *m_project;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // CURRENTPROJECTFILTER_H
diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp
new file mode 100644
index 0000000000..da560894fb
--- /dev/null
+++ b/src/plugins/projectexplorer/currentprojectfind.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "currentprojectfind.h"
+#include "projectexplorer.h"
+#include "project.h"
+
+#include <QtDebug>
+#include <QtCore/QRegExp>
+#include <QtGui/QGridLayout>
+
+using namespace Find;
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+using namespace TextEditor;
+
+CurrentProjectFind::CurrentProjectFind(ProjectExplorerPlugin *plugin, Core::ICore *core, SearchResultWindow *resultWindow)
+ : BaseFileFind(core, resultWindow),
+ m_plugin(plugin),
+ m_configWidget(0)
+{
+ connect(m_plugin, SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
+ this, SIGNAL(changed()));
+}
+
+QString CurrentProjectFind::name() const
+{
+ return tr("Current Project");
+}
+
+bool CurrentProjectFind::isEnabled() const
+{
+ return m_plugin->currentProject() != 0 && BaseFileFind::isEnabled();
+}
+
+QKeySequence CurrentProjectFind::defaultShortcut() const
+{
+ return QKeySequence("Ctrl+Alt+F");
+}
+
+QStringList CurrentProjectFind::files()
+{
+ Project *project = m_plugin->currentProject();
+ Q_ASSERT(project);
+ if (!project)
+ return QStringList();
+ QList<QRegExp> filterRegs;
+ QStringList nameFilters = fileNameFilters();
+ foreach (const QString &filter, nameFilters) {
+ filterRegs << QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard);
+ }
+ QStringList files;
+ if (!filterRegs.isEmpty()) {
+ foreach (const QString &file, project->files(Project::AllFiles)) {
+ foreach (const QRegExp &reg, filterRegs) {
+ if (reg.exactMatch(file)) {
+ files.append(file);
+ break;
+ }
+ }
+ }
+ } else {
+ files += project->files(Project::AllFiles);
+ }
+ files.removeDuplicates();
+ return files;
+}
+
+QWidget *CurrentProjectFind::createConfigWidget()
+{
+ if (!m_configWidget) {
+ m_configWidget = new QWidget;
+ QGridLayout * const layout = new QGridLayout(m_configWidget);
+ layout->setMargin(0);
+ m_configWidget->setLayout(layout);
+ layout->addWidget(createRegExpWidget(), 0, 1);
+ QLabel * const filePatternLabel = new QLabel(tr("File pattern:"));
+ filePatternLabel->setMinimumWidth(80);
+ filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ layout->addWidget(filePatternLabel, 1, 0, Qt::AlignRight);
+ layout->addWidget(createPatternWidget(), 1, 1);
+ m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ }
+ return m_configWidget;
+}
+
+void CurrentProjectFind::writeSettings(QSettings *settings)
+{
+ settings->beginGroup("CurrentProjectFind");
+ writeCommonSettings(settings);
+ settings->endGroup();
+}
+
+void CurrentProjectFind::readSettings(QSettings *settings)
+{
+ settings->beginGroup("CurrentProjectFind");
+ readCommonSettings(settings, "*");
+ settings->endGroup();
+}
diff --git a/src/plugins/projectexplorer/currentprojectfind.h b/src/plugins/projectexplorer/currentprojectfind.h
new file mode 100644
index 0000000000..a70567b7e4
--- /dev/null
+++ b/src/plugins/projectexplorer/currentprojectfind.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CURRENTPROJECTFIND_H
+#define CURRENTPROJECTFIND_H
+
+#include <coreplugin/icore.h>
+#include <find/ifindfilter.h>
+#include <find/searchresultwindow.h>
+#include <texteditor/basefilefind.h>
+
+#include <QtCore/QPointer>
+#include <QtGui/QWidget>
+
+namespace ProjectExplorer {
+
+class ProjectExplorerPlugin;
+
+namespace Internal {
+
+class CurrentProjectFind : public TextEditor::BaseFileFind
+{
+public:
+ CurrentProjectFind(ProjectExplorerPlugin *plugin, Core::ICore *core, Find::SearchResultWindow *resultWindow);
+
+ QString name() const;
+
+ bool isEnabled() const;
+ QKeySequence defaultShortcut() const;
+
+ QWidget *createConfigWidget();
+ void writeSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+protected:
+ QStringList files();
+
+private:
+ ProjectExplorerPlugin *m_plugin;
+ QPointer<QWidget> m_configWidget;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // CURRENTPROJECTFIND_H
diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
new file mode 100644
index 0000000000..4f2b470aec
--- /dev/null
+++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
@@ -0,0 +1,316 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "customexecutablerunconfiguration.h"
+#include "environment.h"
+#include "project.h"
+
+#include <QtGui/QFormLayout>
+#include <QtGui/QLineEdit>
+#include <QtGui/QLabel>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QToolButton>
+#include <QtGui/QFileDialog>
+#include <QDialogButtonBox>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+CustomExecutableConfigurationWidget::CustomExecutableConfigurationWidget(CustomExecutableRunConfiguration *rc)
+ : m_ignoreChange(false)
+{
+ m_runConfiguration = rc;
+
+ QFormLayout *layout = new QFormLayout();
+ layout->setMargin(0);
+
+ m_executableLineEdit = new QLineEdit;
+ QToolButton *exectuableToolButton = new QToolButton();
+ exectuableToolButton->setText("...");
+ QHBoxLayout *hl = new QHBoxLayout;
+ hl->addWidget(m_executableLineEdit);
+ hl->addWidget(exectuableToolButton);
+ layout->addRow("Executable", hl);
+
+ m_commandLineArgumentsLineEdit = new QLineEdit;
+ layout->addRow("Arguments", m_commandLineArgumentsLineEdit);
+
+ m_workingDirectoryLineEdit = new QLineEdit();
+ QToolButton *workingDirectoryToolButton = new QToolButton();
+ workingDirectoryToolButton->setText("...");
+ hl = new QHBoxLayout;
+ hl->addWidget(m_workingDirectoryLineEdit);
+ hl->addWidget(workingDirectoryToolButton);
+ layout->addRow("Working Directory", hl);
+
+ setLayout(layout);
+ changed();
+
+ connect(m_executableLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(setExecutable(const QString&)));
+ connect(m_commandLineArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(setCommandLineArguments(const QString&)));
+ connect(m_workingDirectoryLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(setWorkingDirectory(const QString&)));
+ connect(exectuableToolButton, SIGNAL(clicked(bool)),
+ this, SLOT(executableToolButtonClicked()));
+ connect(workingDirectoryToolButton, SIGNAL(clicked(bool)),
+ this, SLOT(workingDirectoryToolButtonClicked()));
+
+ connect(m_runConfiguration, SIGNAL(changed()), this, SLOT(changed()));
+}
+
+void CustomExecutableConfigurationWidget::setExecutable(const QString &executable)
+{
+ m_ignoreChange = true;
+ m_runConfiguration->setExecutable(executable);
+ m_ignoreChange = false;
+}
+void CustomExecutableConfigurationWidget::setCommandLineArguments(const QString &commandLineArguments)
+{
+ m_ignoreChange = true;
+ m_runConfiguration->setCommandLineArguments(commandLineArguments);
+ m_ignoreChange = false;
+}
+void CustomExecutableConfigurationWidget::setWorkingDirectory(const QString &workingDirectory)
+{
+ m_ignoreChange = true;
+ m_runConfiguration->setWorkingDirectory(workingDirectory);
+ m_ignoreChange = false;
+}
+
+void CustomExecutableConfigurationWidget::executableToolButtonClicked()
+{
+ QString newValue;
+ QString executableFilter;
+#ifdef Q_OS_WIN
+ executableFilter = "Executable (*.exe)";
+#endif
+ newValue = QFileDialog::getOpenFileName(this, "Executable", "", executableFilter);
+ if (!newValue.isEmpty()) {
+ m_executableLineEdit->setText(newValue);
+ setExecutable(newValue);
+ }
+}
+
+void CustomExecutableConfigurationWidget::workingDirectoryToolButtonClicked()
+{
+ QString newValue;
+ QString executableFilter;
+
+ newValue = QFileDialog::getExistingDirectory(this, "Directory", m_workingDirectoryLineEdit->text());
+ if (newValue.isEmpty()) {
+ m_workingDirectoryLineEdit->setText(newValue);
+ setWorkingDirectory(newValue);
+ }
+}
+
+void CustomExecutableConfigurationWidget::changed()
+{
+ // We triggered the change, don't update us
+ if (m_ignoreChange)
+ return;
+ m_executableLineEdit->setText(m_runConfiguration->baseExecutable());
+ m_commandLineArgumentsLineEdit->setText(ProjectExplorer::Environment::joinArgumentList(m_runConfiguration->commandLineArguments()));
+ m_workingDirectoryLineEdit->setText(m_runConfiguration->baseWorkingDirectory());
+}
+
+CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Project *pro)
+ : ApplicationRunConfiguration(pro)
+{
+ m_workingDirectory = "$BUILDDIR";
+ setName("Custom Executable");
+}
+
+CustomExecutableRunConfiguration::~CustomExecutableRunConfiguration()
+{
+}
+
+QString CustomExecutableRunConfiguration::type() const
+{
+ return "ProjectExplorer.CustomExecutableRunConfiguration";
+}
+
+QString CustomExecutableRunConfiguration::baseExecutable() const
+{
+ return m_executable;
+}
+
+QString CustomExecutableRunConfiguration::executable() const
+{
+ QString exec;
+ if (QDir::isRelativePath(m_executable)) {
+ Environment env = project()->environment(project()->activeBuildConfiguration());
+ exec = env.searchInPath(m_executable);
+ } else {
+ exec = m_executable;
+ }
+
+ if (!QFileInfo(exec).exists()) {
+ // Oh the executable doesn't exists, ask the user.
+ QWidget *confWidget = const_cast<CustomExecutableRunConfiguration *>(this)->configurationWidget();
+ QDialog dialog;
+ dialog.setLayout(new QVBoxLayout());
+ dialog.layout()->addWidget(new QLabel("Could not find the executable, please specify one."));
+ dialog.layout()->addWidget(confWidget);
+ QDialogButtonBox *dbb = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(dbb, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(dbb, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ dialog.layout()->addWidget(dbb);
+
+ QString oldExecutable = m_executable;
+ QString oldWorkingDirectory = m_workingDirectory;
+ QStringList oldCmdArguments = m_cmdArguments;
+
+ if (dialog.exec()) {
+ return executable();
+ } else {
+ CustomExecutableRunConfiguration *that = const_cast<CustomExecutableRunConfiguration *>(this);
+ that->m_executable = oldExecutable;
+ that->m_workingDirectory = oldWorkingDirectory;
+ that->m_cmdArguments = oldCmdArguments;
+ emit that->changed();
+ return QString::null;
+ }
+ }
+ return exec;
+}
+
+ApplicationRunConfiguration::RunMode CustomExecutableRunConfiguration::runMode() const
+{
+ return ApplicationRunConfiguration::Gui;
+}
+
+QString CustomExecutableRunConfiguration::baseWorkingDirectory() const
+{
+ return m_workingDirectory;
+}
+
+QString CustomExecutableRunConfiguration::workingDirectory() const
+{
+ QString wd = m_workingDirectory;
+ QString bd = project()->buildDirectory(project()->activeBuildConfiguration());
+ return wd.replace("$BUILDDIR", QDir::cleanPath(bd));
+}
+
+QStringList CustomExecutableRunConfiguration::commandLineArguments() const
+{
+ return m_cmdArguments;
+}
+
+Environment CustomExecutableRunConfiguration::environment() const
+{
+ return project()->environment(project()->activeBuildConfiguration());
+}
+
+
+void CustomExecutableRunConfiguration::save(PersistentSettingsWriter &writer) const
+{
+ writer.saveValue("Executable", m_executable);
+ writer.saveValue("Arguments", m_cmdArguments);
+ writer.saveValue("WorkingDirectory", m_workingDirectory);
+ ApplicationRunConfiguration::save(writer);
+}
+
+void CustomExecutableRunConfiguration::restore(const PersistentSettingsReader &reader)
+{
+ m_executable = reader.restoreValue("Executable").toString();
+ m_cmdArguments = reader.restoreValue("Arguments").toStringList();
+ m_workingDirectory = reader.restoreValue("WorkingDirectory").toString();
+ ApplicationRunConfiguration::restore(reader);
+}
+
+void CustomExecutableRunConfiguration::setExecutable(const QString &executable)
+{
+ m_executable = executable;
+ setName(tr("Run %1").arg(m_executable));
+ emit changed();
+}
+
+void CustomExecutableRunConfiguration::setCommandLineArguments(const QString &commandLineArguments)
+{
+ m_cmdArguments = ProjectExplorer::Environment::parseCombinedArgString(commandLineArguments);
+ emit changed();
+}
+
+void CustomExecutableRunConfiguration::setWorkingDirectory(const QString &workingDirectory)
+{
+ m_workingDirectory = workingDirectory;
+ emit changed();
+}
+
+QWidget *CustomExecutableRunConfiguration::configurationWidget()
+{
+ return new CustomExecutableConfigurationWidget(this);
+}
+
+// Factory
+
+CustomExecutableRunConfigurationFactory::CustomExecutableRunConfigurationFactory()
+{
+}
+
+CustomExecutableRunConfigurationFactory::~CustomExecutableRunConfigurationFactory()
+{
+
+}
+
+// used to recreate the runConfigurations when restoring settings
+bool CustomExecutableRunConfigurationFactory::canCreate(const QString &type) const
+{
+ return type == "ProjectExplorer.CustomExecutableRunConfiguration";
+}
+
+QSharedPointer<RunConfiguration> CustomExecutableRunConfigurationFactory::create(Project *project, const QString &type)
+{
+ if (type == "ProjectExplorer.CustomExecutableRunConfiguration") {
+ QSharedPointer<RunConfiguration> rc(new CustomExecutableRunConfiguration(project));
+ rc->setName("Custom Executable");
+ return rc;
+ } else {
+ return QSharedPointer<RunConfiguration>(0);
+ }
+}
+
+QStringList CustomExecutableRunConfigurationFactory::canCreate(Project *pro) const
+{
+ Q_UNUSED(pro)
+ return QStringList()<< "ProjectExplorer.CustomExecutableRunConfiguration";
+}
+
+QString CustomExecutableRunConfigurationFactory::nameForType(const QString &type) const
+{
+ if (type == "ProjectExplorer.CustomExecutableRunConfiguration")
+ return "Custom Executable";
+ else
+ return QString::null;
+}
diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.h b/src/plugins/projectexplorer/customexecutablerunconfiguration.h
new file mode 100644
index 0000000000..8f53582bfc
--- /dev/null
+++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CUSTOMEXECUTABLERUNCONFIGURATION_H
+#define CUSTOMEXECUTABLERUNCONFIGURATION_H
+
+#include "applicationrunconfiguration.h"
+
+#include <QtGui/QToolButton>
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+
+namespace Internal {
+ class CustomExecutableConfigurationWidget;
+}
+
+class PROJECTEXPLORER_EXPORT CustomExecutableRunConfiguration : public ApplicationRunConfiguration
+{
+ // the configuration widget needs to setExecutable setWorkingDirectory and setCommandLineArguments
+ friend class Internal::CustomExecutableConfigurationWidget;
+ Q_OBJECT
+public:
+ CustomExecutableRunConfiguration(Project *pro);
+ ~CustomExecutableRunConfiguration();
+ virtual QString type() const;
+ // returns the executable,
+ // looks in the environment for it
+ // and might even ask the user if none is specified
+ virtual QString executable() const;
+ // Returns only what is stored in the internal variable
+ // not what we might get after extending it with a path
+ // or asking the user. This value is needed for the configuration widget
+ QString baseExecutable() const;
+ virtual ApplicationRunConfiguration::RunMode runMode() const;
+ virtual QString workingDirectory() const;
+ QString baseWorkingDirectory() const;
+ virtual QStringList commandLineArguments() const;
+ virtual Environment environment() const;
+
+ virtual void save(PersistentSettingsWriter &writer) const;
+ virtual void restore(const PersistentSettingsReader &reader);
+
+ virtual QWidget *configurationWidget();
+signals:
+ void changed();
+private slots:
+ void setExecutable(const QString &executable);
+ void setCommandLineArguments(const QString &commandLineArguments);
+ void setWorkingDirectory(const QString &workingDirectory);
+private:
+ QString m_executable;
+ QString m_workingDirectory;
+ QStringList m_cmdArguments;
+};
+
+class CustomExecutableRunConfigurationFactory : public IRunConfigurationFactory
+{
+ Q_OBJECT
+public:
+ CustomExecutableRunConfigurationFactory();
+ virtual ~CustomExecutableRunConfigurationFactory();
+ // used to recreate the runConfigurations when restoring settings
+ virtual bool canCreate(const QString &type) const;
+ virtual QSharedPointer<RunConfiguration> create(Project *project, const QString &type);
+ QStringList canCreate(Project *pro) const;
+ QString nameForType(const QString &type) const;
+};
+
+namespace Internal {
+class CustomExecutableConfigurationWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ CustomExecutableConfigurationWidget(CustomExecutableRunConfiguration *rc);
+private slots:
+ void changed();
+ void executableToolButtonClicked();
+ void workingDirectoryToolButtonClicked();
+
+ void setExecutable(const QString &executable);
+ void setCommandLineArguments(const QString &commandLineArguments);
+ void setWorkingDirectory(const QString &workingDirectory);
+private:
+ bool m_ignoreChange;
+ CustomExecutableRunConfiguration *m_runConfiguration;
+ QLineEdit *m_executableLineEdit;
+ QLineEdit *m_commandLineArgumentsLineEdit;
+ QLineEdit *m_workingDirectoryLineEdit;
+};
+}
+}
+
+#endif // CUSTOMEXECUTABLERUNCONFIGURATION_H
diff --git a/src/plugins/projectexplorer/dependenciesdialog.cpp b/src/plugins/projectexplorer/dependenciesdialog.cpp
new file mode 100644
index 0000000000..5314262f48
--- /dev/null
+++ b/src/plugins/projectexplorer/dependenciesdialog.cpp
@@ -0,0 +1,244 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "dependenciesdialog.h"
+#include "project.h"
+#include "session.h"
+
+#include <QtCore/QVector>
+#include <QtCore/QDebug>
+#include <QtCore/QAbstractTableModel>
+#include <QtGui/QPushButton>
+#include <QtGui/QHeaderView>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+// ------ DependencyModel
+
+class DependencyModel : public QAbstractTableModel {
+public:
+ typedef ProjectExplorer::Project Project;
+ typedef DependenciesDialog::ProjectList ProjectList;
+
+ DependencyModel(SessionManager *sln, const ProjectList &projectList, QObject * parent = 0);
+
+ virtual int rowCount(const QModelIndex&) const { return m_projects.size(); }
+ virtual int columnCount(const QModelIndex&) const { return m_projects.size(); }
+
+ virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
+ bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
+
+ virtual Qt::ItemFlags flags ( const QModelIndex & index ) const;
+
+ QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
+
+ // Apply changed items
+ unsigned apply(SessionManager *sln) const;
+
+ void resetDependencies();
+
+private:
+
+ struct Entry {
+ Entry(SessionManager *sln, Project *rootProject, Project *dependentProject);
+ Entry() : m_dependentProject(0), m_dependent(false), m_defaultValue(false), m_canAddDependency(false) {}
+ Project* m_dependentProject;
+ bool m_dependent;
+ bool m_defaultValue;
+ bool m_canAddDependency;
+ };
+
+ // column
+ typedef QVector<Entry> ProjectDependencies;
+ typedef QList<ProjectDependencies> Projects;
+ Projects m_projects;
+ ProjectList m_projectList;
+};
+
+DependencyModel::Entry::Entry(SessionManager *sln,
+ Project *rootProject,
+ Project *dependentProject) :
+ m_dependentProject(dependentProject),
+ m_dependent(sln->hasDependency(rootProject, dependentProject)),
+ m_defaultValue(m_dependent),
+ m_canAddDependency(sln->canAddDependency(rootProject, dependentProject))
+{
+}
+
+DependencyModel::DependencyModel(SessionManager *sln,
+ const ProjectList &projectList,
+ QObject * parent) :
+ QAbstractTableModel(parent),
+ m_projectList(projectList)
+{
+ const int count = projectList.size();
+ for (int p = 0; p < count; p++) {
+ Project *rootProject = projectList.at(p);
+ ProjectDependencies dependencies;
+ dependencies.reserve(count);
+ for (int d = 0; d < count ; d++)
+ dependencies.push_back(p == d ? Entry() : Entry(sln, rootProject, projectList.at(d)));
+
+ m_projects += dependencies;
+ }
+}
+
+QVariant DependencyModel::data ( const QModelIndex & index, int role ) const
+{
+ static const QVariant empty = QVariant(QString());
+ // TO DO: find a checked icon
+ static const QVariant checked = QVariant(QString(QLatin1Char('x')));
+
+ const int p = index.column();
+ const int d = index.row();
+ switch (role) {
+ case Qt::EditRole:
+ return QVariant(m_projects[p][d].m_dependent);
+ case Qt::DisplayRole:
+ return m_projects[p][d].m_dependent ? checked : empty;
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+bool DependencyModel::setData ( const QModelIndex & index, const QVariant & value, int role)
+{
+ switch (role) {
+ case Qt::EditRole: {
+ const int p = index.column();
+ const int d = index.row();
+ if (d == p)
+ return false;
+ Entry &e(m_projects[p][d]);
+ e.m_dependent = value.toBool();
+ emit dataChanged(index, index);
+ }
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+Qt::ItemFlags DependencyModel::flags ( const QModelIndex & index ) const
+{
+ const int p = index.column();
+ const int d = index.row();
+
+ if (d == p)
+ return 0;
+
+ const Entry &e(m_projects[p][d]);
+ Qt::ItemFlags rc = Qt::ItemIsEnabled|Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
+ if (e.m_canAddDependency)
+ rc |= Qt::ItemIsEditable;
+ return rc;
+}
+
+QVariant DependencyModel::headerData ( int section, Qt::Orientation , int role ) const
+{
+ switch (role) {
+ case Qt::DisplayRole:
+ return QVariant(m_projectList.at(section)->name());
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+void DependencyModel::resetDependencies()
+{
+ if (const int count = m_projectList.size()) {
+ for (int p = 0; p < count; p++)
+ for (int d = 0; d < count; d++)
+ m_projects[p][d].m_dependent = false;
+ reset();
+ }
+}
+
+unsigned DependencyModel::apply(SessionManager *sln) const
+{
+ unsigned rc = 0;
+ const int count = m_projectList.size();
+ for (int p = 0; p < count; p++) {
+ Project *rootProject = m_projectList.at(p);
+ for (int d = 0; d < count; d++) {
+ if (d != p) {
+ const Entry &e(m_projects[p][d]);
+ if (e.m_dependent != e. m_defaultValue) {
+ rc++;
+ if (e.m_dependent) {
+ sln->addDependency(rootProject, e.m_dependentProject);
+ } else {
+ sln->removeDependency(rootProject, e.m_dependentProject);
+ }
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+// ------ DependenciesDialog
+DependenciesDialog::DependenciesDialog(QWidget *parent, SessionManager *sln) :
+ QDialog(parent),
+ m_sln(sln),
+ m_projectList(m_sln->projects()),
+ m_model(new DependencyModel(sln, m_projectList))
+{
+ m_ui.setupUi(this);
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ QPushButton *resetButton = m_ui.buttonBox->addButton (QDialogButtonBox::Reset);
+ connect(resetButton, SIGNAL(clicked()), this, SLOT(reset()));
+
+ m_ui.dependencyTable->setModel(m_model);
+}
+
+void DependenciesDialog::accept()
+{
+ m_model->apply(m_sln);
+ QDialog::accept();
+}
+
+void DependenciesDialog::reset()
+{
+ m_model->resetDependencies();
+}
+
+DependenciesDialog::~DependenciesDialog()
+{
+}
+
+}
+}
diff --git a/src/plugins/projectexplorer/dependenciesdialog.h b/src/plugins/projectexplorer/dependenciesdialog.h
new file mode 100644
index 0000000000..7292a3affa
--- /dev/null
+++ b/src/plugins/projectexplorer/dependenciesdialog.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEPENDENCIESDIALOG_H
+#define DEPENDENCIESDIALOG_H
+
+#include "ui_dependenciesdialog.h"
+
+#include <QtGui/QDialog>
+
+namespace ProjectExplorer {
+
+class Project;
+class SessionManager;
+
+namespace Internal {
+
+class DependencyModel;
+
+// NBS kill DependenciesDialog?
+class DependenciesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ typedef QList<ProjectExplorer::Project *> ProjectList;
+
+ DependenciesDialog(QWidget *parent, SessionManager *sln);
+ virtual ~DependenciesDialog();
+
+public slots:
+ virtual void accept();
+ void reset();
+
+private:
+ Ui::DependenciesDialog m_ui;
+ SessionManager *m_sln;
+ ProjectList m_projectList;
+ DependencyModel *m_model;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // DEPENDENCIESDIALOG_H
diff --git a/src/plugins/projectexplorer/dependenciesdialog.ui b/src/plugins/projectexplorer/dependenciesdialog.ui
new file mode 100644
index 0000000000..25ffdff894
--- /dev/null
+++ b/src/plugins/projectexplorer/dependenciesdialog.ui
@@ -0,0 +1,98 @@
+<ui version="4.0" >
+ <class>ProjectExplorer::Internal::DependenciesDialog</class>
+ <widget class="QDialog" name="ProjectExplorer::Internal::DependenciesDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>618</width>
+ <height>660</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Project Dependencies</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QTableView" name="dependencyTable" >
+ <property name="minimumSize" >
+ <size>
+ <width>600</width>
+ <height>600</height>
+ </size>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </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>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProjectExplorer::Internal::DependenciesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>142</x>
+ <y>285</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>142</x>
+ <y>155</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProjectExplorer::Internal::DependenciesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>142</x>
+ <y>285</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>142</x>
+ <y>155</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/projectexplorer/directoryproject.cpp b/src/plugins/projectexplorer/directoryproject.cpp
new file mode 100644
index 0000000000..95674a5efd
--- /dev/null
+++ b/src/plugins/projectexplorer/directoryproject.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "directoryproject.h"
+
diff --git a/src/plugins/projectexplorer/editorconfiguration.cpp b/src/plugins/projectexplorer/editorconfiguration.cpp
new file mode 100644
index 0000000000..4b61b3ea83
--- /dev/null
+++ b/src/plugins/projectexplorer/editorconfiguration.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "editorconfiguration.h"
+
+#include <QtCore/QTextCodec>
+
+using namespace ProjectExplorer;
+
+EditorConfiguration::EditorConfiguration()
+ : m_defaultTextCodec(QTextCodec::codecForLocale())
+{
+}
+
+QTextCodec *EditorConfiguration::defaultTextCodec() const
+{
+ return m_defaultTextCodec;
+}
+
+void EditorConfiguration::setDefaultTextCodec(QTextCodec *codec)
+{
+ m_defaultTextCodec = codec;
+}
+
diff --git a/src/plugins/projectexplorer/editorconfiguration.h b/src/plugins/projectexplorer/editorconfiguration.h
new file mode 100644
index 0000000000..830e514c91
--- /dev/null
+++ b/src/plugins/projectexplorer/editorconfiguration.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EDITORCONFIGURATION_H
+#define EDITORCONFIGURATION_H
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+class QTextCodec;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+
+class PROJECTEXPLORER_EXPORT EditorConfiguration
+{
+public:
+ EditorConfiguration();
+ QTextCodec *defaultTextCodec() const;
+ void setDefaultTextCodec(QTextCodec *codec);
+
+private:
+ QTextCodec *m_defaultTextCodec;
+};
+
+}
+
+#endif
diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp
new file mode 100644
index 0000000000..0c98878d37
--- /dev/null
+++ b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "editorsettingspropertiespage.h"
+#include "editorconfiguration.h"
+
+#include <QtCore/QTextCodec>
+
+#include <QDebug>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+bool EditorSettingsPanelFactory::supports(Project * /*project*/)
+{
+ return true;
+}
+PropertiesPanel *EditorSettingsPanelFactory::createPanel(Project *project)
+{
+ return new EditorSettingsPanel(project);
+}
+
+EditorSettingsPanel::EditorSettingsPanel(Project *project)
+ : PropertiesPanel(),
+ m_widget(new EditorSettingsWidget(project))
+{
+}
+
+EditorSettingsPanel::~EditorSettingsPanel()
+{
+ delete m_widget;
+}
+
+QString EditorSettingsPanel::name() const
+{
+ return tr("Editor Settings");
+}
+
+QWidget *EditorSettingsPanel::widget()
+{
+ return m_widget;
+}
+
+EditorSettingsWidget::EditorSettingsWidget(Project *project)
+ : QWidget(),
+ m_project(project)
+{
+ m_ui.setupUi(this);
+ QTextCodec *defaultTextCodec = m_project->editorConfiguration()->defaultTextCodec();
+ QList<int> mibs = QTextCodec::availableMibs();
+ qSort(mibs);
+ QList<int> sortedMibs;
+ foreach (int mib, mibs)
+ if (mib >= 0)
+ sortedMibs += mib;
+ foreach (int mib, mibs)
+ if (mib < 0)
+ sortedMibs += mib;
+ int i = 0;
+ foreach (int mib, sortedMibs) {
+ QTextCodec *codec = QTextCodec::codecForMib(mib);
+ m_codecs += codec;
+ QString name = codec->name();
+ foreach (QByteArray alias, codec->aliases())
+ name += QLatin1String(" / ") + alias;
+ m_ui.encodingComboBox->addItem(name);
+ if (defaultTextCodec == codec)
+ m_ui.encodingComboBox->setCurrentIndex(i);
+ i++;
+ }
+
+ connect(m_ui.encodingComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(currentEncodingChanged(int)));
+}
+
+void EditorSettingsWidget::currentEncodingChanged(int index)
+{
+ QList<int> codecs = QTextCodec::availableMibs();
+ m_project->editorConfiguration()->setDefaultTextCodec(m_codecs.at(index));
+}
+
+
diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.h b/src/plugins/projectexplorer/editorsettingspropertiespage.h
new file mode 100644
index 0000000000..8d2e057ab2
--- /dev/null
+++ b/src/plugins/projectexplorer/editorsettingspropertiespage.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EDITORSETTINGSPROPERTIESPAGE_H
+#define EDITORSETTINGSPROPERTIESPAGE_H
+
+#include "iprojectproperties.h"
+#include "ui_editorsettingspropertiespage.h"
+
+namespace ProjectExplorer {
+
+namespace Internal {
+
+class EditorSettingsPanelFactory : public IPanelFactory
+{
+public:
+ bool supports(Project *project);
+ PropertiesPanel *createPanel(Project *project);
+};
+
+class EditorSettingsWidget;
+
+class EditorSettingsPanel : public PropertiesPanel
+{
+ Q_OBJECT
+public:
+ EditorSettingsPanel(Project *project);
+ ~EditorSettingsPanel();
+ QString name() const;
+ QWidget *widget();
+
+private:
+ EditorSettingsWidget *m_widget;
+};
+
+class EditorSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ EditorSettingsWidget(Project *project);
+
+private slots:
+ void currentEncodingChanged(int index);
+
+private:
+
+ Ui::EditorSettingsPropertiesPage m_ui;
+ Project *m_project;
+ QList<QTextCodec *> m_codecs;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // EDITORSETTINGSPROPERTIESPAGE_H
diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.ui b/src/plugins/projectexplorer/editorsettingspropertiespage.ui
new file mode 100644
index 0000000000..704f5cd0b3
--- /dev/null
+++ b/src/plugins/projectexplorer/editorsettingspropertiespage.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::EditorSettingsPropertiesPage</class>
+ <widget class="QWidget" name="ProjectExplorer::Internal::EditorSettingsPropertiesPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="encodingLabel">
+ <property name="text">
+ <string>Default File Encoding:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="encodingComboBox"/>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>232</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>249</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/projectexplorer/environment.cpp b/src/plugins/projectexplorer/environment.cpp
new file mode 100644
index 0000000000..9233b2b9a1
--- /dev/null
+++ b/src/plugins/projectexplorer/environment.cpp
@@ -0,0 +1,346 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "environment.h"
+
+#include <QtCore/QProcess>
+#include <QtCore/QDir>
+#include <QtCore/QString>
+#include <QtCore/QDebug>
+
+using namespace ProjectExplorer;
+
+QList<EnvironmentItem> EnvironmentItem::fromStringList(QStringList list)
+{
+ QList<EnvironmentItem> result;
+ foreach (const QString &string, list) {
+ int pos = string.indexOf(QLatin1Char('='));
+ if(pos == -1) {
+ EnvironmentItem item(string, "");
+ item.unset = true;
+ result.append(item);
+ } else {
+ EnvironmentItem item(string.left(pos), string.mid(pos+1));
+ result.append(item);
+ }
+ }
+ return result;
+}
+
+QStringList EnvironmentItem::toStringList(QList<EnvironmentItem> list)
+{
+ QStringList result;
+ foreach (const EnvironmentItem &item, list) {
+ if(item.unset)
+ result << QString(item.name);
+ else
+ result << QString(item.name + '=' + item.value);
+ }
+ return result;
+}
+
+Environment::Environment()
+{
+
+}
+
+Environment::Environment(QStringList env)
+{
+ foreach(QString s, env) {
+ int i = s.indexOf("=");
+ if (i >=0 ) {
+#ifdef Q_OS_WIN
+ m_values.insert(s.left(i).toUpper(), s.mid(i+1));
+#else
+ m_values.insert(s.left(i), s.mid(i+1));
+#endif
+ }
+ }
+}
+
+QStringList Environment::toStringList()
+{
+ QStringList result;
+ QMap<QString, QString>::const_iterator it, end;
+ end = m_values.constEnd();
+ for (it = m_values.constBegin(); it != end; ++it)
+ result<<(it.key() + "=" + it.value());
+
+ return result;
+}
+
+void Environment::set(const QString &key, const QString &value)
+{
+#ifdef Q_OS_WIN
+ QString _key = key.toUpper();
+#else
+ const QString &_key = key;
+#endif
+ m_values.insert(_key, value);
+}
+
+void Environment::unset(const QString &key)
+{
+#ifdef Q_OS_WIN
+ QString _key = key.toUpper();
+#else
+ const QString &_key = key;
+#endif
+ m_values.remove(_key);
+}
+
+void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
+{
+#ifdef Q_OS_WIN
+ QString _key = key.toUpper();
+#else
+ const QString &_key = key;
+#endif
+ QMap<QString, QString>::const_iterator it = m_values.constFind(key);
+ if (it == m_values.constEnd()) {
+ m_values.insert(_key, value);
+ } else {
+ QString tmp = *it + sep + value;
+ m_values.insert(_key, tmp);
+ }
+
+}
+
+void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep)
+{
+#ifdef Q_OS_WIN
+ QString _key = key.toUpper();
+#else
+ const QString &_key = key;
+#endif
+ QMap<QString, QString>::const_iterator it = m_values.constFind(key);
+ if (it == m_values.constEnd()) {
+ m_values.insert(_key, value);
+ } else {
+ QString tmp = value + sep + *it;
+ m_values.insert(_key, tmp);
+ }
+}
+
+void Environment::appendOrSetPath(const QString &value)
+{
+#ifdef Q_OS_WIN
+ QString sep = ";";
+#else
+ QString sep = ":";
+#endif
+ appendOrSet("PATH", QDir::toNativeSeparators(value), sep);
+}
+
+void Environment::prependOrSetPath(const QString &value)
+{
+#ifdef Q_OS_WIN
+ QString sep = ";";
+#else
+ QString sep = ":";
+#endif
+ prependOrSet("PATH", QDir::toNativeSeparators(value), sep);
+}
+
+Environment Environment::systemEnvironment()
+{
+ return Environment(QProcess::systemEnvironment());
+}
+
+void Environment::clear()
+{
+ m_values.clear();
+}
+
+// currently it returns the string that was passed in, except
+// under windows and if the executable does not end in .exe
+// then it returns executable appended with .exe
+// that is clearly wrong
+QString Environment::searchInPath(QString executable)
+{
+// qDebug()<<"looking for "<<executable<< "in PATH: "<<m_values.value("PATH");
+ if (executable.isEmpty())
+ return QString::null;
+#ifdef Q_OS_WIN
+ if (!executable.endsWith(QLatin1String(".exe")))
+ executable.append(QLatin1String(".exe"));
+#endif
+ const QChar slash = QLatin1Char('/');
+ foreach(const QString &p, path()) {
+// qDebug()<<"trying"<<path + '/' + executable;
+ QString fp = p;
+ fp += slash;
+ fp += executable;
+ const QFileInfo fi(fp);
+ if(fi.exists()) {
+// qDebug()<<"returning "<<fi.absoluteFilePath();
+ return fi.absoluteFilePath();
+ }
+ }
+ return QString::null;
+}
+
+QStringList Environment::path() const
+{
+#ifdef Q_OS_WIN
+ QString sep = ";";
+#else
+ QString sep = ":";
+#endif
+ return m_values.value("PATH").split(sep);
+}
+
+QString Environment::value(const QString &key) const
+{
+ return m_values.value(key);
+}
+
+QString Environment::key(Environment::const_iterator it) const
+{
+ return it.key();
+}
+
+QString Environment::value(Environment::const_iterator it) const
+{
+ return it.value();
+}
+
+Environment::const_iterator Environment::constBegin() const
+{
+ return m_values.constBegin();
+}
+
+Environment::const_iterator Environment::constEnd() const
+{
+ return m_values.constEnd();
+}
+
+Environment::const_iterator Environment::find(const QString &name)
+{
+ QMap<QString, QString>::const_iterator it = m_values.constFind(name);
+ if(it == m_values.constEnd())
+ return constEnd();
+ else
+ return it;
+}
+
+int Environment::size() const
+{
+ return m_values.size();
+}
+
+void Environment::modify(const QList<EnvironmentItem> & list)
+{
+ Environment resultEnvironment = *this;
+ foreach (const EnvironmentItem &item, list) {
+ if(item.unset) {
+ resultEnvironment.unset(item.name);
+ } else {
+ // TODO use variable expansion
+ QString value = item.value;
+ for(int i=0; i < value.size(); ++i) {
+ if(value.at(i) == QLatin1Char('$')) {
+ if((i + 1) < value.size()) {
+ const QChar &c = value.at(i+1);
+ int end = -1;
+ if (c == '(')
+ end = value.indexOf(')', i);
+ else if (c=='{')
+ end = value.indexOf('}', i);
+ if(end != -1) {
+ const QString &name = value.mid(i+2, end-i-2);
+ Environment::const_iterator it = find(name);
+ if(it != constEnd())
+ value.replace(i, end-i+1, it.value());
+ }
+ }
+ }
+ }
+ resultEnvironment.set(item.name, value);
+ }
+ }
+ *this = resultEnvironment;
+}
+
+QStringList Environment::parseCombinedArgString(const QString &program)
+{
+ QStringList args;
+ QString tmp;
+ int quoteCount = 0;
+ bool inQuote = false;
+
+ // handle quoting. tokens can be surrounded by double quotes
+ // "hello world". three consecutive double quotes represent
+ // the quote character itself.
+ for (int i = 0; i < program.size(); ++i) {
+ if (program.at(i) == QLatin1Char('"')) {
+ ++quoteCount;
+ if (quoteCount == 3) {
+ // third consecutive quote
+ quoteCount = 0;
+ tmp += program.at(i);
+ }
+ continue;
+ }
+ if (quoteCount) {
+ if (quoteCount == 1)
+ inQuote = !inQuote;
+ quoteCount = 0;
+ }
+ if (!inQuote && program.at(i).isSpace()) {
+ if (!tmp.isEmpty()) {
+ args += tmp;
+ tmp.clear();
+ }
+ } else {
+ tmp += program.at(i);
+ }
+ }
+ if (!tmp.isEmpty())
+ args += tmp;
+ return args;
+}
+
+QString Environment::joinArgumentList(const QStringList &arguments)
+{
+ QString result;
+ foreach(QString arg, arguments) {
+ if (!result.isEmpty())
+ result += QLatin1Char(' ');
+ arg.replace(QLatin1String("\""), QLatin1String("\"\"\""));
+ if (arg.contains(QLatin1Char(' ')))
+ arg = "\"" + arg + "\"";
+ result += arg;
+ }
+ return result;
+}
+
diff --git a/src/plugins/projectexplorer/environment.h b/src/plugins/projectexplorer/environment.h
new file mode 100644
index 0000000000..0d8c8d4379
--- /dev/null
+++ b/src/plugins/projectexplorer/environment.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ENVIRONMENT
+#define ENVIRONMENT
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QList>
+
+namespace ProjectExplorer {
+
+struct PROJECTEXPLORER_EXPORT EnvironmentItem
+{
+ EnvironmentItem(QString n, QString v)
+ : name(n), value(v), unset(false)
+ {}
+
+ QString name;
+ QString value;
+ bool unset;
+
+ static QList<EnvironmentItem> fromStringList(QStringList list);
+ static QStringList toStringList(QList<EnvironmentItem> list);
+};
+
+class PROJECTEXPLORER_EXPORT Environment {
+public:
+ typedef QMap<QString, QString>::const_iterator const_iterator;
+
+ Environment();
+ explicit Environment(QStringList env);
+ static Environment systemEnvironment();
+
+ QStringList toStringList();
+ QString value(const QString &key) const;
+ void set(const QString &key, const QString &value);
+ void unset(const QString &key);
+ void modify(const QList<EnvironmentItem> & list);
+
+ void appendOrSet(const QString &key, const QString &value, const QString &sep = "");
+ void prependOrSet(const QString &key, const QString &value, const QString &sep = "");
+
+ void appendOrSetPath(const QString &value);
+ void prependOrSetPath(const QString &value);
+
+ void clear();
+ int size() const;
+
+ Environment::const_iterator find(const QString &name);
+ QString key(Environment::const_iterator it) const;
+ QString value(Environment::const_iterator it) const;
+
+ Environment::const_iterator constBegin() const;
+ Environment::const_iterator constEnd() const;
+
+ QString searchInPath(QString executable);
+ QStringList path() const;
+
+ static QStringList parseCombinedArgString(const QString &program);
+ static QString joinArgumentList(const QStringList &arguments);
+
+private:
+ QMap<QString, QString> m_values;
+};
+
+}
+
+#endif
diff --git a/src/plugins/projectexplorer/environmenteditmodel.cpp b/src/plugins/projectexplorer/environmenteditmodel.cpp
new file mode 100644
index 0000000000..eb7f42ebb7
--- /dev/null
+++ b/src/plugins/projectexplorer/environmenteditmodel.cpp
@@ -0,0 +1,421 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "environmenteditmodel.h"
+
+using namespace ProjectExplorer;
+
+EnvironmentModel::EnvironmentModel()
+ : m_mergedEnvironments(false)
+{}
+EnvironmentModel::~EnvironmentModel() {}
+
+QString EnvironmentModel::indexToVariable(const QModelIndex &index) const
+{
+ if(m_mergedEnvironments)
+ return m_resultEnvironment.key(m_resultEnvironment.constBegin() + index.row());
+ else
+ return m_items.at(index.row()).name;
+}
+
+void EnvironmentModel::updateResultEnvironment()
+{
+ m_resultEnvironment = m_baseEnvironment;
+ m_resultEnvironment.modify(m_items);
+ foreach (const EnvironmentItem &item, m_items) {
+ if(item.unset) {
+ m_resultEnvironment.set(item.name, "<UNSET>");
+ }
+ }
+}
+
+void EnvironmentModel::setBaseEnvironment(const ProjectExplorer::Environment &env)
+{
+ m_baseEnvironment = env;
+ updateResultEnvironment();
+ reset();
+}
+
+void EnvironmentModel::setMergedEnvironments(bool b)
+{
+ if(m_mergedEnvironments == b)
+ return;
+ m_mergedEnvironments = b;
+ if(b)
+ updateResultEnvironment();
+ reset();
+}
+
+bool EnvironmentModel::mergedEnvironments()
+{
+ return m_mergedEnvironments;
+}
+
+int EnvironmentModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_mergedEnvironments ? m_resultEnvironment.size() : m_items.count();
+}
+int EnvironmentModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 2;
+}
+
+bool EnvironmentModel::changes(const QString &name) const
+{
+ foreach(const EnvironmentItem& item, m_items) {
+ if(item.name == name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QVariant EnvironmentModel::data(const QModelIndex &index, int role) const
+{
+ if((role == Qt::DisplayRole || role == Qt::EditRole) && index.isValid()) {
+ if((m_mergedEnvironments && index.row() >= m_resultEnvironment.size()) ||
+ (!m_mergedEnvironments && index.row() >= m_items.count())) {
+ return QVariant();
+ }
+
+ if(index.column() == 0) {
+ if(m_mergedEnvironments) {
+ return m_resultEnvironment.key(m_resultEnvironment.constBegin() + index.row());
+ } else {
+ return m_items.at(index.row()).name;
+ }
+ } else if(index.column() == 1) {
+ if(m_mergedEnvironments) {
+ if(role == Qt::EditRole) {
+ int pos = findInChanges(indexToVariable(index));
+ if(pos != -1)
+ return m_items.at(pos).value;
+ }
+ return m_resultEnvironment.value(m_resultEnvironment.constBegin() + index.row());
+ } else {
+ if(m_items.at(index.row()).unset)
+ return "<UNSET>";
+ else
+ return m_items.at(index.row()).value;
+ }
+ }
+ }
+ if(role == Qt::FontRole) {
+ if(m_mergedEnvironments) {
+ // check wheter this environment variable exists in m_items
+ if(changes(m_resultEnvironment.key(m_resultEnvironment.constBegin() + index.row()))) {
+ QFont f;
+ f.setBold(true);
+ return QVariant(f);
+ }
+ }
+ return QFont();
+ }
+ return QVariant();
+}
+
+
+Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const
+{
+ Q_UNUSED(index);
+ return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
+}
+
+bool EnvironmentModel::hasChildren(const QModelIndex &index) const
+{
+ if(!index.isValid())
+ return true;
+ else
+ return false;
+}
+
+QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Vertical || role != Qt::DisplayRole)
+ return QVariant();
+ return section == 0 ? tr("Variable") : tr("Value");
+}
+
+QModelIndex EnvironmentModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if(!parent.isValid())
+ return createIndex(row, column, 0);
+ return QModelIndex();
+}
+
+QModelIndex EnvironmentModel::parent(const QModelIndex &index) const
+{
+ Q_UNUSED(index);
+ return QModelIndex();
+}
+
+/// *****************
+/// Utility functions
+/// *****************
+int EnvironmentModel::findInChanges(const QString &name) const
+{
+ for(int i=0; i<m_items.size(); ++i)
+ if(m_items.at(i).name == name)
+ return i;
+ return -1;
+}
+
+int EnvironmentModel::findInChangesInsertPosition(const QString &name) const
+{
+ for(int i=0; i<m_items.size(); ++i)
+ if(m_items.at(i).name > name)
+ return i;
+ return m_items.size();
+}
+
+int EnvironmentModel::findInResult(const QString &name) const
+{
+ Environment::const_iterator it;
+ int i = 0;
+ for(it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i)
+ if(m_resultEnvironment.key(it) == name)
+ return i;
+ return -1;
+}
+
+int EnvironmentModel::findInResultInsertPosition(const QString &name) const
+{
+ Environment::const_iterator it;
+ int i = 0;
+ for(it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i)
+ if(m_resultEnvironment.key(it) > name)
+ return i;
+ return m_resultEnvironment.size();
+}
+
+bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if(role == Qt::EditRole && index.isValid()) {
+ if(index.column() == 0) {
+ //fail if a variable with the same name already exists
+#ifdef Q_OS_WIN
+ if(findInChanges(value.toString().toUpper()) != -1)
+ return false;
+#else
+ if(findInChanges(value.toString()) != -1)
+ return false;
+#endif
+ EnvironmentItem old("", "");
+ if(m_mergedEnvironments) {
+ int pos = findInChanges(indexToVariable(index));
+ if(pos != -1) {
+ old = m_items.at(pos);
+ } else {
+ old.name = m_resultEnvironment.key(m_resultEnvironment.constBegin() + index.row());
+ old.value = m_resultEnvironment.value(m_resultEnvironment.constBegin() + index.row());
+ old.unset = false;
+ }
+ } else {
+ old = m_items.at(index.row());
+ }
+#ifdef Q_OS_WIN
+ const QString &newName = value.toString().toUpper();
+#else
+ const QString &newName = value.toString();
+#endif
+ if(changes(old.name))
+ removeVariable(old.name);
+ old.name = newName;
+ addVariable(old);
+ return true;
+ } else if(index.column() == 1) {
+ if(m_mergedEnvironments) {
+ const QString &name = indexToVariable(index);
+ int pos = findInChanges(name);
+ if(pos != -1) {
+ m_items[pos].value = value.toString();
+ m_items[pos].unset = false;
+ updateResultEnvironment();
+ emit dataChanged(index, index);
+ emit userChangesUpdated();
+ return true;
+ }
+ // not found in m_items, so add it as a new variable
+ addVariable(EnvironmentItem(name, value.toString()));
+ return true;
+ } else {
+ m_items[index.row()].value = value.toString();
+ m_items[index.row()].unset = false;
+ emit dataChanged(index, index);
+ emit userChangesUpdated();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+QModelIndex EnvironmentModel::addVariable()
+{
+ const QString &name = "<VARIABLE>";
+ if(m_mergedEnvironments) {
+ int i = findInResult(name);
+ if(i != -1)
+ return index(i, 0, QModelIndex());
+ } else {
+ int i = findInChanges(name);
+ if(i != -1)
+ return index(i, 0, QModelIndex());
+ }
+ // Don't exist, really add them
+ return addVariable(EnvironmentItem(name, "<VALUE>"));
+}
+
+QModelIndex EnvironmentModel::addVariable(const EnvironmentItem &item)
+{
+ if(m_mergedEnvironments) {
+ bool existsInBaseEnvironment = (m_baseEnvironment.find(item.name) != m_baseEnvironment.constEnd());
+ int rowInResult;
+ if(existsInBaseEnvironment)
+ rowInResult = findInResult(item.name);
+ else
+ rowInResult = findInResultInsertPosition(item.name);
+ int rowInChanges = findInChangesInsertPosition(item.name);
+
+ qDebug()<<"addVariable "<<item.name<<existsInBaseEnvironment<<rowInResult<<rowInChanges;
+
+ if(existsInBaseEnvironment) {
+ m_items.insert(rowInChanges, item);
+ updateResultEnvironment();
+ emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex()));
+ emit userChangesUpdated();
+ return index(rowInResult, 0, QModelIndex());
+ } else {
+ beginInsertRows(QModelIndex(), rowInResult, rowInResult);
+ m_items.insert(rowInChanges, item);
+ updateResultEnvironment();
+ endInsertRows();
+ qDebug()<<"returning index: "<<rowInResult;
+ emit userChangesUpdated();
+ return index(rowInResult, 0, QModelIndex());
+ }
+ } else {
+ int newPos = findInChangesInsertPosition(item.name);
+ beginInsertRows(QModelIndex(), newPos, newPos);
+ m_items.insert(newPos, item);
+ endInsertRows();
+ emit userChangesUpdated();
+ return index(newPos, 0, QModelIndex());
+ }
+}
+
+void EnvironmentModel::removeVariable(const QString &name)
+{
+ if(m_mergedEnvironments) {
+ int rowInResult = findInResult(name);
+ int rowInChanges = findInChanges(name);
+ bool existsInBaseEnvironment = m_baseEnvironment.find(name) != m_baseEnvironment.constEnd();
+ if(existsInBaseEnvironment) {
+ m_items.removeAt(rowInChanges);
+ updateResultEnvironment();
+ emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex()));
+ emit userChangesUpdated();
+ } else {
+ beginRemoveRows(QModelIndex(), rowInResult, rowInResult);
+ m_items.removeAt(rowInChanges);
+ updateResultEnvironment();
+ endRemoveRows();
+ emit userChangesUpdated();
+ }
+ } else {
+ int removePos = findInChanges(name);
+ beginRemoveRows(QModelIndex(), removePos, removePos);
+ m_items.removeAt(removePos);
+ updateResultEnvironment();
+ endRemoveRows();
+ emit userChangesUpdated();
+ }
+}
+
+void EnvironmentModel::unset(const QString &name)
+{
+ if(m_mergedEnvironments) {
+ int row = findInResult(name);
+ // look in m_items for the variable
+ int pos = findInChanges(name);
+ if(pos != -1) {
+ m_items[pos].unset = true;
+ updateResultEnvironment();
+ emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
+ emit userChangesUpdated();
+ return;
+ }
+ pos = findInChangesInsertPosition(name);
+ m_items.insert(pos, EnvironmentItem(name, ""));
+ m_items[pos].unset = true;
+ updateResultEnvironment();
+ emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
+ emit userChangesUpdated();
+ return;
+ } else {
+ int pos = findInChanges(name);
+ m_items[pos].unset = true;
+ emit dataChanged(index(pos, 1, QModelIndex()), index(pos, 1, QModelIndex()));
+ emit userChangesUpdated();
+ return;
+ }
+}
+
+bool EnvironmentModel::isUnset(const QString &name)
+{
+ int pos = findInChanges(name);
+ if(pos != -1)
+ return m_items.at(pos).unset;
+ else
+ return false;
+}
+
+bool EnvironmentModel::isInBaseEnvironment(const QString &name)
+{
+ return m_baseEnvironment.find(name) != m_baseEnvironment.constEnd();
+}
+
+QList<EnvironmentItem> EnvironmentModel::userChanges() const
+{
+ return m_items;
+}
+
+void EnvironmentModel::setUserChanges(QList<EnvironmentItem> list)
+{
+ m_items = list;
+ updateResultEnvironment();
+ emit reset();
+}
diff --git a/src/plugins/projectexplorer/environmenteditmodel.h b/src/plugins/projectexplorer/environmenteditmodel.h
new file mode 100644
index 0000000000..35762dd0d2
--- /dev/null
+++ b/src/plugins/projectexplorer/environmenteditmodel.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ENVIRONMENTEDITMODEL_H
+#define ENVIRONMENTEDITMODEL_H
+
+#include "environment.h"
+
+#include <QtCore/QString>
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QDebug>
+#include <QtGui/QFont>
+
+namespace ProjectExplorer
+{
+
+class PROJECTEXPLORER_EXPORT EnvironmentModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ EnvironmentModel();
+ ~EnvironmentModel();
+ void setBaseEnvironment(const ProjectExplorer::Environment &env);
+ void setMergedEnvironments(bool b);
+ bool mergedEnvironments();
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool hasChildren(const QModelIndex &index) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ QModelIndex addVariable();
+ QModelIndex addVariable(const EnvironmentItem& item);
+ void removeVariable(const QString &name);
+ void unset(const QString &name);
+ bool isUnset(const QString &name);
+ bool isInBaseEnvironment(const QString &name);
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QString indexToVariable(const QModelIndex &index) const;
+ bool changes(const QString &key) const;
+
+ QList<EnvironmentItem> userChanges() const;
+ void setUserChanges(QList<EnvironmentItem> list);
+signals:
+ void userChangesUpdated();
+private:
+ void updateResultEnvironment();
+ int findInChanges(const QString &name) const;
+ int findInResult(const QString &name) const;
+ int findInChangesInsertPosition(const QString &name) const;
+ int findInResultInsertPosition(const QString &name) const;
+
+ ProjectExplorer::Environment m_baseEnvironment;
+ ProjectExplorer::Environment m_resultEnvironment;
+ QList<EnvironmentItem> m_items;
+ bool m_mergedEnvironments;
+};
+
+}
+#endif // ENVIRONMENTEDITMODEL_H
diff --git a/src/plugins/projectexplorer/foldernavigationwidget.cpp b/src/plugins/projectexplorer/foldernavigationwidget.cpp
new file mode 100644
index 0000000000..8066c5899d
--- /dev/null
+++ b/src/plugins/projectexplorer/foldernavigationwidget.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "foldernavigationwidget.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <utils/pathchooser.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QToolButton>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+namespace {
+bool debug = false;
+}
+
+namespace ProjectExplorer {
+ namespace Internal {
+ class FirstRowFilter : public QSortFilterProxyModel {
+ Q_OBJECT
+ public:
+ FirstRowFilter(QObject *parent = 0) : QSortFilterProxyModel(parent) {}
+ protected:
+ bool filterAcceptsRow (int source_row, const QModelIndex & ) const {
+ return source_row != 0;
+ }
+ };
+ }
+}
+
+/*!
+ /class FolderNavigationWidget
+
+ Shows a file system folder
+ */
+FolderNavigationWidget::FolderNavigationWidget(Core::ICore *core, QWidget *parent)
+ : QWidget(parent),
+ m_core(core),
+ m_explorer(ProjectExplorerPlugin::instance()),
+ m_view(new QListView(this)),
+ m_dirModel(new QDirModel(this)),
+ m_filter(new FirstRowFilter(this)),
+ m_title(new QLabel(this)),
+ m_autoSync(false)
+{
+ m_dirModel->setFilter(QDir::Dirs | QDir::Files | QDir::Drives | QDir::Readable | QDir::Writable
+ | QDir::Executable | QDir::Hidden);
+ m_dirModel->setSorting(QDir::Name | QDir::DirsFirst);
+ m_filter->setSourceModel(m_dirModel);
+ m_view->setModel(m_filter);
+ m_view->setFrameStyle(QFrame::NoFrame);
+ setFocusProxy(m_view);
+
+ QVBoxLayout *layout = new QVBoxLayout();
+ layout->addWidget(m_title);
+ layout->addWidget(m_view);
+ m_title->setMargin(5);
+ layout->setSpacing(0);
+ layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(layout);
+
+ // connections
+ connect(m_view, SIGNAL(activated(const QModelIndex&)),
+ this, SLOT(openItem(const QModelIndex&)));
+
+ setAutoSynchronization(true);
+}
+
+void FolderNavigationWidget::toggleAutoSynchronization()
+{
+ setAutoSynchronization(!m_autoSync);
+}
+
+bool FolderNavigationWidget::autoSynchronization() const
+{
+ return m_autoSync;
+}
+
+void FolderNavigationWidget::setAutoSynchronization(bool sync)
+{
+ if (sync == m_autoSync)
+ return;
+
+ m_autoSync = sync;
+
+ Core::FileManager *fileManager = m_core->fileManager();
+ if (m_autoSync) {
+ connect(fileManager, SIGNAL(currentFileChanged(const QString&)),
+ this, SLOT(setCurrentFile(const QString&)));
+ setCurrentFile(fileManager->currentFile());
+ } else {
+ disconnect(fileManager, SIGNAL(currentFileChanged(const QString&)),
+ this, SLOT(setCurrentFile(const QString&)));
+ }
+}
+
+void FolderNavigationWidget::setCurrentFile(const QString &filePath)
+{
+ if (debug)
+ qDebug() << "FolderNavigationWidget::setCurrentFile(" << filePath << ")";
+
+ QString dir = QFileInfo(filePath).path();
+ if (dir.isEmpty())
+ dir = Core::Utils::PathChooser::homePath();
+
+ QModelIndex dirIndex = m_dirModel->index(dir);
+ QModelIndex fileIndex = m_dirModel->index(filePath);
+
+ m_view->setRootIndex(m_filter->mapFromSource(dirIndex));
+ if (dirIndex.isValid()) {
+ setCurrentTitle(QDir(m_dirModel->filePath(dirIndex)));
+ if (fileIndex.isValid()) {
+ QItemSelectionModel *selections = m_view->selectionModel();
+ QModelIndex mainIndex = m_filter->mapFromSource(fileIndex);
+ selections->setCurrentIndex(mainIndex, QItemSelectionModel::SelectCurrent
+ | QItemSelectionModel::Clear);
+ m_view->scrollTo(mainIndex);
+ }
+ } else {
+ setCurrentTitle(QDir());
+ }
+}
+
+void FolderNavigationWidget::openItem(const QModelIndex &index)
+{
+ if (index.isValid()) {
+ const QModelIndex srcIndex = m_filter->mapToSource(index);
+ if (m_dirModel->isDir(srcIndex)) {
+ m_view->setRootIndex(index);
+ setCurrentTitle(QDir(m_dirModel->filePath(srcIndex)));
+ } else {
+ const QString filePath = m_dirModel->filePath(srcIndex);
+ m_core->editorManager()->openEditor(filePath);
+ m_core->editorManager()->ensureEditorManagerVisible();
+ }
+ }
+}
+
+void FolderNavigationWidget::setCurrentTitle(const QDir &dir)
+{
+ m_title->setText(dir.dirName());
+ m_title->setToolTip(dir.absolutePath());
+}
+
+FolderNavigationWidgetFactory::FolderNavigationWidgetFactory(Core::ICore *core)
+ : m_core(core)
+{
+}
+
+FolderNavigationWidgetFactory::~FolderNavigationWidgetFactory()
+{
+}
+
+QString FolderNavigationWidgetFactory::displayName()
+{
+ return tr("File System");
+}
+
+QKeySequence FolderNavigationWidgetFactory::activationSequence()
+{
+ return QKeySequence(Qt::ALT + Qt::Key_Y);
+}
+
+Core::NavigationView FolderNavigationWidgetFactory::createWidget()
+{
+ Core::NavigationView n;
+ FolderNavigationWidget *ptw = new FolderNavigationWidget(m_core);
+ n.widget = ptw;
+ QToolButton *toggleSync = new QToolButton;
+ toggleSync->setProperty("type", "dockbutton");
+ toggleSync->setIcon(QIcon(":/qworkbench/images/linkicon.png"));
+ toggleSync->setCheckable(true);
+ toggleSync->setChecked(ptw->autoSynchronization());
+ toggleSync->setToolTip(tr("Synchronize with Editor"));
+ connect(toggleSync, SIGNAL(clicked(bool)), ptw, SLOT(toggleAutoSynchronization()));
+ n.doockToolBarWidgets << toggleSync;
+ return n;
+}
+
+#include "foldernavigationwidget.moc"
diff --git a/src/plugins/projectexplorer/foldernavigationwidget.h b/src/plugins/projectexplorer/foldernavigationwidget.h
new file mode 100644
index 0000000000..84909776e2
--- /dev/null
+++ b/src/plugins/projectexplorer/foldernavigationwidget.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FOLDERNAVIGATIONWIDGET_H
+#define FOLDERNAVIGATIONWIDGET_H
+
+#include <coreplugin/inavigationwidgetfactory.h>
+
+#include <QtGui/QWidget>
+#include <QtGui/QListView>
+#include <QtGui/QDirModel>
+#include <QtGui/QLabel>
+#include <QtGui/QSortFilterProxyModel>
+
+namespace Core {
+class ICore;
+}
+
+namespace ProjectExplorer {
+
+class ProjectExplorerPlugin;
+class Project;
+class Node;
+
+namespace Internal {
+
+class FolderNavigationWidget : public QWidget {
+ Q_OBJECT
+public:
+ FolderNavigationWidget(Core::ICore *core, QWidget *parent = 0);
+
+ bool autoSynchronization() const;
+ void setAutoSynchronization(bool sync);
+
+ QString currentFolder() const;
+
+public slots:
+ void toggleAutoSynchronization();
+
+private slots:
+ void openItem(const QModelIndex &mainIndex);
+ void setCurrentFile(const QString &filePath);
+
+private:
+ void setCurrentTitle(const QDir &directory);
+
+ Core::ICore *m_core;
+ ProjectExplorerPlugin *m_explorer;
+ QListView *m_view;
+ QDirModel *m_dirModel;
+ QSortFilterProxyModel *m_filter;
+ QLabel *m_title;
+ bool m_autoSync;
+};
+
+class FolderNavigationWidgetFactory : public Core::INavigationWidgetFactory
+{
+public:
+ FolderNavigationWidgetFactory(Core::ICore *core);
+ virtual ~FolderNavigationWidgetFactory();
+
+ virtual QString displayName();
+ virtual QKeySequence activationSequence();
+ virtual Core::NavigationView createWidget();
+private:
+ Core::ICore *m_core;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // FOLDERNAVIGATIONWIDGET_H
diff --git a/src/plugins/projectexplorer/images/build.png b/src/plugins/projectexplorer/images/build.png
new file mode 100644
index 0000000000..4b79d9d470
--- /dev/null
+++ b/src/plugins/projectexplorer/images/build.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/build_small.png b/src/plugins/projectexplorer/images/build_small.png
new file mode 100644
index 0000000000..e5a0e8a4e7
--- /dev/null
+++ b/src/plugins/projectexplorer/images/build_small.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/clean.png b/src/plugins/projectexplorer/images/clean.png
new file mode 100644
index 0000000000..ab5e07ef79
--- /dev/null
+++ b/src/plugins/projectexplorer/images/clean.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/clean_small.png b/src/plugins/projectexplorer/images/clean_small.png
new file mode 100644
index 0000000000..6a6d16718c
--- /dev/null
+++ b/src/plugins/projectexplorer/images/clean_small.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/closetab.png b/src/plugins/projectexplorer/images/closetab.png
new file mode 100644
index 0000000000..ef9e02086c
--- /dev/null
+++ b/src/plugins/projectexplorer/images/closetab.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/compile_error.png b/src/plugins/projectexplorer/images/compile_error.png
new file mode 100644
index 0000000000..162072e58d
--- /dev/null
+++ b/src/plugins/projectexplorer/images/compile_error.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/compile_unspecified.png b/src/plugins/projectexplorer/images/compile_unspecified.png
new file mode 100644
index 0000000000..c9e8b7fb0e
--- /dev/null
+++ b/src/plugins/projectexplorer/images/compile_unspecified.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/compile_warning.png b/src/plugins/projectexplorer/images/compile_warning.png
new file mode 100644
index 0000000000..a42077a82a
--- /dev/null
+++ b/src/plugins/projectexplorer/images/compile_warning.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/debugger_start.png b/src/plugins/projectexplorer/images/debugger_start.png
new file mode 100644
index 0000000000..36e5fc4780
--- /dev/null
+++ b/src/plugins/projectexplorer/images/debugger_start.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/debugger_start_small.png b/src/plugins/projectexplorer/images/debugger_start_small.png
new file mode 100644
index 0000000000..98e8ccd001
--- /dev/null
+++ b/src/plugins/projectexplorer/images/debugger_start_small.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/filtericon.png b/src/plugins/projectexplorer/images/filtericon.png
new file mode 100644
index 0000000000..7e46d22675
--- /dev/null
+++ b/src/plugins/projectexplorer/images/filtericon.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/findallprojects.png b/src/plugins/projectexplorer/images/findallprojects.png
new file mode 100644
index 0000000000..1847aebe0f
--- /dev/null
+++ b/src/plugins/projectexplorer/images/findallprojects.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/findproject.png b/src/plugins/projectexplorer/images/findproject.png
new file mode 100644
index 0000000000..ec7c39e8e6
--- /dev/null
+++ b/src/plugins/projectexplorer/images/findproject.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/insert_line_small.png b/src/plugins/projectexplorer/images/insert_line_small.png
new file mode 100644
index 0000000000..e80f06089f
--- /dev/null
+++ b/src/plugins/projectexplorer/images/insert_line_small.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/projectexplorer.png b/src/plugins/projectexplorer/images/projectexplorer.png
new file mode 100644
index 0000000000..a84f2536f3
--- /dev/null
+++ b/src/plugins/projectexplorer/images/projectexplorer.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/rebuild.png b/src/plugins/projectexplorer/images/rebuild.png
new file mode 100644
index 0000000000..fe3a6504a3
--- /dev/null
+++ b/src/plugins/projectexplorer/images/rebuild.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/rebuild_small.png b/src/plugins/projectexplorer/images/rebuild_small.png
new file mode 100644
index 0000000000..3b36d527b2
--- /dev/null
+++ b/src/plugins/projectexplorer/images/rebuild_small.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/run.png b/src/plugins/projectexplorer/images/run.png
new file mode 100644
index 0000000000..046a8e3db9
--- /dev/null
+++ b/src/plugins/projectexplorer/images/run.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/run_small.png b/src/plugins/projectexplorer/images/run_small.png
new file mode 100644
index 0000000000..940af831f8
--- /dev/null
+++ b/src/plugins/projectexplorer/images/run_small.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/session.png b/src/plugins/projectexplorer/images/session.png
new file mode 100644
index 0000000000..6d526f6bee
--- /dev/null
+++ b/src/plugins/projectexplorer/images/session.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/stop.png b/src/plugins/projectexplorer/images/stop.png
new file mode 100644
index 0000000000..5a9f49c1c6
--- /dev/null
+++ b/src/plugins/projectexplorer/images/stop.png
Binary files differ
diff --git a/src/plugins/projectexplorer/iprojectmanager.h b/src/plugins/projectexplorer/iprojectmanager.h
new file mode 100644
index 0000000000..869e5d2b8f
--- /dev/null
+++ b/src/plugins/projectexplorer/iprojectmanager.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTMANAGERINTERFACE_H
+#define PROJECTMANAGERINTERFACE_H
+
+#include "projectexplorer_export.h"
+#include <QtCore/QObject>
+
+namespace ProjectExplorer {
+
+class Project;
+
+class PROJECTEXPLORER_EXPORT IProjectManager
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ IProjectManager() {}
+
+ virtual int projectContext() const = 0; //TODO move into project
+ virtual int projectLanguage() const = 0; //TODO move into project
+
+ virtual QString mimeType() const = 0;
+ virtual Project *openProject(const QString &fileName) = 0;
+};
+
+} // namespace ProjectExplorer
+
+#endif //PROJECTMANAGERINTERFACE_H
diff --git a/src/plugins/projectexplorer/iprojectproperties.h b/src/plugins/projectexplorer/iprojectproperties.h
new file mode 100644
index 0000000000..3a8d2e8609
--- /dev/null
+++ b/src/plugins/projectexplorer/iprojectproperties.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IPROJECTPROPERTIES_H
+#define IPROJECTPROPERTIES_H
+
+#include "projectexplorer_export.h"
+#include "project.h"
+
+#include <coreplugin/icontext.h>
+
+#include <QtGui/QWidget>
+
+namespace ProjectExplorer {
+
+class PropertiesPanel;
+
+class PROJECTEXPLORER_EXPORT IPanelFactory : public QObject
+{
+ Q_OBJECT
+public:
+ virtual bool supports(Project *project) = 0;
+ virtual PropertiesPanel *createPanel(Project *project) = 0;
+};
+
+class PROJECTEXPLORER_EXPORT PropertiesPanel : public Core::IContext
+{
+ Q_OBJECT
+public:
+ virtual void finish() {};
+ virtual QString name() const = 0;
+
+ // IContext
+ virtual QList<int> context() const { return QList<int>(); }
+};
+
+} // namespace ProjectExplorer
+
+#endif // IPROJECTPROPERTIES_H
diff --git a/src/plugins/projectexplorer/metatypedeclarations.h b/src/plugins/projectexplorer/metatypedeclarations.h
new file mode 100644
index 0000000000..a53c4203af
--- /dev/null
+++ b/src/plugins/projectexplorer/metatypedeclarations.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTEXPLORERMETATYPEDECLARATIONS_H
+#define PROJECTEXPLORERMETATYPEDECLARATIONS_H
+
+#include <QtCore/QMetaType>
+#include <QtCore/QList>
+
+namespace QWorkbench {
+class FileInterface;
+}
+namespace ProjectExplorer {
+class ProjectInterface;
+class IProjectManager;
+class SessionManager;
+class IApplicationOutput;
+class BuildParserInterface;
+class GlobalConfigManagerInterface;
+
+namespace Internal {
+class CommandQObject;
+}
+}
+
+Q_DECLARE_METATYPE(QWorkbench::FileInterface*)
+Q_DECLARE_METATYPE(QList<QWorkbench::FileInterface*>)
+
+Q_DECLARE_METATYPE(ProjectExplorer::Project*)
+Q_DECLARE_METATYPE(QList<ProjectExplorer::Project*>)
+Q_DECLARE_METATYPE(ProjectExplorer::SessionManager*)
+Q_DECLARE_METATYPE(ProjectExplorer::IProjectManager*)
+Q_DECLARE_METATYPE(ProjectExplorer::IApplicationOutput*)
+Q_DECLARE_METATYPE(ProjectExplorer::Internal::CommandQObject*)
+Q_DECLARE_METATYPE(QList<ProjectExplorer::Internal::CommandQObject*>)
+Q_DECLARE_METATYPE(ProjectExplorer::BuildParserInterface*)
+Q_DECLARE_METATYPE(ProjectExplorer::GlobalConfigManagerInterface*)
+#endif // PROJECTEXPLORERMETATYPEDECLARATIONS_H
diff --git a/src/plugins/projectexplorer/nodesvisitor.cpp b/src/plugins/projectexplorer/nodesvisitor.cpp
new file mode 100644
index 0000000000..1997eda309
--- /dev/null
+++ b/src/plugins/projectexplorer/nodesvisitor.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "nodesvisitor.h"
+#include "projectnodes.h"
+
+using namespace ProjectExplorer;
+
+/*!
+ \class NodesVisitor
+
+ \short Base class for visitors that can be used to traverse a node hierarchy.
+
+ The class follows the visitor pattern as described in Gamma et al. Pass
+ an instance of NodesVisitor to FolderNode::accept(): The visit methods
+ will be called for each node in the subtree, except for file nodes:
+ Access these through FolderNode::fileNodes() in visitProjectNode()
+ and visitoFolderNode().
+*/
+
+/*!
+ \method NodesVisitor::visitSessionNode(SessionNode *)
+
+ Called for the root session node.
+
+ The default implementation does nothing.
+ */
+
+/*!
+ \method NodesVisitor::visitProjectNode(SessionNode *)
+
+ Called for a project node.
+
+ The default implementation does nothing.
+ */
+
+/*!
+ \method NodesVisitor::visitFolderNode(SessionNode *)
+
+ Called for a folder node that is _not_ a SessionNode or a ProjectNode.
+
+ The default implementation does nothing.
+ */
+
+
+/*!
+ \class FindNodeForFileVisitor
+
+ Searches the first node that has the given file as it's path.
+ */
+
+FindNodesForFileVisitor::FindNodesForFileVisitor(const QString &fileToSearch)
+ : m_path(fileToSearch)
+{
+}
+
+QList<Node*> FindNodesForFileVisitor::nodes() const
+{
+ return m_nodes;
+}
+
+void FindNodesForFileVisitor::visitProjectNode(ProjectNode *node)
+{
+ visitFolderNode(node);
+}
+
+void FindNodesForFileVisitor::visitFolderNode(FolderNode *node)
+{
+ if (node->path() == m_path) {
+ m_nodes << node;
+ }
+ foreach (FileNode *fileNode, node->fileNodes()) {
+ if (fileNode->path() == m_path) {
+ m_nodes << fileNode;
+ }
+ }
+}
+
+/*!
+ \class FindAllFilesVisitor
+
+ Collects file information from all sub file nodes.
+ */
+
+QStringList FindAllFilesVisitor::filePaths() const
+{
+ return m_filePaths;
+}
+
+void FindAllFilesVisitor::visitProjectNode(ProjectNode *projectNode)
+{
+ visitFolderNode(projectNode);
+}
+
+void FindAllFilesVisitor::visitFolderNode(FolderNode *folderNode)
+{
+ m_filePaths.append(folderNode->path());
+ foreach (const FileNode *fileNode, folderNode->fileNodes())
+ m_filePaths.append(fileNode->path());
+}
diff --git a/src/plugins/projectexplorer/nodesvisitor.h b/src/plugins/projectexplorer/nodesvisitor.h
new file mode 100644
index 0000000000..814ed42d9b
--- /dev/null
+++ b/src/plugins/projectexplorer/nodesvisitor.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef NODESVISITOR_H
+#define NODESVISITOR_H
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+namespace ProjectExplorer {
+
+class Node;
+class FileNode;
+class SessionNode;
+class ProjectNode;
+class FolderNode;
+
+class NodesVisitor {
+public:
+ virtual ~NodesVisitor() {}
+
+ virtual void visitSessionNode(SessionNode *) {}
+ virtual void visitProjectNode(ProjectNode *) {}
+ virtual void visitFolderNode(FolderNode *) {}
+protected:
+ NodesVisitor() {}
+};
+
+/* useful visitors */
+
+class PROJECTEXPLORER_EXPORT FindNodesForFileVisitor : public NodesVisitor {
+public:
+ FindNodesForFileVisitor(const QString &fileToSearch);
+
+ QList<Node*> nodes() const;
+
+ void visitProjectNode(ProjectNode *node);
+ void visitFolderNode(FolderNode *node);
+private:
+ QString m_path;
+ QList<Node*> m_nodes;
+};
+
+class PROJECTEXPLORER_EXPORT FindAllFilesVisitor : public NodesVisitor {
+public:
+ QStringList filePaths() const;
+
+ void visitProjectNode(ProjectNode *projectNode);
+ void visitFolderNode(FolderNode *folderNode);
+private:
+ QStringList m_filePaths;
+};
+
+}
+
+#endif // NODESVISITOR_H
diff --git a/src/plugins/projectexplorer/outputwindow.cpp b/src/plugins/projectexplorer/outputwindow.cpp
new file mode 100644
index 0000000000..891b882277
--- /dev/null
+++ b/src/plugins/projectexplorer/outputwindow.cpp
@@ -0,0 +1,680 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "outputwindow.h"
+#include "projectexplorerconstants.h"
+#include "runconfiguration.h"
+
+#include <find/basetextfind.h>
+#include <aggregation/aggregate.h>
+
+#include <QtGui/QIcon>
+#include <QtGui/QScrollBar>
+#include <QtGui/QTextLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QTabWidget>
+
+using namespace ProjectExplorer::Internal;
+using namespace ProjectExplorer;
+
+bool OutputPane::hasFocus()
+{
+ return m_tabWidget->currentWidget() && m_tabWidget->currentWidget()->hasFocus();
+}
+
+bool OutputPane::canFocus()
+{
+ return m_tabWidget->currentWidget();
+}
+
+void OutputPane::setFocus()
+{
+ if(m_tabWidget->currentWidget())
+ m_tabWidget->currentWidget()->setFocus();
+}
+
+void OutputPane::appendOutput(const QString &/*out*/)
+{
+ // This function is in the interface, since we can't do anything sensible here, we don't do anything here.
+}
+
+void OutputPane::appendOutput(RunControl *rc, const QString &out)
+{
+ OutputWindow *ow = m_outputWindows.value(rc);
+ ow->appendOutput(out);
+}
+
+void OutputPane::showTabFor(RunControl *rc)
+{
+ OutputWindow *ow = m_outputWindows.value(rc);
+ m_tabWidget->setCurrentWidget(ow);
+}
+
+void OutputPane::stopRunControl()
+{
+ RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
+ rc->stop();
+}
+
+void OutputPane::reRunRunControl()
+{
+ RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
+ if (rc->runConfiguration()->project() != 0)
+ rc->start();
+}
+
+void OutputPane::closeTab(int index)
+{
+ OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
+ RunControl *rc = m_outputWindows.key(ow);
+
+ if (rc->isRunning()) {
+ QString msg = tr("The application is still running. Close it first.");
+ QMessageBox::critical(0, tr("Unable to close"), msg);
+ return;
+ }
+
+ m_tabWidget->removeTab(index);
+ delete ow;
+ delete rc;
+}
+
+OutputPane::OutputPane()
+ : m_mainWidget(new QWidget)
+{
+// m_insertLineButton = new QToolButton;
+// m_insertLineButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_INSERT_LINE));
+// m_insertLineButton->setText(tr("Insert line"));
+// m_insertLineButton->setToolTip(tr("Insert line"));
+// m_insertLineButton->setAutoRaise(true);
+// connect(m_insertLineButton, SIGNAL(clicked()), this, SLOT(insertLine()));
+
+ QIcon runIcon(Constants::ICON_RUN);
+ runIcon.addFile(Constants::ICON_RUN_SMALL);
+
+ //Rerun
+ m_reRunButton = new QToolButton;
+ m_reRunButton->setIcon(runIcon);
+ m_reRunButton->setToolTip(tr("Rerun this runconfiguration"));
+ m_reRunButton->setAutoRaise(true);
+ m_reRunButton->setEnabled(false);
+ connect(m_reRunButton, SIGNAL(clicked()),
+ this, SLOT(reRunRunControl()));
+
+ //Stop
+ m_stopButton = new QToolButton;
+ m_stopButton->setIcon(QIcon(Constants::ICON_STOP));
+ m_stopButton->setToolTip(tr("Stop"));
+ m_stopButton->setAutoRaise(true);
+ m_stopButton->setEnabled(false);
+ connect(m_stopButton, SIGNAL(clicked()),
+ this, SLOT(stopRunControl()));
+
+ // Spacer (?)
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ m_tabWidget = new QTabWidget;
+ m_tabWidget->setDocumentMode(true);
+ m_tabWidget->setTabsClosable(true);
+ m_tabWidget->setMovable(true);
+ connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
+ layout->addWidget(m_tabWidget);
+
+ connect(m_tabWidget, SIGNAL(currentChanged(int)),
+ this, SLOT(tabChanged(int)));
+
+ m_mainWidget->setLayout(layout);
+}
+
+OutputPane::~OutputPane()
+{
+ while (m_tabWidget->count()) {
+ RunControl *rc = runControlForTab(0);
+ if (rc->isRunning())
+ rc->stop();
+ closeTab(0);
+ }
+ delete m_mainWidget;
+}
+
+void OutputPane::projectRemoved()
+{
+ tabChanged(m_tabWidget->currentIndex());
+}
+
+void OutputPane::tabChanged(int i)
+{
+ if (i == -1) {
+ m_stopButton->setEnabled(false);
+ m_reRunButton->setEnabled(false);
+ } else {
+ RunControl *rc = runControlForTab(i);
+ m_stopButton->setEnabled(rc->isRunning());
+ m_reRunButton->setEnabled(!rc->isRunning() && rc->runConfiguration()->project());
+ }
+}
+
+void OutputPane::createNewOutputWindow(RunControl *rc)
+{
+ connect(rc, SIGNAL(started()),
+ this, SLOT(runControlStarted()));
+ connect(rc, SIGNAL(finished()),
+ this, SLOT(runControlFinished()));
+
+ // First look if we can reuse a tab
+ bool found = false;
+ for(int i=0; i<m_tabWidget->count(); ++i) {
+ RunControl *old = runControlForTab(i);
+ if (old->runConfiguration() == rc->runConfiguration() && !old->isRunning()) {
+ // Reuse this tab
+ delete old;
+ m_outputWindows.remove(old);
+ OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(i));
+ ow->appendOutput("");//New line
+ m_outputWindows.insert(rc, ow);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ OutputWindow *ow = new OutputWindow(m_tabWidget);
+ Aggregation::Aggregate *agg = new Aggregation::Aggregate;
+ agg->add(ow);
+ agg->add(new Find::BaseTextFind(ow));
+ m_outputWindows.insert(rc, ow);
+ m_tabWidget->addTab(ow, rc->runConfiguration()->name());
+ }
+}
+
+void OutputPane::runControlStarted()
+{
+ RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
+ if (rc == qobject_cast<RunControl *>(sender())) {
+ m_reRunButton->setEnabled(false);
+ m_stopButton->setEnabled(true);
+ }
+}
+
+void OutputPane::runControlFinished()
+{
+ RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
+ if (rc == qobject_cast<RunControl *>(sender())) {
+ m_reRunButton->setEnabled(rc->runConfiguration()->project());
+ m_stopButton->setEnabled(false);
+ }
+}
+
+QWidget *OutputPane::outputWidget(QWidget *)
+{
+ return m_mainWidget;
+}
+
+QList<QWidget*> OutputPane::toolBarWidgets(void) const
+{
+ return QList<QWidget*>() << m_reRunButton << m_stopButton
+ ; // << m_insertLineButton;
+}
+
+QString OutputPane::name() const
+{
+ return tr("Application Output");
+}
+
+void OutputPane::clearContents()
+{
+ OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
+ if (currentWindow)
+ currentWindow->clear();
+}
+
+void OutputPane::visibilityChanged(bool /* b */)
+{
+
+}
+
+void OutputPane::insertLine()
+{
+ OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
+ if (currentWindow)
+ currentWindow->clear();
+}
+
+RunControl* OutputPane::runControlForTab(int index) const
+{
+ return m_outputWindows.key(qobject_cast<OutputWindow *>(m_tabWidget->widget(index)));
+}
+
+int OutputPane::priorityInStatusBar() const
+{
+ return 60;
+}
+
+
+/*******************/
+
+OutputWindow::OutputWindow(QWidget *parent)
+ : QPlainTextEdit(parent)
+{
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ //setCenterOnScroll(false);
+ //setMaximumBlockCount(10000);
+ setWindowTitle(tr("Application Output Window"));
+ setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
+ setFrameShape(QFrame::NoFrame);
+}
+
+
+OutputWindow::~OutputWindow()
+{
+}
+
+void OutputWindow::appendOutput(const QString &out)
+{
+ appendPlainText(out);
+}
+
+void OutputWindow::insertLine()
+{
+ appendPlainText(QString());
+}
+
+#if 0
+OutputWindow::OutputWindow(QWidget *parent)
+ : QAbstractScrollArea(parent)
+{
+ max_lines = 1000;
+ width_used = 0;
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ same_height = true;
+ block_scroll = false;
+ setWindowTitle(tr("Application Output Window"));
+ setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
+}
+
+void OutputWindow::changed() {
+ int remove = lines.size() - max_lines;
+ if (remove > 0) {
+ selection_start.line -= remove;
+ selection_end.line -= remove;
+ selection_start = qMax(selection_start, Selection());
+ selection_end = qMax(selection_end, Selection());
+ if (remove > verticalScrollBar()->value()) {
+ if (same_height)
+ viewport()->scroll(0, -remove * fontMetrics().lineSpacing());
+ else
+ viewport()->update();
+ } else {
+ block_scroll = true;
+ verticalScrollBar()->setValue(verticalScrollBar()->value() - remove);
+ block_scroll = false;
+ }
+ while (remove--)
+ lines.removeFirst();
+ }
+
+ verticalScrollBar()->setRange(0, lines.size() - 1);
+
+}
+
+
+bool OutputWindow::getCursorPos(int *lineNumber, int *position, const QPoint &pos) {
+ if (lines.isEmpty())
+ return false;
+ *lineNumber = verticalScrollBar()->value();
+
+ int x = 4 - horizontalScrollBar()->value();
+
+ int spacing = fontMetrics().lineSpacing();
+ int leading = fontMetrics().leading();
+ int height = 0;
+
+ QTextLayout textLayout;
+ textLayout.setFont(font());
+
+ if (same_height && pos.y() > 0) {
+ int skipLines = pos.y() / spacing;
+ height += skipLines * spacing;
+ *lineNumber = qMin(*lineNumber + skipLines, lines.size() - 1);
+ }
+
+ same_height = true;
+
+ while ( *lineNumber < lines.size()) {
+ textLayout.setText(lines.at(*lineNumber));
+
+ textLayout.beginLayout();
+ while (1) {
+ QTextLine line = textLayout.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(INT_MAX/256);
+ height += leading;
+ line.setPosition(QPoint(x, height));
+ height += static_cast<int>(line.height());
+ }
+ textLayout.endLayout();
+ if (height > pos.y()) {
+ *position = textLayout.lineAt(0).xToCursor(pos.x());
+ break;
+ }
+ ++*lineNumber;
+ }
+ return true;
+}
+
+void OutputWindow::setNumberOfLines(int max)
+{
+ max_lines = qMax(1, max);
+ while (lines.size() > max_lines)
+ lines.removeLast();
+ changed();
+}
+
+int OutputWindow::numberOfLines() const
+{
+ return max_lines;
+}
+
+bool OutputWindow::hasSelectedText() const
+{
+ return selection_start != selection_end;
+}
+
+void OutputWindow::clearSelection()
+{
+ bool hadSelectedText = hasSelectedText();
+ selection_start = selection_end = Selection();
+ if (hadSelectedText)
+ viewport()->update();
+}
+
+QString OutputWindow::selectedText() const
+{
+ Selection sel_start = qMin(selection_start, selection_end);
+ Selection sel_end = qMax(selection_start, selection_end);
+ QString text;
+
+ if (sel_start.line == sel_end.line) {
+ text += lines.at(sel_start.line).mid(sel_start.pos, sel_end.pos - sel_start.pos);
+ } else {
+ int line = sel_start.line;
+ text += lines.at(line++).mid(sel_start.pos);
+ text += QLatin1Char('\n');
+ while (line < sel_end.line) {
+ text += lines.at(line++);
+ text += QLatin1Char('\n');
+ }
+ text += lines.at(sel_end.line).left(sel_end.pos);
+ }
+ return text;
+}
+
+void OutputWindow::appendOutput(const QString &text)
+{
+ lines.append(text);
+ if (same_height)
+ viewport()->update(
+ QRect(0, (lines.size() - verticalScrollBar()->value() - 1) * fontMetrics().lineSpacing(),
+ viewport()->width(), viewport()->height()));
+ else
+ viewport()->update();
+
+ changed();
+ int top = lines.size() - (viewport()->height() / fontMetrics().lineSpacing());
+ if (verticalScrollBar()->value() == top - 1)
+ verticalScrollBar()->setValue(top);
+}
+
+void OutputWindow::clear()
+{
+ clearSelection();
+ lines.clear();
+ viewport()->update();
+}
+
+void OutputWindow::copy()
+{
+ if (hasSelectedText())
+ QApplication::clipboard()->setText(selectedText());
+}
+
+void OutputWindow::selectAll()
+{
+ selection_start = Selection();
+ selection_end.line = lines.size() - 1;
+ selection_end.pos = lines.last().length() - 1;
+ viewport()->update();
+}
+
+void OutputWindow::scrollContentsBy(int dx, int dy)
+{
+ if (block_scroll)
+ return;
+ if (dx && dy) {
+ viewport()->update();
+ } else if (dx && !dy) {
+ viewport()->scroll(dx, 0);
+ } else {
+ if (same_height) {
+ viewport()->scroll(0, fontMetrics().lineSpacing() * dy);
+ } else {
+ viewport()->update();
+ }
+ }
+}
+
+void OutputWindow::keyPressEvent(QKeyEvent *e)
+{
+ bool accept = true;
+ if (e == QKeySequence::Copy) {
+ copy();
+ } else if (e == QKeySequence::SelectAll) {
+ selectAll();
+ } else if (e->key() == Qt::Key_Enter
+ || e->key() == Qt::Key_Return) {
+ insertLine();
+ } else {
+ accept = false;
+ }
+
+ if (accept)
+ e->accept();
+ else
+ QAbstractScrollArea::keyPressEvent(e);
+}
+
+void OutputWindow::paintEvent(QPaintEvent *e)
+{
+ int lineNumber = verticalScrollBar()->value();
+
+ int x = 4 - horizontalScrollBar()->value();
+ QPainter p(viewport());
+
+ int spacing = fontMetrics().lineSpacing();
+ int leading = fontMetrics().leading();
+ int height = 0;
+
+ QTextLayout textLayout;
+ textLayout.setFont(font());
+
+ QTextCharFormat selectionFormat;
+ selectionFormat.setBackground(palette().highlight());
+ selectionFormat.setForeground(palette().highlightedText());
+
+ if (e->rect().top() <= 0 && e->rect().bottom() >= viewport()->rect().bottom())
+ width_used = 0; // recalculate
+
+ if (same_height) {
+ int skipLines = e->rect().top() / spacing;
+ height += skipLines * spacing;
+ lineNumber += skipLines;
+ }
+
+ same_height = true;
+
+ Selection sel_start = qMin(selection_start, selection_end);
+ Selection sel_end = qMax(selection_start, selection_end);
+
+ while ( lineNumber < lines.size() && height <= e->rect().bottom()) {
+
+ QString line = lines.at(lineNumber);
+
+ if (line.size() == 1 && line.at(0) == QChar::ParagraphSeparator) {
+ int y = height + spacing/2;
+ p.drawLine(e->rect().left(), y, e->rect().right(), y);
+ height += spacing;
+
+ } else {
+ textLayout.setText(line);
+ textLayout.beginLayout();
+ while (1) {
+ QTextLine line = textLayout.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(INT_MAX/256);
+ height += leading;
+ line.setPosition(QPoint(x, height));
+ height += static_cast<int>(line.height());
+
+ same_height = same_height && (line.height() + leading) == spacing;
+ width_used = qMax(width_used, 8 + static_cast<int>(line.naturalTextWidth()));
+ }
+ textLayout.endLayout();
+
+ if (lineNumber >= sel_start.line && lineNumber <= sel_end.line) {
+ QVector<QTextLayout::FormatRange> selection(1);
+ selection[0].start = (lineNumber == sel_start.line)? sel_start.pos : 0;
+ selection[0].length = ((lineNumber == sel_end.line) ? sel_end.pos : lines.at(lineNumber).size()) - selection[0].start;
+ selection[0].format = selectionFormat;
+
+ textLayout.draw(&p, QPoint(0, 0), selection);
+ } else {
+ textLayout.draw(&p, QPoint(0, 0));
+ }
+ }
+
+
+ ++lineNumber;
+ }
+
+ horizontalScrollBar()->setRange(0, qMax(0, width_used - viewport()->width()));
+ if (horizontalScrollBar()->pageStep() != viewport()->width())
+ horizontalScrollBar()->setPageStep(viewport()->width());
+ if (height > viewport()->height())
+ verticalScrollBar()->setPageStep(lineNumber - verticalScrollBar()->value());
+ else if (verticalScrollBar()->pageStep() != viewport()->height() / fontMetrics().lineSpacing())
+ verticalScrollBar()->setPageStep(viewport()->height() / fontMetrics().lineSpacing());
+}
+
+void OutputWindow::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ clearSelection();
+ if (getCursorPos(&selection_start.line, &selection_start.pos, e->pos())) {
+ selection_end = selection_start;
+ autoscroll = 0;
+ }
+ }
+}
+
+void OutputWindow::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == autoscroll_timer.timerId()) {
+ int autoscroll = 0;
+ if (lastMouseMove.y() < 0)
+ autoscroll = -1;
+ else if (lastMouseMove.y() > viewport()->height())
+ autoscroll = 1;
+ if (autoscroll) {
+ verticalScrollBar()->setValue(verticalScrollBar()->value() + autoscroll);
+ OutputWindow::mouseMoveEvent(0);
+ }
+ }
+ QAbstractScrollArea::timerEvent(e);
+}
+
+void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ autoscroll_timer.stop();
+ if (hasSelectedText() && QApplication::clipboard()->supportsSelection())
+ QApplication::clipboard()->setText(selectedText(), QClipboard::Selection);
+ }
+}
+
+void OutputWindow::mouseMoveEvent(QMouseEvent *e)
+{
+ if (e) {
+ lastMouseMove = e->pos();
+ if (viewport()->rect().contains(e->pos()))
+ autoscroll_timer.stop();
+ else
+ autoscroll_timer.start(20, this);
+ }
+
+
+ Selection old = selection_end;
+ if (!getCursorPos(&selection_end.line, &selection_end.pos, lastMouseMove))
+ return;
+ if (same_height) {
+ Selection from = qMin(old, selection_end);
+ Selection to = qMax(old, selection_end);
+ viewport()->update(QRect(0, -1 + (from.line - verticalScrollBar()->value()) * fontMetrics().lineSpacing(),
+ viewport()->width(), 2 + (to.line - from.line + 1) * fontMetrics().lineSpacing()));
+ } else {
+ viewport()->update();
+ }
+}
+
+void OutputWindow::contextMenuEvent(QContextMenuEvent * e)
+{
+ QMenu menu(this);
+ QAction *clearAction = menu.addAction("Clear", this, SLOT(clear()));
+ QAction *copyAction = menu.addAction("Copy", this, SLOT(copy()), QKeySequence::Copy);
+ QAction *selectAllAction = menu.addAction("Select All", this, SLOT(selectAll()), QKeySequence::SelectAll);
+ if (lines.empty()) {
+ clearAction->setDisabled(true);
+ selectAllAction->setDisabled(true);
+ }
+ if (!hasSelectedText())
+ copyAction->setDisabled(true);
+
+ menu.exec(e->globalPos());
+}
+
+#endif // 0
diff --git a/src/plugins/projectexplorer/outputwindow.h b/src/plugins/projectexplorer/outputwindow.h
new file mode 100644
index 0000000000..5a25ea40a8
--- /dev/null
+++ b/src/plugins/projectexplorer/outputwindow.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OUTPUTWINDOW_H
+#define OUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+#include <texteditor/plaintexteditor.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QBasicTimer>
+#include <QtGui/QAbstractScrollArea>
+#include <QtGui/QToolButton>
+#include <QtGui/QPlainTextEdit>
+
+QT_BEGIN_NAMESPACE
+class QTabWidget;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+
+class RunControl;
+
+namespace Internal {
+
+class OutputWindow;
+
+class OutputPane : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ OutputPane();
+ ~OutputPane();
+
+ QWidget *outputWidget(QWidget *);
+ QList<QWidget*> toolBarWidgets(void) const;
+ QString name() const;
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool);
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+ void appendOutput(const QString &out);
+
+ // ApplicationOutputspecifics
+ void createNewOutputWindow(RunControl *);
+ void appendOutput(RunControl *, const QString &out);
+ void showTabFor(RunControl *);
+
+public slots:
+ void projectRemoved();
+
+private slots:
+ void insertLine();
+ void reRunRunControl();
+ void stopRunControl();
+ void closeTab(int index);
+ void tabChanged(int);
+ void runControlStarted();
+ void runControlFinished();
+
+private:
+ RunControl *runControlForTab(int index) const;
+
+ QWidget *m_mainWidget;
+ QTabWidget *m_tabWidget;
+ QHash<RunControl *, OutputWindow *> m_outputWindows;
+// QToolButton *m_insertLineButton;
+ QToolButton *m_reRunButton;
+ QToolButton *m_stopButton;
+};
+
+
+
+class OutputWindow : public QPlainTextEdit
+{
+ Q_OBJECT
+public:
+ OutputWindow(QWidget *parent = 0);
+ ~OutputWindow();
+
+ void appendOutput(const QString &out);
+ void insertLine();
+};
+
+#if 0
+class OutputWindow
+ : public QAbstractScrollArea
+{
+ Q_OBJECT
+
+ int max_lines;
+ bool same_height;
+ int width_used;
+ bool block_scroll;
+ QStringList lines;
+ QBasicTimer autoscroll_timer;
+ int autoscroll;
+ QPoint lastMouseMove;
+
+
+ struct Selection {
+ Selection():line(0), pos(0){}
+ int line;
+ int pos;
+
+ bool operator==(const Selection &other) const
+ { return line == other.line && pos == other.pos; }
+ bool operator!=(const Selection &other) const
+ { return !(*this == other); }
+ bool operator<(const Selection &other) const
+ { return line < other.line || (line == other.line && pos < other.pos); }
+ bool operator>=(const Selection &other) const
+ { return !(*this < other); }
+ bool operator<=(const Selection &other) const
+ { return line < other.line || (line == other.line && pos == other.pos); }
+ bool operator>(const Selection &other) const
+ { return !(*this <= other); }
+ };
+
+ Selection selection_start, selection_end;
+ void changed();
+ bool getCursorPos(int *lineNumber, int *position, const QPoint &pos);
+
+public:
+ OutputWindow(QWidget *parent = 0);
+ ~OutputWindow();
+
+ void setNumberOfLines(int max);
+ int numberOfLines() const;
+
+ bool hasSelectedText() const;
+ void clearSelection();
+
+ QString selectedText() const;
+
+ void appendOutput(const QString &out);
+ void insertLine() {
+ appendOutput(QChar(QChar::ParagraphSeparator));
+ }
+
+
+public slots:
+ void clear();
+ void copy();
+ void selectAll();
+
+signals:
+ void showPage();
+
+protected:
+ void scrollContentsBy(int dx, int dy);
+ void keyPressEvent(QKeyEvent *e);
+ void paintEvent(QPaintEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void timerEvent(QTimerEvent *e);
+ void contextMenuEvent(QContextMenuEvent * e);
+};
+#endif // 0
+} //namespace Internal
+} //namespace ProjectExplorer
+
+#endif
diff --git a/src/plugins/projectexplorer/persistentsettings.cpp b/src/plugins/projectexplorer/persistentsettings.cpp
new file mode 100644
index 0000000000..2ce7ed8cfe
--- /dev/null
+++ b/src/plugins/projectexplorer/persistentsettings.cpp
@@ -0,0 +1,225 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "persistentsettings.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QVariant>
+#include <QtXml/QDomDocument>
+#include <QtXml/QDomCDATASection>
+
+
+using namespace ProjectExplorer;
+
+PersistentSettingsReader::PersistentSettingsReader()
+{
+
+}
+
+QVariant PersistentSettingsReader::restoreValue(const QString & variable) const
+{
+ const QString &name = m_prefix + variable;
+ if (m_valueMap.contains(name))
+ return m_valueMap.value(name);
+ return QVariant();
+}
+
+bool PersistentSettingsReader::load(const QString & fileName)
+{
+ m_valueMap.clear();
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ QDomDocument doc;
+ if (!doc.setContent(&file))
+ return false;
+
+ QDomElement root = doc.documentElement();
+ if (root.nodeName() != QLatin1String("qtcreator"))
+ return false;
+
+ QDomElement child = root.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("data"))
+ readValues(child);
+ }
+
+ file.close();
+ return true;
+}
+
+void PersistentSettingsReader::setPrefix(const QString &prefix)
+{
+ m_prefix = prefix;
+}
+
+QString PersistentSettingsReader::prefix() const
+{
+ return m_prefix;
+}
+
+QVariant PersistentSettingsReader::readValue(const QDomElement &valElement) const
+{
+ QString name = valElement.nodeName();
+ QString type = valElement.attribute(QLatin1String("type"));
+ QVariant v;
+
+ if (name == QLatin1String("value")) {
+ v.setValue(valElement.text());
+ v.convert(QVariant::nameToType(type.toLatin1().data()));
+ } else if (name == QLatin1String("valuelist")) {
+ QDomElement child = valElement.firstChildElement();
+ QList<QVariant> valList;
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ valList << readValue(child);
+ }
+ v.setValue(valList);
+ } else if (name == QLatin1String("valuemap")) {
+ QDomElement child = valElement.firstChildElement();
+ QMap<QString, QVariant> valMap;
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ QString key = child.attribute(QLatin1String("key"));
+ valMap.insert(key, readValue(child));
+ }
+ v.setValue(valMap);
+ }
+
+ return v;
+}
+
+void PersistentSettingsReader::readValues(const QDomElement &data)
+{
+ QString variable;
+ QVariant v;
+
+ QDomElement child = data.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("variable")) {
+ variable = child.text();
+ } else {
+ v = readValue(child);
+ }
+ }
+
+ m_valueMap.insert(variable, v);
+}
+
+///
+/// PersistentSettingsWriter
+///
+
+PersistentSettingsWriter::PersistentSettingsWriter()
+{
+
+}
+
+void PersistentSettingsWriter::writeValue(QDomElement &ps, const QVariant &variant)
+{
+ if (variant.type() == QVariant::StringList || variant.type() == QVariant::List) {
+ QDomElement values = ps.ownerDocument().createElement("valuelist");
+ values.setAttribute("type", QVariant::typeToName(QVariant::List));
+ QList<QVariant> varList = variant.toList();
+ foreach(QVariant var, varList) {
+ writeValue(values, var);
+ }
+ ps.appendChild(values);
+ } else if (variant.type() == QVariant::Map) {
+ QDomElement values = ps.ownerDocument().createElement("valuemap");
+ values.setAttribute("type", QVariant::typeToName(QVariant::Map));
+
+ QMap<QString, QVariant> varMap = variant.toMap();
+ QMap<QString, QVariant>::const_iterator i = varMap.constBegin();
+ while (i != varMap.constEnd()) {
+ writeValue(values, i.value());
+ values.lastChild().toElement().
+ setAttribute(QLatin1String("key"), i.key());
+ ++i;
+ }
+
+ ps.appendChild(values);
+ } else {
+ QDomElement value = ps.ownerDocument().createElement("value");
+ ps.appendChild(value);
+ QDomText valueText = ps.ownerDocument().createTextNode(variant.toString());
+ value.appendChild(valueText);
+ value.setAttribute("type", variant.typeName());
+ ps.appendChild(value);
+ }
+}
+
+void PersistentSettingsWriter::saveValue(const QString & variable, const QVariant &value)
+{
+ m_valueMap[m_prefix + variable] = value;
+}
+
+bool PersistentSettingsWriter::save(const QString & fileName, const QString & docType)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly))
+ return false;
+
+ QDomDocument doc(docType);
+
+ QDomElement root = doc.createElement("qtcreator");
+ doc.appendChild(root);
+
+ QMap<QString, QVariant>::const_iterator i = m_valueMap.constBegin();
+ while (i != m_valueMap.constEnd()) {
+ QDomElement ps = doc.createElement("data");
+ root.appendChild(ps);
+
+ QDomElement variable = doc.createElement("variable");
+ ps.appendChild(variable);
+ QDomText variableText = doc.createTextNode(i.key());
+ variable.appendChild(variableText);
+
+ writeValue(ps, i.value());
+ ++i;
+ }
+
+ file.write(doc.toByteArray());
+ file.close();
+ return true;
+}
+
+void PersistentSettingsWriter::setPrefix(const QString &prefix)
+{
+ m_prefix = prefix;
+}
+
+QString PersistentSettingsWriter::prefix() const
+{
+ return m_prefix;
+}
diff --git a/src/plugins/projectexplorer/persistentsettings.h b/src/plugins/projectexplorer/persistentsettings.h
new file mode 100644
index 0000000000..179fc1f3ab
--- /dev/null
+++ b/src/plugins/projectexplorer/persistentsettings.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PERSISTENTSETTINGS_H
+#define PERSISTENTSETTINGS_H
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QVariant>
+#include <QtXml/QDomElement>
+
+namespace ProjectExplorer {
+
+class PROJECTEXPLORER_EXPORT PersistentSettingsReader
+{
+public:
+ PersistentSettingsReader();
+ QVariant restoreValue(const QString & variable) const;
+ bool load(const QString & fileName);
+ void setPrefix(const QString &prefix);
+ QString prefix() const;
+private:
+ QString m_prefix;
+ QVariant readValue(const QDomElement &valElement) const;
+ void readValues(const QDomElement &data);
+ QMap<QString, QVariant> m_valueMap;
+};
+
+class PROJECTEXPLORER_EXPORT PersistentSettingsWriter
+{
+public:
+ PersistentSettingsWriter();
+ void saveValue(const QString & variable, const QVariant &value);
+ bool save(const QString & fileName, const QString & docType);
+ void setPrefix(const QString &prefix);
+ QString prefix() const;
+private:
+ QString m_prefix;
+ void writeValue(QDomElement &ps, const QVariant &value);
+ QMap<QString, QVariant> m_valueMap;
+};
+
+} //namespace ProjectExplorer
+
+#endif //PERSISTENTSETTINGS_H
diff --git a/src/plugins/projectexplorer/pluginfilefactory.cpp b/src/plugins/projectexplorer/pluginfilefactory.cpp
new file mode 100644
index 0000000000..9a56363ac8
--- /dev/null
+++ b/src/plugins/projectexplorer/pluginfilefactory.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "pluginfilefactory.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+#include "iprojectmanager.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/messagemanager.h>
+
+#include <QtCore/QDebug>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+ProjectFileFactory::ProjectFileFactory(const Core::ICore* core, IProjectManager *manager) :
+ m_mimeTypes(manager->mimeType()),
+ m_kind(Constants::FILE_FACTORY_KIND),
+ m_core(core),
+ m_manager(manager)
+{
+}
+
+QStringList ProjectFileFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
+
+QString ProjectFileFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *ProjectFileFactory::open(const QString &fileName)
+{
+ Core::IFile *fIFace = 0;
+
+ ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance();
+ if (!pe->openProject(fileName)) {
+ m_core->messageManager()->printToOutputPane(tr("Could not open the following project: '%1'").arg(fileName));
+ } else if (pe->session()) {
+ 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;
+}
+
+QList<ProjectFileFactory*> ProjectFileFactory::createFactories(const Core::ICore* core,
+ QString *filterString)
+{
+ // Register factories for all project managers
+ QList<Internal::ProjectFileFactory*> rc;
+ QList<IProjectManager*> projectManagers = core->pluginManager()->getObjects<IProjectManager>();
+
+ const QString filterSeparator = QLatin1String(";;");
+ filterString->clear();
+ foreach(IProjectManager *manager, projectManagers) {
+ rc.push_back(new ProjectFileFactory(core, manager));
+ if (!filterString->isEmpty())
+ *filterString += filterSeparator;
+ const QString mimeType = manager->mimeType();
+ const QString pFilterString = core->mimeDatabase()->findByType(mimeType).filterString();
+ *filterString += pFilterString;
+ }
+ return rc;
+}
diff --git a/src/plugins/projectexplorer/pluginfilefactory.h b/src/plugins/projectexplorer/pluginfilefactory.h
new file mode 100644
index 0000000000..11cc60845b
--- /dev/null
+++ b/src/plugins/projectexplorer/pluginfilefactory.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLUGINFILEFACTORY_H
+#define PLUGINFILEFACTORY_H
+
+#include <coreplugin/ifilefactory.h>
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+
+namespace Core {
+ class ICore;
+}
+
+namespace ProjectExplorer {
+ class IProjectManager;
+ class ProjectExplorerPlugin;
+
+namespace Internal {
+
+/* Factory for project files. */
+
+class ProjectFileFactory : public Core::IFileFactory
+{
+ Q_OBJECT
+ explicit ProjectFileFactory(const Core::ICore* core, ProjectExplorer::IProjectManager *manager);
+public:
+
+ virtual QStringList mimeTypes() const;
+ bool canOpen(const QString &fileName);
+ QString kind() const;
+ Core::IFile *open(const QString &fileName);
+
+ static QList<ProjectFileFactory*> createFactories(const Core::ICore* core, QString *filterString);
+
+private:
+ const QStringList m_mimeTypes;
+ const QString m_kind;
+ const Core::ICore* m_core;
+ ProjectExplorer::IProjectManager *m_manager;
+};
+
+
+} //namespace Internal
+} //namespace ProjectExplorer
+
+#endif // PLUGINFILEFACTORY
diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp
new file mode 100644
index 0000000000..2ab5d77a71
--- /dev/null
+++ b/src/plugins/projectexplorer/processstep.cpp
@@ -0,0 +1,220 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "processstep.h"
+#include "buildstep.h"
+#include "project.h"
+
+#include <coreplugin/ifile.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QFileDialog>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+ProcessStep::ProcessStep(Project *pro)
+ : AbstractProcessStep(pro)
+{
+
+}
+
+bool ProcessStep::init(const QString &buildConfiguration)
+{
+ setEnvironment(buildConfiguration, project()->environment(buildConfiguration));
+ QVariant wd = value(buildConfiguration, "workingDirectory").toString();
+ QString workingDirectory;
+ if(!wd.isValid() || wd.toString().isEmpty())
+ workingDirectory = "$BUILDDIR";
+ else
+ workingDirectory = wd.toString();
+ setWorkingDirectory(buildConfiguration, workingDirectory.replace("$BUILDDIR", project()->buildDirectory(buildConfiguration)));
+ return AbstractProcessStep::init(buildConfiguration);
+}
+
+void ProcessStep::run(QFutureInterface<bool> & fi)
+{
+ return AbstractProcessStep::run(fi);
+}
+
+QString ProcessStep::name()
+{
+ return "projectexplorer.processstep";
+}
+
+void ProcessStep::setDisplayName(const QString &name)
+{
+ setValue("ProjectExplorer.ProcessStep.DisplayName", name);
+ emit displayNameChanged(this, name);
+}
+
+QString ProcessStep::displayName()
+{
+ QVariant displayName = value("ProjectExplorer.ProcessStep.DisplayName");
+ if (displayName.isValid())
+ return displayName.toString();
+ else
+ return tr("Custom Process Step");
+}
+
+BuildStepConfigWidget *ProcessStep::createConfigWidget()
+{
+ return new ProcessStepConfigWidget(this);
+}
+
+bool ProcessStep::immutable() const
+{
+ return false;
+}
+
+//*******
+// ProcessStepFactory
+//*******
+
+ProcessStepFactory::ProcessStepFactory()
+{
+
+}
+
+bool ProcessStepFactory::canCreate(const QString &name) const
+{
+ return name == "projectexplorer.processstep";
+}
+
+BuildStep *ProcessStepFactory::create(Project *pro, const QString &name) const
+{
+ Q_UNUSED(name);
+ return new ProcessStep(pro);
+}
+
+QStringList ProcessStepFactory::canCreateForProject(Project *pro) const
+{
+ Q_UNUSED(pro)
+ return QStringList()<<"projectexplorer.processstep";
+}
+QString ProcessStepFactory::displayNameForName(const QString &name) const
+{
+ Q_UNUSED(name);
+ return "Custom Process Step";
+}
+
+//*******
+// ProcessStepConfigWidget
+//*******
+
+ProcessStepConfigWidget::ProcessStepConfigWidget(ProcessStep *step)
+ : m_step(step)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.commandBrowseButton, SIGNAL(clicked(bool)),
+ this, SLOT(commandBrowseButtonClicked()));
+ connect(m_ui.workingDirBrowseButton, SIGNAL(clicked(bool)),
+ this, SLOT(workingDirBrowseButtonClicked()));
+
+ connect(m_ui.nameLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(nameLineEditTextEdited()));
+ connect(m_ui.commandLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(commandLineEditTextEdited()));
+ connect(m_ui.workingDirectoryLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(workingDirectoryLineEditTextEdited()));
+ connect(m_ui.commandArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(commandArgumentsLineEditTextEdited()));
+ connect(m_ui.enabledGroupBox, SIGNAL(clicked(bool)),
+ this, SLOT(enabledGroupBoxClicked(bool)));
+}
+
+QString ProcessStepConfigWidget::displayName() const
+{
+ return m_step->name();
+}
+
+void ProcessStepConfigWidget::workingDirBrowseButtonClicked()
+{
+ QString workingDirectory = QFileDialog::getExistingDirectory(this, "Select the working directory", m_ui.workingDirectoryLineEdit->text());
+ if(workingDirectory.isEmpty())
+ return;
+ m_ui.workingDirectoryLineEdit->setText(workingDirectory);
+ workingDirectoryLineEditTextEdited();
+}
+
+void ProcessStepConfigWidget::commandBrowseButtonClicked()
+{
+ QString filename = QFileDialog::getOpenFileName(this, "Select the executable");
+ if(filename.isEmpty())
+ return;
+ m_ui.commandLineEdit->setText(filename);
+ commandLineEditTextEdited();
+}
+
+void ProcessStepConfigWidget::init(const QString &buildConfiguration)
+{
+ m_buildConfiguration = buildConfiguration;
+ if(buildConfiguration != QString::null) {
+ m_ui.commandLineEdit->setText(m_step->command(buildConfiguration));
+
+ QString workingDirectory = m_step->value(buildConfiguration, "workingDirectory").toString();
+ if (workingDirectory.isEmpty())
+ workingDirectory = "$BUILDDIR";
+ m_ui.workingDirectoryLineEdit->setText(workingDirectory);
+
+ m_ui.commandArgumentsLineEdit->setText(m_step->arguments(buildConfiguration).join(" "));
+ m_ui.enabledGroupBox->setChecked(m_step->enabled(buildConfiguration));
+ }
+ m_ui.nameLineEdit->setText(m_step->displayName());
+}
+
+void ProcessStepConfigWidget::nameLineEditTextEdited()
+{
+ m_step->setDisplayName(m_ui.nameLineEdit->text());
+}
+
+void ProcessStepConfigWidget::commandLineEditTextEdited()
+{
+ m_step->setCommand(m_buildConfiguration, m_ui.commandLineEdit->text());
+}
+
+void ProcessStepConfigWidget::workingDirectoryLineEditTextEdited()
+{
+ QString wd = m_ui.workingDirectoryLineEdit->text();
+ m_step->setValue(m_buildConfiguration, "workingDirectory", wd);
+}
+
+void ProcessStepConfigWidget::commandArgumentsLineEditTextEdited()
+{
+ m_step->setArguments(m_buildConfiguration, m_ui.commandArgumentsLineEdit->text().split(" ",
+ QString::SkipEmptyParts));
+}
+
+void ProcessStepConfigWidget::enabledGroupBoxClicked(bool)
+{
+ m_step->setEnabled(m_buildConfiguration, m_ui.enabledGroupBox->isChecked());
+}
diff --git a/src/plugins/projectexplorer/processstep.h b/src/plugins/projectexplorer/processstep.h
new file mode 100644
index 0000000000..8667cd42b5
--- /dev/null
+++ b/src/plugins/projectexplorer/processstep.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROCESSSTEP_H
+#define PROCESSSTEP_H
+
+#include "ui_processstep.h"
+#include "abstractprocessstep.h"
+#include "environment.h"
+
+namespace ProjectExplorer {
+
+class Project;
+
+namespace Internal {
+
+class ProcessStepFactory : public IBuildStepFactory
+{
+public:
+ ProcessStepFactory();
+ virtual bool canCreate(const QString &name) const;
+ virtual BuildStep *create(Project *pro, const QString &name) const;
+ virtual QStringList canCreateForProject(Project *pro) const;
+ virtual QString displayNameForName(const QString &name) const;
+};
+
+class ProcessStep : public ProjectExplorer::AbstractProcessStep
+{
+ Q_OBJECT
+public:
+ ProcessStep(Project *pro);
+ virtual bool init(const QString & name);
+ virtual void run(QFutureInterface<bool> &);
+
+ virtual QString name();
+ void setDisplayName(const QString &name);
+ virtual QString displayName();
+ virtual BuildStepConfigWidget *createConfigWidget();
+ virtual bool immutable() const;
+private:
+ QString m_name;
+};
+
+class ProcessStepConfigWidget : public BuildStepConfigWidget
+{
+ Q_OBJECT
+public:
+ ProcessStepConfigWidget(ProcessStep *step);
+ virtual QString displayName() const;
+ virtual void init(const QString &buildConfiguration);
+private slots:
+ void nameLineEditTextEdited();
+ void commandLineEditTextEdited();
+ void workingDirectoryLineEditTextEdited();
+ void commandArgumentsLineEditTextEdited();
+ void enabledGroupBoxClicked(bool);
+ void workingDirBrowseButtonClicked();
+ void commandBrowseButtonClicked();
+private:
+ QString m_buildConfiguration;
+ ProcessStep *m_step;
+ Ui::ProcessStepWidget m_ui;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // PROCESSSTEP_H
diff --git a/src/plugins/projectexplorer/processstep.ui b/src/plugins/projectexplorer/processstep.ui
new file mode 100644
index 0000000000..9875ef474c
--- /dev/null
+++ b/src/plugins/projectexplorer/processstep.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::ProcessStepWidget</class>
+ <widget class="QWidget" name="ProjectExplorer::Internal::ProcessStepWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>428</width>
+ <height>222</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="enabledGroupBox">
+ <property name="title">
+ <string>Enable custom process step</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="commandLabel">
+ <property name="text">
+ <string>Command</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="commandLineEdit"/>
+ </item>
+ <item row="1" column="2">
+ <widget class="QToolButton" name="commandBrowseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="workingDirecoryLabel">
+ <property name="text">
+ <string>Working Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="workingDirectoryLineEdit"/>
+ </item>
+ <item row="2" column="2">
+ <widget class="QToolButton" name="workingDirBrowseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="commandArgumentsLabel">
+ <property name="text">
+ <string>command arguments</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2">
+ <widget class="QLineEdit" name="commandArgumentsLineEdit"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <widget class="QLineEdit" name="nameLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>80</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
new file mode 100644
index 0000000000..88cdc53049
--- /dev/null
+++ b/src/plugins/projectexplorer/project.cpp
@@ -0,0 +1,522 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "buildstep.h"
+#include "project.h"
+#include "projectexplorer.h"
+#include "runconfiguration.h"
+#include "editorconfiguration.h"
+
+#include <coreplugin/ifile.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QTextCodec>
+#include <QtCore/QDebug>
+
+using namespace ProjectExplorer;
+using ExtensionSystem::PluginManager;
+
+Project::Project()
+ : m_activeRunConfiguration(0),
+ m_editorConfiguration(new EditorConfiguration())
+{
+}
+
+void Project::insertBuildStep(int position, BuildStep *step)
+{
+ m_buildSteps.insert(position, step);
+ // check that the step has all the configurations
+ foreach(const QString & name, buildConfigurations())
+ {
+ if (!step->getBuildConfiguration(name))
+ step->addBuildConfiguration(name);
+ }
+}
+
+void Project::removeBuildStep(int position)
+{
+ delete m_buildSteps.at(position);
+ m_buildSteps.removeAt(position);
+}
+
+void Project::moveBuildStepUp(int position)
+{
+ BuildStep *bs = m_buildSteps.takeAt(position);
+ m_buildSteps.insert(position - 1, bs);
+}
+
+void Project::insertCleanStep(int position, BuildStep *step)
+{
+ m_cleanSteps.insert(position, step);
+ // check that the step has all the configurations
+ foreach(const QString & name, buildConfigurations())
+ {
+ if (!step->getBuildConfiguration(name))
+ step->addBuildConfiguration(name);
+ }
+}
+
+void Project::removeCleanStep(int position)
+{
+ delete m_cleanSteps.at(position);
+ m_cleanSteps.removeAt(position);
+}
+
+void Project::addBuildConfiguration(const QString &name)
+{
+ if (buildConfigurations().contains(name) )
+ return;
+
+ m_buildConfigurationValues.push_back(new BuildConfiguration(name));
+
+ for (int i = 0; i!=m_buildSteps.size(); ++i)
+ m_buildSteps.at(i)->addBuildConfiguration(name);
+
+ for (int i = 0; i!=m_cleanSteps.size(); ++i)
+ m_cleanSteps.at(i)->addBuildConfiguration(name);
+}
+
+void Project::removeBuildConfiguration(const QString &name)
+{
+ if (!buildConfigurations().contains(name))
+ return;
+
+ for (int i = 0; i != m_buildConfigurationValues.size(); ++i)
+ if(m_buildConfigurationValues.at(i)->name() == name) {
+ delete m_buildConfigurationValues.at(i);
+ m_buildConfigurationValues.removeAt(i);
+ break;
+ }
+
+ for (int i = 0; i!=m_buildSteps.size(); ++i)
+ m_buildSteps.at(i)->removeBuildConfiguration(name);
+ for (int i = 0; i!=m_cleanSteps.size(); ++i)
+ m_cleanSteps.at(i)->removeBuildConfiguration(name);
+
+}
+
+void Project::copyBuildConfiguration(const QString &source, const QString &dest)
+{
+ if (!buildConfigurations().contains(source))
+ return;
+
+ for (int i = 0; i != m_buildConfigurationValues.size(); ++i)
+ if(m_buildConfigurationValues.at(i)->name() == source)
+ m_buildConfigurationValues.push_back(new BuildConfiguration(dest, m_buildConfigurationValues.at(i)));
+
+ for (int i = 0; i!= m_buildSteps.size(); ++i)
+ m_buildSteps.at(i)->copyBuildConfiguration(source, dest);
+
+ for (int i = 0; i!= m_cleanSteps.size(); ++i)
+ m_cleanSteps.at(i)->copyBuildConfiguration(source, dest);
+}
+
+QStringList Project::buildConfigurations() const
+{
+ QStringList result;
+ foreach (BuildConfiguration *bc, m_buildConfigurationValues) {
+ result << bc->name();
+ }
+ return result;
+}
+
+QList<BuildStep *> Project::buildSteps() const
+{
+ return m_buildSteps;
+}
+
+QList<BuildStep *> Project::cleanSteps() const
+{
+ return m_cleanSteps;
+}
+
+
+
+void Project::saveSettings()
+{
+ PersistentSettingsWriter writer;
+ saveSettingsImpl(writer);
+ writer.save(file()->fileName() + QLatin1String(".user"), "QtCreatorProject");
+}
+
+void Project::restoreSettings()
+{
+ PersistentSettingsReader reader;
+ reader.load(file()->fileName() + QLatin1String(".user"));
+ restoreSettingsImpl(reader);
+
+ if (m_activeBuildConfiguration.isEmpty() && !m_buildConfigurations.isEmpty())
+ setActiveBuildConfiguration(m_buildConfigurations.at(0));
+
+ if (!m_activeRunConfiguration && !m_runConfigurations.isEmpty())
+ setActiveRunConfiguration(m_runConfigurations.at(0));
+}
+
+QList<BuildStepConfigWidget*> Project::subConfigWidgets()
+{
+ return QList<BuildStepConfigWidget*>();
+}
+
+void Project::saveSettingsImpl(PersistentSettingsWriter &writer)
+{
+ writer.saveValue("activebuildconfiguration", m_activeBuildConfiguration);
+ //save m_values
+ writer.saveValue("project", m_values);
+
+ //save buildsettings
+ foreach(const QString & buildConfigurationName, buildConfigurations()) {
+ QMap<QString, QVariant> temp =
+ getBuildConfiguration(buildConfigurationName)->toMap();
+ writer.saveValue("buildConfiguration-" + buildConfigurationName, temp);
+ }
+
+ QStringList buildStepNames;
+ foreach(BuildStep * buildStep, buildSteps()) {
+ buildStepNames << buildStep->name();
+ }
+ writer.saveValue("buildsteps", buildStepNames);
+
+ QStringList cleanStepNames;
+ foreach(BuildStep * cleanStep, cleanSteps()) {
+ cleanStepNames << cleanStep->name();
+ }
+ writer.saveValue("cleansteps", cleanStepNames);
+ QStringList buildConfigurationNames = buildConfigurations();
+ writer.saveValue("buildconfigurations", buildConfigurationNames );
+
+ //save buildstep configuration
+ int buildstepnr = 0;
+ foreach(BuildStep * buildStep, buildSteps())
+ {
+ QMap<QString, QVariant> buildConfiguration = buildStep->valuesToMap();
+ writer.saveValue("buildstep" + QString().setNum(buildstepnr), buildConfiguration);
+ ++buildstepnr;
+ }
+
+ // save each buildstep/buildConfiguration combination
+ foreach(const QString & buildConfigurationName, buildConfigurationNames) {
+ buildstepnr = 0;
+ foreach(BuildStep * buildStep, buildSteps()) {
+ QMap<QString, QVariant> temp =
+ buildStep->valuesToMap(buildConfigurationName);
+ writer.saveValue("buildconfiguration-" + buildConfigurationName + "-buildstep" + QString().setNum(buildstepnr), temp);
+ ++buildstepnr;
+ }
+ }
+
+ //save cleansteps buildconfiguration
+ int cleanstepnr = 0;
+ foreach(BuildStep * cleanStep, cleanSteps())
+ {
+ QMap<QString, QVariant> buildConfiguration = cleanStep->valuesToMap();
+ writer.saveValue("cleanstep" + QString().setNum(cleanstepnr), buildConfiguration);
+ ++cleanstepnr;
+ }
+
+ // save each cleanstep/buildConfiguration combination
+ foreach(const QString & buildConfigurationName, buildConfigurationNames) {
+ cleanstepnr = 0;
+ foreach(BuildStep * cleanStep, cleanSteps()) {
+ QMap<QString, QVariant> temp = cleanStep->valuesToMap(buildConfigurationName);
+ writer.saveValue("buildconfiguration-" + buildConfigurationName + "-cleanstep" + QString().setNum(cleanstepnr), temp);
+ ++cleanstepnr;
+ }
+ }
+
+ // Running
+ int i = 0;
+ int activeId = 0;
+ foreach (QSharedPointer<RunConfiguration> rc, m_runConfigurations) {
+ writer.setPrefix("RunConfiguration" + QString().setNum(i) + "-");
+ writer.saveValue("type", rc->type());
+ rc->save(writer);
+ if (rc == m_activeRunConfiguration)
+ activeId = i;
+ ++i;
+ }
+ writer.setPrefix(QString::null);
+ writer.saveValue("activeRunConfiguration", activeId);
+
+ writer.saveValue("defaultFileEncoding", m_editorConfiguration->defaultTextCodec()->name());
+}
+
+void Project::restoreSettingsImpl(PersistentSettingsReader &reader)
+{
+ m_activeBuildConfiguration = reader.restoreValue("activebuildconfiguration").toString();
+
+ m_values = reader.restoreValue("project").toMap();
+
+ //Build Settings
+ const QStringList buildConfigurationNames = reader.restoreValue("buildconfigurations").toStringList();
+ foreach(const QString & buildConfigurationName, buildConfigurationNames) {
+ addBuildConfiguration(buildConfigurationName);
+ QMap<QString, QVariant> temp =
+ reader.restoreValue("buildConfiguration-" + buildConfigurationName).toMap();
+ getBuildConfiguration(buildConfigurationName)->setValuesFromMap(temp);
+ }
+
+ QVariant buildStepsVariant = reader.restoreValue("buildsteps");
+ if(buildStepsVariant.isValid()) {
+ // restoring BuildSteps from settings
+ int pos = 0;
+ const QList<IBuildStepFactory *> buildStepFactories =
+ ExtensionSystem::PluginManager::instance()->getObjects<IBuildStepFactory>();
+ QStringList buildStepNames = buildStepsVariant.toStringList();
+ foreach(const QString & buildStepName, buildStepNames) {
+ foreach(IBuildStepFactory * factory, buildStepFactories) {
+ if(factory->canCreate(buildStepName)) {
+ BuildStep * buildStep = factory->create(this, buildStepName);
+ insertBuildStep(pos, buildStep);
+ ++pos;
+ break;
+ }
+ }
+ }
+
+ QStringList cleanStepNames = reader.restoreValue("cleansteps").toStringList();
+ // restoring BuildSteps from settings
+ pos = 0;
+ foreach(const QString & cleanStepName, cleanStepNames) {
+ foreach(IBuildStepFactory * factory, buildStepFactories) {
+ if(factory->canCreate(cleanStepName)) {
+ BuildStep * cleanStep = factory->create(this, cleanStepName);
+ insertCleanStep(pos, cleanStep);
+ ++pos;
+ break;
+ }
+ }
+ }
+
+ // restoring BuldConfigurations from settings
+
+
+
+ // restore BuildSteps configuration
+ int buildstepnr = 0;
+ foreach(BuildStep * buildStep, buildSteps()) {
+ QMap<QString, QVariant> buildConfiguration = reader.restoreValue("buildstep" + QString().setNum(buildstepnr)).toMap();
+ buildStep->setValuesFromMap(buildConfiguration);
+ ++buildstepnr;
+ }
+
+ foreach(const QString & buildConfigurationName, buildConfigurationNames) {
+ buildstepnr = 0;
+ foreach(BuildStep * buildStep, buildSteps()) {
+ //get the buildconfiguration for this build step
+ QMap<QString, QVariant> buildConfiguration =
+ reader.restoreValue("buildconfiguration-" + buildConfigurationName + "-buildstep" + QString().setNum(buildstepnr)).toMap();
+ buildStep->setValuesFromMap(buildConfigurationName, buildConfiguration);
+ ++buildstepnr;
+ }
+ }
+
+ // restore CleanSteps configuration
+ int cleanstepnr = 0;
+ foreach(BuildStep * cleanStep, cleanSteps())
+ {
+ QMap<QString, QVariant> buildConfiguration = reader.restoreValue("cleanstep" + QString().setNum(cleanstepnr)).toMap();
+ cleanStep->setValuesFromMap(buildConfiguration);
+ ++cleanstepnr;
+ }
+
+ foreach(const QString & buildConfigurationName, buildConfigurationNames) {
+ cleanstepnr = 0;
+ foreach(BuildStep * cleanStep, cleanSteps()) {
+ //get the buildconfiguration for this clean step
+ QMap<QString, QVariant> buildConfiguration =
+ reader.restoreValue("buildconfiguration-" + buildConfigurationName + "-cleanstep" + QString().setNum(cleanstepnr)).toMap();
+ cleanStep->setValuesFromMap(buildConfigurationName, buildConfiguration);
+ ++cleanstepnr;
+ }
+ }
+ }
+
+ // Running
+ const int activeId = reader.restoreValue("activeRunConfiguration").toInt();
+ int i = 0;
+ const QList<IRunConfigurationFactory *> factories =
+ ExtensionSystem::PluginManager::instance()->getObjects<IRunConfigurationFactory>();
+ forever {
+ reader.setPrefix("RunConfiguration" + QString().setNum(i) + "-");
+ const QVariant &typeVariant = reader.restoreValue("type");
+ if (!typeVariant.isValid())
+ break;
+ const QString &type = typeVariant.toString();
+ foreach (IRunConfigurationFactory * factory, factories) {
+ if (factory->canCreate(type)) {
+ QSharedPointer<RunConfiguration> rc = factory->create(this, type);
+ rc->restore(reader);
+ addRunConfiguration(rc);
+ if (i == activeId)
+ setActiveRunConfiguration(rc);
+ }
+ }
+ ++i;
+ }
+ reader.setPrefix(QString::null);
+
+ QTextCodec *codec = QTextCodec::codecForName(reader.restoreValue("defaultFileEncoding").toByteArray());
+ if (codec)
+ m_editorConfiguration->setDefaultTextCodec(codec);
+
+ if (!m_activeRunConfiguration && !m_runConfigurations.isEmpty())
+ setActiveRunConfiguration(m_runConfigurations.at(0));
+}
+
+void Project::setValue(const QString &name, const QVariant & value)
+{
+ m_values.insert(name, value);
+}
+
+QVariant Project::value(const QString &name) const
+{
+ QMap<QString, QVariant>::const_iterator it =
+ m_values.find(name);
+ if(it != m_values.constEnd())
+ return it.value();
+ else
+ return QVariant();
+}
+
+BuildConfiguration * Project::getBuildConfiguration(const QString &name) const
+{
+ for (int i = 0; i != m_buildConfigurationValues.size(); ++i)
+ if (m_buildConfigurationValues.at(i)->name() == name)
+ return m_buildConfigurationValues.at(i);
+ return 0;
+}
+
+void Project::setValue(const QString &buildConfiguration, const QString &name, const QVariant &value)
+{
+ BuildConfiguration *bc = getBuildConfiguration(buildConfiguration);
+ Q_ASSERT(bc);
+ bc->setValue(name, value);
+}
+
+QVariant Project::value(const QString &buildConfiguration, const QString &name) const
+{
+ BuildConfiguration *bc = getBuildConfiguration(buildConfiguration);
+ if (bc)
+ return bc->getValue(name);
+ else
+ return QVariant();
+}
+
+QString Project::activeBuildConfiguration() const
+{
+ return m_activeBuildConfiguration;
+}
+
+void Project::setActiveBuildConfiguration(const QString &config)
+{
+ if (m_activeBuildConfiguration != config && buildConfigurations().contains(config)) {
+ m_activeBuildConfiguration = config;
+ emit activeBuildConfigurationChanged();
+ }
+}
+
+
+QList<QSharedPointer<RunConfiguration> > Project::runConfigurations() const
+{
+ return m_runConfigurations;
+}
+
+void Project::addRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration)
+{
+ Q_ASSERT(!m_runConfigurations.contains(runConfiguration));
+ m_runConfigurations.push_back(runConfiguration);
+}
+
+void Project::removeRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration)
+{
+ Q_ASSERT(m_runConfigurations.contains(runConfiguration));
+ m_runConfigurations.removeOne(runConfiguration);
+ if (m_activeRunConfiguration == runConfiguration) {
+ if (m_runConfigurations.isEmpty())
+ setActiveRunConfiguration(QSharedPointer<RunConfiguration>(0));
+ else
+ setActiveRunConfiguration(m_runConfigurations.at(0));
+ }
+}
+
+QSharedPointer<RunConfiguration> Project::activeRunConfiguration() const
+{
+ return m_activeRunConfiguration;
+}
+
+void Project::setActiveRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration)
+{
+ if (runConfiguration == m_activeRunConfiguration)
+ return;
+ Q_ASSERT(m_runConfigurations.contains(runConfiguration) || runConfiguration == 0);
+ m_activeRunConfiguration = runConfiguration;
+ emit activeRunConfigurationChanged();
+}
+
+EditorConfiguration *Project::editorConfiguration() const
+{
+ return m_editorConfiguration;
+}
+
+QString Project::displayNameFor(const QString &buildConfiguration)
+{
+ return getBuildConfiguration(buildConfiguration)->displayName();
+}
+
+void Project::setDisplayNameFor(const QString &buildConfiguration, const QString &displayName)
+{
+ QStringList displayNames;
+ foreach(const QString &bc, buildConfigurations()) {
+ if (bc != buildConfiguration)
+ displayNames << displayNameFor(bc);
+ }
+ if (displayNames.contains(displayName)) {
+ int i = 2;
+ while (displayNames.contains(displayName + QString::number(i)))
+ ++i;
+ getBuildConfiguration(buildConfiguration)->setDisplayName(displayName + QString::number(i));
+ } else {
+ getBuildConfiguration(buildConfiguration)->setDisplayName(displayName);
+ }
+ emit buildConfigurationDisplayNameChanged(buildConfiguration);
+}
+
+
+Project::~Project()
+{
+ qDeleteAll(m_buildSteps);
+ qDeleteAll(m_cleanSteps);
+ qDeleteAll(m_buildConfigurationValues);
+ delete m_editorConfiguration;
+}
+
+
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
new file mode 100644
index 0000000000..e6d43fcc37
--- /dev/null
+++ b/src/plugins/projectexplorer/project.h
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECT_H
+#define PROJECT_H
+
+#include "persistentsettings.h"
+#include "projectexplorer_export.h"
+#include "buildconfiguration.h"
+#include "environment.h"
+#include "projectnodes.h"
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QObject>
+#include <QtCore/QModelIndex>
+#include <QtCore/QFileInfo>
+#include <QtGui/QFileSystemModel>
+#include <QtGui/QMenu>
+#include <QtGui/QIcon>
+
+namespace Core {
+ class IFile;
+}
+
+namespace ProjectExplorer {
+
+class BuildManager;
+class BuildStep;
+class BuildStepConfigWidget;
+class IProjectManager;
+class RunConfiguration;
+class EditorConfiguration;
+
+class PROJECTEXPLORER_EXPORT Project
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ // Roles to be implemented by all models that are exported
+ // via model()
+ enum ModelRoles {
+ // Absolute file path
+ FilePathRole = QFileSystemModel::FilePathRole
+ };
+
+ Project();
+ virtual ~Project();
+
+ virtual QString name() const = 0;
+ virtual Core::IFile *file() const = 0;
+ virtual IProjectManager *projectManager() const = 0;
+
+ virtual QList<Core::IFile *> dependencies() = 0; //NBS TODO remove
+ virtual QList<Project *> dependsOn() = 0; //NBS TODO implement dependsOn
+
+ virtual bool isApplication() const = 0;
+
+ //Build/Clean Step functions
+ QList<BuildStep *> buildSteps() const;
+ void insertBuildStep(int position, BuildStep *step);
+ void removeBuildStep(int position);
+ void moveBuildStepUp(int position);
+
+ QList<BuildStep *> cleanSteps() const;
+ void insertCleanStep(int position, BuildStep *step);
+ void removeCleanStep(int position);
+
+ //Build configuration
+ void addBuildConfiguration(const QString &name);
+ void removeBuildConfiguration(const QString &name);
+ void copyBuildConfiguration(const QString &source, const QString &dest);
+ QStringList buildConfigurations() const;
+ QString displayNameFor(const QString &buildConfiguration);
+ void setDisplayNameFor(const QString &buildConfiguration, const QString &displayName);
+
+ QString activeBuildConfiguration() const;
+ void setActiveBuildConfiguration(const QString& config);
+
+ void setValue(const QString &name, const QVariant &value);
+ QVariant value(const QString &name) const;
+
+ void setValue(const QString &buildConfiguration, const QString &name, const QVariant &value);
+ QVariant value(const QString &buildConfiguration, const QString &name) const;
+
+ // Running
+ QList<QSharedPointer<RunConfiguration> > runConfigurations() const;
+ void addRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration);
+ void removeRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration);
+
+ QSharedPointer<RunConfiguration> activeRunConfiguration() const;
+ void setActiveRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration);
+
+ EditorConfiguration *editorConfiguration() const;
+
+ virtual Environment environment(const QString &buildConfiguration) const = 0;
+ virtual QString buildDirectory(const QString &buildConfiguration) const = 0;
+
+ void saveSettings();
+ void restoreSettings();
+
+ virtual BuildStepConfigWidget *createConfigWidget() = 0;
+ virtual QList<BuildStepConfigWidget*> subConfigWidgets();
+
+ // This method is called for new build configurations
+ // You should probably set some default values in this method
+ virtual void newBuildConfiguration(const QString &buildConfiguration) = 0;
+
+ virtual ProjectNode *rootProjectNode() const = 0;
+
+ enum FilesMode { AllFiles, ExcludeGeneratedFiles };
+ virtual QStringList files(FilesMode fileMode) const = 0;
+
+signals:
+ void fileListChanged();
+ void activeBuildConfigurationChanged();
+ void activeRunConfigurationChanged();
+ // This signal is jut there for updating the tree list in the buildsettings wizard
+ void buildConfigurationDisplayNameChanged(const QString &buildConfiguraiton);
+
+protected:
+ // This method is called when the project .user file is saved.
+ // Simply call writer.saveValue() for each value you want to save
+ // Make sure to always call your base class implementation
+ // Note: All the values from the project/buildsteps and buildconfigurations
+ // are automatically stored.
+ virtual void saveSettingsImpl(PersistentSettingsWriter &writer);
+ // This method is called when the project is opened
+ // You can retrieve all the values you saved in saveSettingsImpl()
+ // in this method.
+
+ // Note: This function is also called if there is no .user file
+ // You should probably add some default build and run settings to the project
+ // so that it can be build and run
+ virtual void restoreSettingsImpl(PersistentSettingsReader &reader);
+
+private:
+ BuildConfiguration *getBuildConfiguration(const QString & name) const;
+
+ QList<BuildStep *> m_buildSteps;
+ QList<BuildStep *> m_cleanSteps;
+ QStringList m_buildConfigurations;
+ QMap<QString, QVariant> m_values;
+ QList<BuildConfiguration *> m_buildConfigurationValues;
+ QString m_activeBuildConfiguration;
+ QList<QSharedPointer<RunConfiguration> > m_runConfigurations;
+ QSharedPointer<RunConfiguration> m_activeRunConfiguration;
+ EditorConfiguration *m_editorConfiguration;
+};
+
+} //namespace ProjectExplorer
+
+#endif //PROJECTINTERFACE_H
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
new file mode 100644
index 0000000000..5df721a9f9
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -0,0 +1,1814 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "applicationrunconfiguration.h"
+#include "allprojectsfilter.h"
+#include "allprojectsfind.h"
+#include "currentprojectfind.h"
+#include "buildmanager.h"
+#include "buildsettingspropertiespage.h"
+#include "editorsettingspropertiespage.h"
+#include "currentprojectfilter.h"
+#include "customexecutablerunconfiguration.h"
+#include "foldernavigationwidget.h"
+#include "iprojectmanager.h"
+#include "metatypedeclarations.h"
+#include "nodesvisitor.h"
+#include "outputwindow.h"
+#include "persistentsettings.h"
+#include "pluginfilefactory.h"
+#include "processstep.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+#include "projectfilewizardextension.h"
+#include "projecttreewidget.h"
+#include "projectwindow.h"
+#include "removefiledialog.h"
+#include "runsettingspropertiespage.h"
+#include "scriptwrappers.h"
+#include "session.h"
+#include "sessiondialog.h"
+
+#include <coreplugin/basemode.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mainwindow.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/findplaceholder.h>
+#include <coreplugin/basefilewizard.h>
+#include <coreplugin/mainwindow.h>
+#include <coreplugin/welcomemode.h>
+#include <coreplugin/vcsmanager.h>
+#include <coreplugin/iversioncontrol.h>
+#include <utils/listutils.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtCore/QDateTime>
+#include <QtGui/QAction>
+#include <QtGui/QFileDialog>
+#include <QtGui/QFileSystemModel>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMenu>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QToolBar>
+#include <QtGui/QMainWindow>
+#include <QtGui/QHeaderView>
+#include <QtGui/QInputDialog>
+
+Q_DECLARE_METATYPE(QSharedPointer<ProjectExplorer::RunConfiguration>);
+Q_DECLARE_METATYPE(Core::IEditorFactory *);
+
+namespace {
+bool debug = false;
+}
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+CoreListenerCheckingForRunningBuild::CoreListenerCheckingForRunningBuild(BuildManager *manager)
+ : Core::ICoreListener(0), m_manager(manager)
+{
+}
+
+bool CoreListenerCheckingForRunningBuild::coreAboutToClose()
+{
+ if (m_manager->isBuilding()) {
+ QMessageBox box;
+ QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Close"), QMessageBox::AcceptRole);
+ QPushButton *cancelClose = box.addButton(tr("Don't Close"), QMessageBox::RejectRole);
+ box.setDefaultButton(cancelClose);
+ box.setWindowTitle(tr("Close QtCreator?"));
+ box.setText(tr("A project is currently being built."));
+ box.setInformativeText(tr("Do you want to cancel the build process and close QtCreator anyway?"));
+ box.exec();
+ return (box.clickedButton() == closeAnyway);
+ }
+ return true;
+}
+
+ProjectExplorerPlugin *ProjectExplorerPlugin::m_instance = 0;
+
+ProjectExplorerPlugin::ProjectExplorerPlugin()
+ : m_buildConfigurationActionGroup(0),
+ m_runConfigurationActionGroup(0),
+ m_currentProject(0),
+ m_currentNode(0),
+ m_delayedRunConfiguration(0),
+ m_debuggingRunControl(0)
+{
+ m_instance = this;
+}
+
+ProjectExplorerPlugin::~ProjectExplorerPlugin()
+{
+ removeObject(this);
+}
+
+ProjectExplorerPlugin *ProjectExplorerPlugin::instance()
+{
+ return m_instance;
+}
+
+bool ProjectExplorerPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ m_core = pm->getObject<Core::ICore>();
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ addObject(this);
+
+ connect(m_core->fileManager(), SIGNAL(currentFileChanged(const QString&)),
+ this, SLOT(setCurrentFile(const QString&)));
+
+ m_session = new SessionManager(m_core, this);
+
+ connect(m_session, SIGNAL(projectAdded(ProjectExplorer::Project *)),
+ this, SIGNAL(fileListChanged()));
+ connect(m_session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project *)),
+ this, SLOT(invalidateProject(ProjectExplorer::Project *)));
+ connect(m_session, SIGNAL(projectRemoved(ProjectExplorer::Project *)),
+ this, SIGNAL(fileListChanged()));
+ connect(m_session, SIGNAL(startupProjectChanged(ProjectExplorer::Project *)),
+ this, SLOT(startupProjectChanged()));
+
+ m_proWindow = new ProjectWindow(m_core);
+
+ QList<int> globalcontext;
+ globalcontext.append(Core::Constants::C_GLOBAL_ID);
+
+ QList<int> pecontext;
+ pecontext << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_PROJECTEXPLORER);
+
+ Core::BaseMode *mode = new Core::BaseMode(tr("Projects"),
+ Constants::MODE_SESSION,
+ QIcon(QLatin1String(":/fancyactionbar/images/mode_Project.png")),
+ Constants::P_MODE_SESSION,
+ m_proWindow);
+ mode->setContext(QList<int>() << pecontext);
+ addAutoReleasedObject(mode);
+ m_proWindow->layout()->addWidget(new Core::FindToolBarPlaceHolder(mode));
+
+ m_buildManager = new BuildManager(this);
+ connect(m_buildManager, SIGNAL(buildStateChanged(ProjectExplorer::Project *)),
+ this, SLOT(buildStateChanged(ProjectExplorer::Project *)));
+ connect(m_buildManager, SIGNAL(buildQueueFinished(bool)),
+ this, SLOT(buildQueueFinished(bool)));
+ connect(m_buildManager, SIGNAL(tasksChanged()),
+ this, SLOT(updateTaskActions()));
+
+ addAutoReleasedObject(new CoreListenerCheckingForRunningBuild(m_buildManager));
+
+ m_outputPane = new OutputPane();
+ addAutoReleasedObject(m_outputPane);
+ connect(m_session, SIGNAL(projectRemoved(ProjectExplorer::Project *)),
+ m_outputPane, SLOT(projectRemoved()));
+
+ AllProjectsFilter *allProjectsFilter = new AllProjectsFilter(this, m_core);
+ addAutoReleasedObject(allProjectsFilter);
+
+ CurrentProjectFilter *currentProjectFilter = new CurrentProjectFilter(this, m_core);
+ addAutoReleasedObject(currentProjectFilter);
+
+ addAutoReleasedObject(new BuildSettingsPanelFactory);
+ addAutoReleasedObject(new RunSettingsPanelFactory);
+ addAutoReleasedObject(new EditorSettingsPanelFactory);
+
+ ProcessStepFactory *processStepFactory = new ProcessStepFactory;
+ addAutoReleasedObject(processStepFactory);
+
+ AllProjectsFind *allProjectsFind = new AllProjectsFind(this, m_core,
+ m_core->pluginManager()->getObject<Find::SearchResultWindow>());
+ addAutoReleasedObject(allProjectsFind);
+
+ CurrentProjectFind *currentProjectFind = new CurrentProjectFind(this, m_core,
+ m_core->pluginManager()->getObject<Find::SearchResultWindow>());
+ addAutoReleasedObject(currentProjectFind);
+
+ addAutoReleasedObject(new ApplicationRunConfigurationRunner);
+ addAutoReleasedObject(new CustomExecutableRunConfigurationFactory);
+
+ addAutoReleasedObject(new ProjectFileWizardExtension(m_core));
+
+ // context menus
+ Core::IActionContainer *msessionContextMenu =
+ am->createMenu(Constants::M_SESSIONCONTEXT);
+ Core::IActionContainer *mproject =
+ am->createMenu(Constants::M_PROJECTCONTEXT);
+ Core::IActionContainer *msubProject =
+ am->createMenu(Constants::M_SUBPROJECTCONTEXT);
+ Core::IActionContainer *mfolder =
+ am->createMenu(Constants::M_FOLDERCONTEXT);
+ Core::IActionContainer *mfilec =
+ am->createMenu(Constants::M_FILECONTEXT);
+
+ m_sessionContextMenu = msessionContextMenu->menu();
+ m_projectMenu = mproject->menu();
+ m_subProjectMenu = msubProject->menu();
+ m_folderMenu = mfolder->menu();
+ m_fileMenu = mfilec->menu();
+
+ Core::IActionContainer *mfile =
+ am->actionContainer(Core::Constants::M_FILE);
+ Core::IActionContainer *menubar =
+ am->actionContainer(Core::Constants::MENU_BAR);
+
+ // mode manager (for fancy actions)
+ Core::ModeManager *modeManager = m_core->modeManager();
+
+ // build menu
+ Core::IActionContainer *mbuild =
+ am->createMenu(Constants::M_BUILDPROJECT);
+ mbuild->menu()->setTitle("&Build");
+ menubar->addMenu(mbuild, Core::Constants::G_VIEW);
+
+ // debug menu
+ Core::IActionContainer *mdebug =
+ am->createMenu(Constants::M_DEBUG);
+ mdebug->menu()->setTitle("&Debug");
+ menubar->addMenu(mdebug, Core::Constants::G_VIEW);
+
+
+ //
+ // Groups
+ //
+
+ mbuild->appendGroup(Constants::G_BUILD_SESSION);
+ mbuild->appendGroup(Constants::G_BUILD_PROJECT);
+ mbuild->appendGroup(Constants::G_BUILD_OTHER);
+ mbuild->appendGroup(Constants::G_BUILD_RUN);
+ mbuild->appendGroup(Constants::G_BUILD_TASK);
+ mbuild->appendGroup(Constants::G_BUILD_CANCEL);
+
+ msessionContextMenu->appendGroup(Constants::G_SESSION_BUILD);
+ msessionContextMenu->appendGroup(Constants::G_SESSION_FILES);
+ msessionContextMenu->appendGroup(Constants::G_SESSION_OTHER);
+ msessionContextMenu->appendGroup(Constants::G_SESSION_CONFIG);
+
+ mproject->appendGroup(Constants::G_PROJECT_OPEN);
+ mproject->appendGroup(Constants::G_PROJECT_NEW);
+ mproject->appendGroup(Constants::G_PROJECT_BUILD);
+ mproject->appendGroup(Constants::G_PROJECT_RUN);
+ mproject->appendGroup(Constants::G_PROJECT_FILES);
+ mproject->appendGroup(Constants::G_PROJECT_OTHER);
+ mproject->appendGroup(Constants::G_PROJECT_CONFIG);
+
+ msubProject->appendGroup(Constants::G_PROJECT_OPEN);
+ msubProject->appendGroup(Constants::G_PROJECT_FILES);
+ msubProject->appendGroup(Constants::G_PROJECT_OTHER);
+ msubProject->appendGroup(Constants::G_PROJECT_CONFIG);
+
+ mfolder->appendGroup(Constants::G_FOLDER_FILES);
+ mfolder->appendGroup(Constants::G_FOLDER_OTHER);
+ mfolder->appendGroup(Constants::G_FOLDER_CONFIG);
+
+ mfilec->appendGroup(Constants::G_FILE_OPEN);
+ mfilec->appendGroup(Constants::G_FILE_OTHER);
+ mfilec->appendGroup(Constants::G_FILE_CONFIG);
+
+ // "open with" submenu
+ Core::IActionContainer * const openWith =
+ am->createMenu(ProjectExplorer::Constants::M_OPENFILEWITHCONTEXT);
+ m_openWithMenu = openWith->menu();
+ m_openWithMenu->setTitle(tr("Open With"));
+
+ connect(mfilec->menu(), SIGNAL(aboutToShow()), this, SLOT(populateOpenWithMenu()));
+ connect(m_openWithMenu, SIGNAL(triggered(QAction *)),
+ this, SLOT(openWithMenuTriggered(QAction *)));
+
+ //
+ // Separators
+ //
+
+ Core::ICommand *cmd;
+ QAction *sep;
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Build.Sep"), globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Files.Sep"), globalcontext);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_FILES);
+ mproject->addAction(cmd, Constants::G_PROJECT_FILES);
+ msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.New.Sep"), globalcontext);
+ mproject->addAction(cmd, Constants::G_PROJECT_NEW);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Config.Sep"), globalcontext);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_CONFIG);
+ mproject->addAction(cmd, Constants::G_PROJECT_CONFIG);
+ msubProject->addAction(cmd, Constants::G_PROJECT_CONFIG);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Close.Sep"), globalcontext);
+ mfile->addAction(cmd, Core::Constants::G_FILE_CLOSE);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Projects.Sep"), globalcontext);
+ mfile->addAction(cmd, Core::Constants::G_FILE_PROJECT);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Other.Sep"), globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_OTHER);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_OTHER);
+ mproject->addAction(cmd, Constants::G_PROJECT_OTHER);
+ msubProject->addAction(cmd, Constants::G_PROJECT_OTHER);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Run.Sep"), globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_RUN);
+ mproject->addAction(cmd, Constants::G_PROJECT_RUN);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.Task.Sep"), globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_TASK);
+
+ sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("ProjectExplorer.CancelBuild.Sep"), globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_CANCEL);
+
+ //
+ // Actions
+ //
+
+ // new session action
+ m_sessionManagerAction = new QAction(tr("Session Manager..."), this);
+ cmd = am->registerAction(m_sessionManagerAction, Constants::NEWSESSION, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence());
+
+ // new action
+ m_newAction = new QAction(tr("New Project..."), this);
+ cmd = am->registerAction(m_newAction, Constants::NEWPROJECT, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+N")));
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_FILES);
+
+#if 0
+ // open action
+ m_loadAction = new QAction(tr("Load Project..."), this);
+ cmd = am->registerAction(m_loadAction, Constants::LOAD, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+O")));
+ mfile->addAction(cmd, Core::Constants::G_FILE_PROJECT);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_FILES);
+#endif
+
+#if 0
+ // recent projects menu
+ Core::IActionContainer *mrecent =
+ am->createMenu(Constants::M_RECENTPROJECTS);
+ mrecent->menu()->setTitle("Recent Projects");
+ mfile->addMenu(mrecent, Core::Constants::G_FILE_PROJECT);
+ connect(mfile->menu(), SIGNAL(aboutToShow()),
+ this, SLOT(updateRecentProjectMenu()));
+#endif
+
+ // Default open action
+ m_openFileAction = new QAction(tr("Open File"), this);
+ cmd = am->registerAction(m_openFileAction, ProjectExplorer::Constants::OPENFILE,
+ globalcontext);
+ mfilec->addAction(cmd, Constants::G_FILE_OPEN);
+
+ // Open With menu
+ mfilec->addMenu(openWith, ProjectExplorer::Constants::G_FILE_OPEN);
+
+ // unload action
+ m_unloadAction = new QAction(tr("Unload Project"), this);
+ cmd = am->registerAction(m_unloadAction, Constants::UNLOAD, globalcontext);
+ cmd->setAttribute(Core::ICommand::CA_UpdateText);
+ cmd->setDefaultText(m_unloadAction->text());
+ mfile->addAction(cmd, Core::Constants::G_FILE_PROJECT);
+ mproject->addAction(cmd, Constants::G_PROJECT_FILES);
+
+ // unload session action
+ m_clearSession = new QAction(tr("Unload All Projects"), this);
+ cmd = am->registerAction(m_clearSession, Constants::CLEARSESSION, globalcontext);
+ mfile->addAction(cmd, Core::Constants::G_FILE_PROJECT);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_FILES);
+
+ // session menu
+ Core::IActionContainer *msession = am->createMenu(Constants::M_SESSION);
+ msession->menu()->setTitle("&Session");
+ mfile->addMenu(msession, Core::Constants::G_FILE_PROJECT);
+ m_sessionMenu = msession->menu();
+ connect(mfile->menu(), SIGNAL(aboutToShow()),
+ this, SLOT(updateSessionMenu()));
+
+ // build menu
+ Core::IActionContainer *mbc =
+ am->createMenu(Constants::BUILDCONFIGURATIONMENU);
+ m_buildConfigurationMenu = mbc->menu();
+ m_buildConfigurationMenu->setTitle(tr("Set Build Configuration"));
+ //TODO this means it is build twice, rrr
+ connect(mproject->menu(), SIGNAL(aboutToShow()), this, SLOT(populateBuildConfigurationMenu()));
+ connect(mbuild->menu(), SIGNAL(aboutToShow()), this, SLOT(populateBuildConfigurationMenu()));
+ connect(m_buildConfigurationMenu, SIGNAL(aboutToShow()), this, SLOT(populateBuildConfigurationMenu()));
+ connect(m_buildConfigurationMenu, SIGNAL(triggered(QAction *)), this, SLOT(buildConfigurationMenuTriggered(QAction *)));
+
+ // build session action
+ QIcon buildIcon(Constants::ICON_BUILD);
+ buildIcon.addFile(Constants::ICON_BUILD_SMALL);
+ m_buildSessionAction = new QAction(buildIcon, tr("Build All"), this);
+ cmd = am->registerAction(m_buildSessionAction, Constants::BUILDSESSION, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+B")));
+ mbuild->addAction(cmd, Constants::G_BUILD_SESSION);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD);
+ // Add to mode bar
+ modeManager->addAction(cmd, Constants::P_ACTION_BUILDSESSION, m_buildConfigurationMenu);
+
+
+ // rebuild session action
+ QIcon rebuildIcon(Constants::ICON_REBUILD);
+ rebuildIcon.addFile(Constants::ICON_REBUILD_SMALL);
+ m_rebuildSessionAction = new QAction(rebuildIcon, tr("Rebuild All"), this);
+ cmd = am->registerAction(m_rebuildSessionAction, Constants::REBUILDSESSION, globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_SESSION);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD);
+
+ // clean session
+ QIcon cleanIcon(Constants::ICON_CLEAN);
+ cleanIcon.addFile(Constants::ICON_CLEAN_SMALL);
+ m_cleanSessionAction = new QAction(cleanIcon, tr("Clean All"), this);
+ cmd = am->registerAction(m_cleanSessionAction, Constants::CLEANSESSION, globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_SESSION);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD);
+
+
+ // build action
+ m_buildAction = new QAction(tr("Build Project"), this);
+ cmd = am->registerAction(m_buildAction, Constants::BUILD, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+B")));
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
+ mproject->addAction(cmd, Constants::G_PROJECT_BUILD);
+
+ // rebuild action
+ m_rebuildAction = new QAction(tr("Rebuild Project"), this);
+ cmd = am->registerAction(m_rebuildAction, Constants::REBUILD, globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
+ mproject->addAction(cmd, Constants::G_PROJECT_BUILD);
+
+ // clean action
+ m_cleanAction = new QAction(tr("Clean Project"), this);
+ cmd = am->registerAction(m_cleanAction, Constants::CLEAN, globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
+ mproject->addAction(cmd, Constants::G_PROJECT_BUILD);
+
+ // Add Set Build Configuration to menu
+ mbuild->addMenu(mbc, Constants::G_BUILD_PROJECT);
+ mproject->addMenu(mbc, Constants::G_PROJECT_CONFIG);
+
+
+ // run action
+ QIcon runIcon(Constants::ICON_RUN);
+ runIcon.addFile(Constants::ICON_RUN_SMALL);
+ m_runAction = new QAction(runIcon, tr("Run"), this);
+ cmd = am->registerAction(m_runAction, Constants::RUN, globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+R")));
+ mbuild->addAction(cmd, Constants::G_BUILD_RUN);
+ mproject->addAction(cmd, Constants::G_PROJECT_RUN);
+
+ Core::IActionContainer *mrc = am->createMenu(Constants::RUNCONFIGURATIONMENU);
+ m_runConfigurationMenu = mrc->menu();
+ m_runConfigurationMenu->setTitle(tr("Set Run Configuration"));
+ mbuild->addMenu(mrc, Constants::G_BUILD_RUN);
+ mproject->addMenu(mrc, Constants::G_PROJECT_CONFIG);
+ // TODO this recreates the menu twice if shown in the Build or context menu
+ connect(m_runConfigurationMenu, SIGNAL(aboutToShow()), this, SLOT(populateRunConfigurationMenu()));
+ connect(mproject->menu(), SIGNAL(aboutToShow()), this, SLOT(populateRunConfigurationMenu()));
+ connect(mbuild->menu(), SIGNAL(aboutToShow()), this, SLOT(populateRunConfigurationMenu()));
+ connect(m_runConfigurationMenu, SIGNAL(triggered(QAction *)), this, SLOT(runConfigurationMenuTriggered(QAction *)));
+
+ modeManager->addAction(cmd, Constants::P_ACTION_RUN, m_runConfigurationMenu);
+
+ // jump to next task
+ m_taskAction = new QAction(tr("Go to Task Window"), this);
+ m_taskAction->setIcon(QIcon(Core::Constants::ICON_NEXT));
+ cmd = am->registerAction(m_taskAction, Constants::GOTOTASKWINDOW, globalcontext);
+ // FIXME: Eike, look here! cmd->setDefaultKeySequence(QKeySequence(tr("F9")));
+ mbuild->addAction(cmd, Constants::G_BUILD_TASK);
+
+ // cancel build action
+ m_cancelBuildAction = new QAction(tr("Cancel Build"), this);
+ cmd = am->registerAction(m_cancelBuildAction, Constants::CANCELBUILD, globalcontext);
+ mbuild->addAction(cmd, Constants::G_BUILD_CANCEL);
+
+ // debug action
+ QIcon debuggerIcon(":/projectexplorer/images/debugger_start_small.png");
+ debuggerIcon.addFile(":/gdbdebugger/images/debugger_start.png");
+ m_debugAction = new QAction(debuggerIcon, tr("Start Debugging"), this);
+ cmd = am->registerAction(m_debugAction, Constants::DEBUG, globalcontext);
+ cmd->setAttribute(Core::ICommand::CA_UpdateText);
+ cmd->setAttribute(Core::ICommand::CA_UpdateIcon);
+ cmd->setDefaultText(tr("Start Debugging"));
+ cmd->setDefaultKeySequence(QKeySequence(tr("F5")));
+ mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+ modeManager->addAction(cmd, Constants::P_ACTION_DEBUG, m_runConfigurationMenu);
+
+ // dependencies action
+ m_dependenciesAction = new QAction(tr("Edit Dependencies..."), this);
+ cmd = am->registerAction(m_dependenciesAction, Constants::DEPENDENCIES, pecontext);
+ msessionContextMenu->addAction(cmd, Constants::G_SESSION_CONFIG);
+
+ // add new file action
+ m_addNewFileAction = new QAction(tr("Add New..."), this);
+ cmd = am->registerAction(m_addNewFileAction, ProjectExplorer::Constants::ADDNEWFILE,
+ globalcontext);
+ mproject->addAction(cmd, Constants::G_PROJECT_FILES);
+ msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
+
+ // add existing file action
+ m_addExistingFilesAction = new QAction(tr("Add Existing Files..."), this);
+ cmd = am->registerAction(m_addExistingFilesAction, ProjectExplorer::Constants::ADDEXISTINGFILES,
+ globalcontext);
+ mproject->addAction(cmd, Constants::G_PROJECT_FILES);
+ msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
+
+ // remove file action
+ m_removeFileAction = new QAction(tr("Remove File..."), this);
+ cmd = am->registerAction(m_removeFileAction, ProjectExplorer::Constants::REMOVEFILE,
+ globalcontext);
+ mfilec->addAction(cmd, Constants::G_FILE_OTHER);
+
+ // renamefile action (TODO: Not supported yet)
+ m_renameFileAction = new QAction(tr("Rename"), this);
+ cmd = am->registerAction(m_renameFileAction, ProjectExplorer::Constants::RENAMEFILE,
+ globalcontext);
+ mfilec->addAction(cmd, Constants::G_FILE_OTHER);
+ m_renameFileAction->setEnabled(false);
+ m_renameFileAction->setVisible(false);
+
+ connect(m_core, SIGNAL(saveSettingsRequested()),
+ this, SLOT(savePersistentSettings()));
+
+ addAutoReleasedObject(new ProjectTreeWidgetFactory(m_core));
+ addAutoReleasedObject(new FolderNavigationWidgetFactory(m_core));
+
+ if (QSettings *s = m_core->settings())
+ m_recentProjects = s->value("ProjectExplorer/RecentProjects/Files", QStringList()).toStringList();
+ for (QStringList::iterator it = m_recentProjects.begin(); it != m_recentProjects.end(); ) {
+ if (QFileInfo(*it).isFile()) {
+ ++it;
+ } else {
+ it = m_recentProjects.erase(it);
+ }
+ }
+
+ connect(m_sessionManagerAction, SIGNAL(triggered()), this, SLOT(sessionManager()));
+ connect(m_newAction, SIGNAL(triggered()), this, SLOT(newProject()));
+#if 0
+ connect(m_loadAction, SIGNAL(triggered()), this, SLOT(loadAction()));
+#endif
+ connect(m_buildAction, SIGNAL(triggered()), this, SLOT(buildProject()));
+ connect(m_buildSessionAction, SIGNAL(triggered()), this, SLOT(buildSession()));
+ connect(m_rebuildAction, SIGNAL(triggered()), this, SLOT(rebuildProject()));
+ connect(m_rebuildSessionAction, SIGNAL(triggered()), this, SLOT(rebuildSession()));
+ connect(m_cleanAction, SIGNAL(triggered()), this, SLOT(cleanProject()));
+ connect(m_cleanSessionAction, SIGNAL(triggered()), this, SLOT(cleanSession()));
+ connect(m_runAction, SIGNAL(triggered()), this, SLOT(runProject()));
+ connect(m_cancelBuildAction, SIGNAL(triggered()), this, SLOT(cancelBuild()));
+ connect(m_debugAction, SIGNAL(triggered()), this, SLOT(debugProject()));
+ connect(m_dependenciesAction, SIGNAL(triggered()), this, SLOT(editDependencies()));
+ connect(m_unloadAction, SIGNAL(triggered()), this, SLOT(unloadProject()));
+ connect(m_clearSession, SIGNAL(triggered()), this, SLOT(clearSession()));
+ connect(m_taskAction, SIGNAL(triggered()), this, SLOT(goToTaskWindow()));
+ connect(m_addNewFileAction, SIGNAL(triggered()), this, SLOT(addNewFile()));
+ connect(m_addExistingFilesAction, SIGNAL(triggered()), this, SLOT(addExistingFiles()));
+ connect(m_openFileAction, SIGNAL(triggered()), this, SLOT(openFile()));
+ connect(m_removeFileAction, SIGNAL(triggered()), this, SLOT(removeFile()));
+ connect(m_renameFileAction, SIGNAL(triggered()), this, SLOT(renameFile()));
+
+ updateActions();
+
+ connect(m_core, SIGNAL(coreOpened()), this, SLOT(restoreSession()));
+
+ return true;
+}
+
+// Find a factory by file mime type in a sequence of factories
+template <class Factory, class Iterator>
+ Factory *findFactory(const QString &mimeType, Iterator i1, Iterator i2)
+{
+ for ( ; i1 != i2; ++i2) {
+ Factory *f = *i1;
+ if (f->mimeTypes().contains(mimeType))
+ return f;
+ }
+ return 0;
+}
+
+ProjectFileFactory * ProjectExplorerPlugin::findProjectFileFactory(const QString &filename) const
+{
+ // Find factory
+ if (const Core::MimeType mt = m_core->mimeDatabase()->findByFile(QFileInfo(filename)))
+ if (ProjectFileFactory *pf = findFactory<ProjectFileFactory>(mt.type(), m_fileFactories.constBegin(), m_fileFactories.constEnd()))
+ return pf;
+ qWarning("Unable to find project file factory for '%s'", filename.toUtf8().constData());
+ return 0;
+}
+
+void ProjectExplorerPlugin::loadAction()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::loadAction";
+
+
+ QString dir = m_lastOpenDirectory;
+
+ // for your special convenience, we preselect a pro file if it is
+ // the current file
+ if (Core::IEditor *editor = Core::EditorManager::instance()->currentEditor()) {
+ if (const Core::IFile *file = editor->file()) {
+ const QString fn = file->fileName();
+ const bool isProject = m_profileMimeTypes.contains(file->mimeType());
+ dir = isProject ? fn : QFileInfo(fn).absolutePath();
+ }
+ }
+
+ QString filename = QFileDialog::getOpenFileName(0, tr("Load Project"),
+ dir,
+ m_projectFilterString);
+ if (filename.isEmpty())
+ return;
+ if (ProjectFileFactory *pf = findProjectFileFactory(filename))
+ pf->open(filename);
+ updateActions();
+}
+
+bool ProjectExplorerPlugin::saveAction(Project *pro)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::saveAction";
+
+ if (!pro)
+ pro = m_currentProject;
+ Q_ASSERT(pro);
+
+ Core::IFile *fi = pro->file();
+
+ if (!fi) // TODO Why saving the session here????
+ fi = m_session->file();
+
+ if (!fi || fi->fileName().isEmpty()) //nothing to save?
+ return false;
+
+ QList<Core::IFile*> filesToSave;
+
+ filesToSave << fi;
+ if (pro)
+ filesToSave << pro->dependencies();
+
+ // check the number of modified files
+ int readonlycount = 0;
+ foreach (const Core::IFile *file, filesToSave) {
+ if (file->isReadOnly())
+ ++readonlycount;
+ }
+
+ bool success = false;
+ if (readonlycount > 0)
+ success = m_core->fileManager()->saveModifiedFiles(filesToSave).isEmpty();
+ else
+ success = m_core->fileManager()->saveModifiedFilesSilently(filesToSave).isEmpty();
+
+ if (success)
+ addToRecentProjects(fi->fileName());
+ updateActions();
+ return success;
+}
+
+void ProjectExplorerPlugin::unloadProject()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::unloadProject";
+
+ if (!saveAction(m_currentProject))
+ return;
+
+ m_session->removeProject(m_currentProject);
+ updateActions();
+}
+
+void ProjectExplorerPlugin::clearSession()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::clearSession";
+
+ if (!m_session->clear())
+ return; // Action has been cancelled
+ updateActions();
+}
+
+void ProjectExplorerPlugin::extensionsInitialized()
+{
+ m_fileFactories = ProjectFileFactory::createFactories(m_core, &m_projectFilterString);
+ foreach(ProjectFileFactory *pf, m_fileFactories) {
+ m_profileMimeTypes += pf->mimeTypes();
+ addAutoReleasedObject(pf);
+ }
+}
+
+void ProjectExplorerPlugin::shutdown()
+{
+ m_session->clear();
+// m_proWindow->saveConfigChanges();
+}
+
+void ProjectExplorerPlugin::newProject()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::newProject";
+
+ QString defaultLocation;
+ if (currentProject()) {
+ const QFileInfo file(currentProject()->file()->fileName());
+ QDir dir = file.dir();
+ dir.cdUp();
+ defaultLocation = dir.absolutePath();
+ }
+
+ m_core->showNewItemDialog(tr("New Project", "Title of dialog"),
+ Core::BaseFileWizard::findWizardsOfKind(Core::IWizard::ProjectWizard),
+ defaultLocation);
+ updateActions();
+}
+
+void ProjectExplorerPlugin::sessionManager()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::newSession";
+
+ if (m_session->isDefaultVirgin()) {
+ // do not save new virgin default sessions
+ } else {
+ m_session->save();
+ }
+ SessionDialog sessionDialog(m_session, m_session->activeSession(), false);
+ sessionDialog.exec();
+
+ updateActions();
+}
+
+void ProjectExplorerPlugin::setStartupProject(Project *project)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::setStartupProject";
+
+ if (!project)
+ project = m_currentProject;
+ Q_ASSERT(project);
+ m_session->setStartupProject(project);
+ // NPE: Visually mark startup project
+ updateActions();
+}
+
+void ProjectExplorerPlugin::savePersistentSettings()
+{
+ if (debug)
+ qDebug()<<"ProjectExplorerPlugin::savePersistentSettings()";
+
+ foreach (Project *pro, m_session->projects())
+ pro->saveSettings();
+
+ if (m_session->isDefaultVirgin()) {
+ // do not save new virgin default sessions
+ } else {
+ m_session->save();
+ }
+
+ QSettings *s = m_core->settings();
+ if (s) {
+ s->setValue("ProjectExplorer/StartupSession", m_session->file()->fileName());
+ s->setValue("ProjectExplorer/RecentProjects/Files", m_recentProjects);
+ }
+}
+
+bool ProjectExplorerPlugin::openProject(const QString &fileName)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::openProject";
+
+ if (openProjects(QStringList() << fileName)) {
+ addToRecentProjects(fileName);
+ return true;
+ }
+ return false;
+}
+
+bool ProjectExplorerPlugin::openProjects(const QStringList &fileNames)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin - opening projects " << fileNames;
+
+ QList<IProjectManager*> projectManagers =
+ m_core->pluginManager()->getObjects<IProjectManager>();
+
+ //QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ // bool blocked = blockSignals(true);
+ QList<Project*> openedPro;
+ foreach (QString fileName, fileNames)
+ if (const Core::MimeType mt = m_core->mimeDatabase()->findByFile(QFileInfo(fileName))) {
+ foreach (IProjectManager *manager, projectManagers)
+ if (manager->mimeType() == mt.type()) {
+ if (Project *pro = manager->openProject(fileName))
+ openedPro += pro;
+ m_session->reportProjectLoadingProgress();
+ break;
+ }
+ }
+ //blockSignals(blocked);
+
+ if (openedPro.isEmpty()) {
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin - Could not open any projects!";
+ QApplication::restoreOverrideCursor();
+ return false;
+ }
+
+ foreach (Project *pro, openedPro) {
+ if (debug)
+ qDebug()<<"restoring settings for "<<pro->file()->fileName();
+ pro->restoreSettings();
+ connect(pro, SIGNAL(fileListChanged()), this, SIGNAL(fileListChanged()));
+ }
+ m_session->addProjects(openedPro);
+
+ // Make sure we always have a current project / node
+ if (!m_currentProject)
+ setCurrentNode(openedPro.first()->rootProjectNode());
+
+ updateActions();
+
+ m_core->modeManager()->activateMode(Core::Constants::MODE_EDIT);
+ QApplication::restoreOverrideCursor();
+
+ return true;
+}
+
+Project *ProjectExplorerPlugin::currentProject() const
+{
+ if (debug) {
+ if (m_currentProject)
+ qDebug() << "ProjectExplorerPlugin::currentProject returns " << m_currentProject->name();
+ else
+ qDebug() << "ProjectExplorerPlugin::currentProject returns 0";
+ }
+ return m_currentProject;
+}
+
+Node *ProjectExplorerPlugin::currentNode() const
+{
+ return m_currentNode;
+}
+
+void ProjectExplorerPlugin::setCurrentFile(Project *project, const QString &filePath)
+{
+ setCurrent(project, filePath, 0);
+}
+
+void ProjectExplorerPlugin::setCurrentFile(const QString &filePath)
+{
+ Project *project = m_session->projectForFile(filePath);
+ setCurrent(project, filePath, 0);
+}
+
+void ProjectExplorerPlugin::setCurrentNode(Node *node)
+{
+ setCurrent(m_session->projectForNode(node), QString(), node);
+}
+
+SessionManager *ProjectExplorerPlugin::session() const
+{
+ return m_session;
+}
+
+Project *ProjectExplorerPlugin::startupProject() const
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::startupProject";
+
+ Project *pro = m_session->startupProject();
+
+ if (!pro)
+ pro = m_currentProject;
+
+ return pro;
+}
+
+// update welcome page
+void ProjectExplorerPlugin::updateWelcomePage(Core::Internal::WelcomeMode *welcomeMode)
+{
+ Core::Internal::WelcomeMode::WelcomePageData welcomePageData;
+ welcomePageData.sessionList = m_session->sessions();
+ welcomePageData.activeSession = m_session->activeSession();
+ welcomePageData.previousSession = m_session->lastSession();
+ welcomePageData.projectList = m_recentProjects;
+ welcomeMode->updateWelcomePage(welcomePageData);
+}
+
+void ProjectExplorerPlugin::currentModeChanged(Core::IMode *mode)
+{
+ if (Core::Internal::WelcomeMode *welcomeMode = qobject_cast<Core::Internal::WelcomeMode*>(mode))
+ updateWelcomePage(welcomeMode);
+}
+
+/*!
+ \fn void ProjectExplorerPlugin::restoreSession()
+
+ This method is connected to the ICore::coreOpened signal. If
+ there was no session explicitly loaded, it creates an empty new
+ default session and puts the list of recent projects and sessions
+ onto the welcome page.
+*/
+
+void ProjectExplorerPlugin::restoreSession()
+{
+
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::restoreSession";
+
+ QStringList sessions = m_session->sessions();
+
+ // We have command line arguments, try to find a session in them
+ QStringList arguments = ExtensionSystem::PluginManager::instance()->arguments();
+
+ // Default to no session loading
+ QString sessionToLoad = QString::null;
+ if (!arguments.isEmpty()) {
+ foreach (const QString &arg, arguments) {
+ if (sessions.contains(arg)) {
+ // Session argument
+ sessionToLoad = arg;
+ arguments.removeOne(arg);
+ if (debug)
+ qDebug()<< "Found session argument, loading session"<<sessionToLoad;
+ break;
+ }
+ }
+ }
+
+ // Restore latest session or what was passed on the command line
+ if (sessionToLoad == QString::null) {
+ m_session->createAndLoadNewDefaultSession();
+ } else {
+ m_session->loadSession(sessionToLoad);
+ }
+
+ // update welcome page
+ Core::ModeManager *modeManager = m_core->modeManager();
+ connect(modeManager, SIGNAL(currentModeChanged(Core::IMode*)), this, SLOT(currentModeChanged(Core::IMode*)));
+ if (Core::Internal::WelcomeMode *welcomeMode = qobject_cast<Core::Internal::WelcomeMode*>(modeManager->mode(Core::Constants::MODE_WELCOME))) {
+ updateWelcomePage(welcomeMode);
+ connect(welcomeMode, SIGNAL(requestSession(QString)), this, SLOT(loadSession(QString)));
+ connect(welcomeMode, SIGNAL(requestProject(QString)), this, SLOT(loadProject(QString)));
+ }
+
+ m_core->openFiles(arguments);
+ updateActions();
+
+}
+
+void ProjectExplorerPlugin::loadSession(const QString &session)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::loadSession" << session;
+ m_session->loadSession(session);
+}
+
+
+void ProjectExplorerPlugin::showContextMenu(const QPoint &globalPos, Node *node)
+{
+ QMenu *contextMenu = 0;
+
+ updateContextMenuActions();
+
+ if (!node)
+ node = m_session->sessionNode();
+
+ if (node->nodeType() != SessionNodeType) {
+ Project *project = m_session->projectForNode(node);
+ setCurrentNode(node);
+
+ emit aboutToShowContextMenu(project, node);
+ switch (node->nodeType()) {
+ case ProjectNodeType:
+ if (node->parentFolderNode() == m_session->sessionNode())
+ contextMenu = m_projectMenu;
+ else
+ contextMenu = m_subProjectMenu;
+ break;
+ case FolderNodeType:
+ contextMenu = m_folderMenu;
+ break;
+ case FileNodeType:
+ contextMenu = m_fileMenu;
+ break;
+ default:
+ qWarning("ProjectExplorerPlugin::showContextMenu - Missing handler for node type");
+ }
+ } else { // session item
+ emit aboutToShowContextMenu(0, node);
+
+ contextMenu = m_sessionContextMenu;
+ }
+
+ if (contextMenu && contextMenu->actions().count() > 0) {
+ contextMenu->popup(globalPos);
+ }
+}
+
+BuildManager *ProjectExplorerPlugin::buildManager() const
+{
+ return m_buildManager;
+}
+
+void ProjectExplorerPlugin::buildStateChanged(Project * pro)
+{
+ if (debug) {
+ qDebug() << "buildStateChanged";
+ qDebug() << pro->file()->fileName() << "isBuilding()" << m_buildManager->isBuilding(pro);
+ }
+ Q_UNUSED(pro);
+ updateActions();
+}
+
+void ProjectExplorerPlugin::buildQueueFinished(bool success)
+{
+ if (debug)
+ qDebug() << "buildQueueFinished()" << success;
+
+ updateActions();
+
+ if (success && m_delayedRunConfiguration) {
+ IRunConfigurationRunner *runner = findRunner(m_delayedRunConfiguration, m_runMode);
+ if (runner) {
+ emit aboutToExecuteProject(m_delayedRunConfiguration->project());
+
+ RunControl *control = runner->run(m_delayedRunConfiguration, m_runMode);
+ m_outputPane->createNewOutputWindow(control);
+ m_outputPane->popup(false);
+ m_outputPane->showTabFor(control);
+
+ connect(control, SIGNAL(addToOutputWindow(RunControl *, const QString &)),
+ this, SLOT(addToApplicationOutputWindow(RunControl *, const QString &)));
+ connect(control, SIGNAL(error(RunControl *, const QString &)),
+ this, SLOT(addErrorToApplicationOutputWindow(RunControl *, const QString &)));
+ connect(control, SIGNAL(finished()),
+ this, SLOT(runControlFinished()));
+ control->start();
+
+
+ if (m_runMode == ProjectExplorer::Constants::DEBUGMODE)
+ m_debuggingRunControl = control;
+
+ updateRunAction();
+ }
+ } else {
+ if (m_buildManager->tasksAvailable())
+ m_buildManager->showTaskWindow();
+ }
+
+ m_delayedRunConfiguration = QSharedPointer<RunConfiguration>(0);
+ m_runMode = QString::null;
+}
+
+void ProjectExplorerPlugin::updateTaskActions()
+{
+ m_taskAction->setEnabled(m_buildManager->tasksAvailable());
+}
+
+void ProjectExplorerPlugin::setCurrent(Project *project, QString filePath, Node *node)
+{
+ if (debug)
+ qDebug() << "ProjectExplorer - setting path to " << (node ? node->path() : filePath)
+ << " and project to " << (project ? project->name() : "0");
+
+ if (node)
+ filePath = node->path();
+ else
+ node = m_session->nodeForFile(filePath);
+
+ bool projectChanged = false;
+ if (m_currentProject != project) {
+ int oldContext = -1;
+ int newContext = -1;
+ int oldLanguageID = -1;
+ int newLanguageID = -1;
+ if (m_currentProject) {
+ oldContext = m_currentProject->projectManager()->projectContext();
+ oldLanguageID = m_currentProject->projectManager()->projectLanguage();
+ }
+ if (project) {
+ newContext = project->projectManager()->projectContext();
+ newLanguageID = project->projectManager()->projectLanguage();
+ }
+ m_core->removeAdditionalContext(oldContext);
+ m_core->removeAdditionalContext(oldLanguageID);
+ m_core->addAdditionalContext(newContext);
+ m_core->addAdditionalContext(newLanguageID);
+ m_core->updateContext();
+
+ m_currentProject = project;
+
+ projectChanged = true;
+ }
+
+ if (projectChanged || m_currentNode != node) {
+ m_currentNode = node;
+ if (debug)
+ qDebug() << "ProjectExplorer - currentNodeChanged(" << node->path() << ", " << (project ? project->name() : "0") << ")";
+ emit currentNodeChanged(m_currentNode, project);
+ }
+ if (projectChanged) {
+ if (debug)
+ qDebug() << "ProjectExplorer - currentProjectChanged(" << (project ? project->name() : "0") << ")";
+ emit currentProjectChanged(project);
+ updateActions();
+ }
+
+ m_core->fileManager()->setCurrentFile(filePath);
+}
+
+void ProjectExplorerPlugin::updateActions()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::updateActions";
+
+ bool enableBuildActions = m_currentProject && ! (m_buildManager->isBuilding(m_currentProject));
+ bool hasProjects = !m_session->projects().isEmpty();
+ bool building = m_buildManager->isBuilding();
+
+ if (debug)
+ qDebug()<<"BuildManager::isBuilding()"<<building;
+
+ m_unloadAction->setEnabled(m_currentProject != 0);
+ if (m_currentProject == 0) {
+ m_unloadAction->setText(tr("Unload Project"));
+ m_buildAction->setText(tr("Build Project"));
+ } else {
+ m_unloadAction->setText(tr("Unload Project \"%1\"").arg(m_currentProject->name()));
+ m_buildAction->setText(tr("Build Project \"%1\"").arg(m_currentProject->name()));
+ }
+
+ m_buildAction->setEnabled(enableBuildActions);
+ m_rebuildAction->setEnabled(enableBuildActions);
+ m_cleanAction->setEnabled(enableBuildActions);
+ m_clearSession->setEnabled(hasProjects && !building);
+ m_buildSessionAction->setEnabled(hasProjects && !building);
+ m_rebuildSessionAction->setEnabled(hasProjects && !building);
+ m_cleanSessionAction->setEnabled(hasProjects && !building);
+ m_cancelBuildAction->setEnabled(building);
+ m_dependenciesAction->setEnabled(hasProjects && !building);
+
+ updateRunAction();
+
+ updateTaskActions();
+}
+
+// NBS TODO check projectOrder()
+// what we want here is all the projects pro depends on
+QStringList ProjectExplorerPlugin::allFilesWithDependencies(Project *pro)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::allFilesWithDependencies(" << pro->file()->fileName() << ")";
+
+ QStringList filesToSave;
+ foreach(Project *p, m_session->projectOrder(pro)) {
+ FindAllFilesVisitor filesVisitor;
+ p->rootProjectNode()->accept(&filesVisitor);
+ filesToSave << filesVisitor.filePaths();
+ }
+ qSort(filesToSave);
+ return filesToSave;
+}
+
+bool ProjectExplorerPlugin::saveModifiedFiles(const QList<Project *> & projects)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::saveModifiedFiles";
+
+ QList<Core::IFile *> modifiedFi = m_core->fileManager()->modifiedFiles();
+ QMap<QString, Core::IFile *> modified;
+
+ QStringList allFiles;
+ foreach (Project *pro, projects)
+ allFiles << allFilesWithDependencies(pro);
+
+ foreach (Core::IFile * fi, modifiedFi)
+ modified.insert(fi->fileName(), fi);
+
+ QList<Core::IFile *> filesToSave;
+
+ QMap<QString, Core::IFile *>::const_iterator mit = modified.constBegin();
+ QStringList::const_iterator ait = allFiles.constBegin();
+ QMap<QString, Core::IFile *>::const_iterator mend = modified.constEnd();
+ QStringList::const_iterator aend = allFiles.constEnd();
+
+ while (mit != mend && ait != aend) {
+ if (mit.key() < *ait)
+ ++mit;
+ else if (*ait < mit.key())
+ ++ait;
+ else {
+ filesToSave.append(mit.value());
+ ++ait;
+ ++mit;
+ }
+ }
+
+ if (!filesToSave.isEmpty()) {
+ bool cancelled;
+ m_core->fileManager()->saveModifiedFiles(filesToSave, &cancelled,
+ tr("The following dependencies are modified, do you want to save them?"));
+ if (cancelled) {
+ return false;
+ }
+ }
+ return true;
+}
+
+//NBS handle case where there is no activeBuildConfiguration
+// because someone delete all build configurations
+
+void ProjectExplorerPlugin::buildProject()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::buildProject";
+
+ if (saveModifiedFiles(QList<Project *>() << m_currentProject))
+ buildManager()->buildProject(m_currentProject, m_currentProject->activeBuildConfiguration());
+}
+
+void ProjectExplorerPlugin::buildSession()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::buildSession";
+
+ const QList<Project *> & projects = m_session->projectOrder();
+ if (saveModifiedFiles(projects)) {
+ QStringList configurations;
+ foreach (const Project * pro, projects)
+ configurations << pro->activeBuildConfiguration();
+
+ m_buildManager->buildProjects(projects, configurations);
+ }
+}
+
+void ProjectExplorerPlugin::rebuildProject()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::rebuildProject";
+
+ if (saveModifiedFiles(QList<Project *>() << m_currentProject)) {
+ m_buildManager->cleanProject(m_currentProject, m_currentProject->activeBuildConfiguration());
+ m_buildManager->buildProject(m_currentProject, m_currentProject->activeBuildConfiguration());
+ }
+}
+
+void ProjectExplorerPlugin::rebuildSession()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::rebuildSession";
+
+ const QList<Project *> & projects = m_session->projectOrder();
+ if (saveModifiedFiles(projects)) {
+ QStringList configurations;
+ foreach (const Project * pro, projects)
+ configurations << pro->activeBuildConfiguration();
+
+ m_buildManager->cleanProjects(projects, configurations);
+ m_buildManager->buildProjects(projects, configurations);
+ }
+}
+
+void ProjectExplorerPlugin::cleanProject()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::cleanProject";
+
+ if (saveModifiedFiles(QList<Project *>() << m_currentProject))
+ m_buildManager->cleanProject(m_currentProject, m_currentProject->activeBuildConfiguration());
+}
+
+void ProjectExplorerPlugin::cleanSession()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::cleanSession";
+
+ const QList<Project *> & projects = m_session->projectOrder();
+ if (saveModifiedFiles(projects)) {
+ QStringList configurations;
+ foreach (const Project * pro, projects)
+ configurations << pro->activeBuildConfiguration();
+
+ m_buildManager->cleanProjects(projects, configurations);
+ }
+}
+
+void ProjectExplorerPlugin::runProject()
+{
+ Project *pro = startupProject();
+ if (!pro)
+ return;
+
+ if (saveModifiedFiles(QList<Project *>() << pro)) {
+ m_runMode = ProjectExplorer::Constants::RUNMODE;
+
+ m_delayedRunConfiguration = pro->activeRunConfiguration();
+ //NBS TODO make the build project step take into account project dependencies
+ m_buildManager->buildProject(pro, pro->activeBuildConfiguration());
+ }
+}
+
+void ProjectExplorerPlugin::debugProject()
+{
+ Project *pro = startupProject();
+ if (!pro || m_debuggingRunControl)
+ return;
+
+ if (saveModifiedFiles(QList<Project *>() << pro)) {
+ m_runMode = ProjectExplorer::Constants::DEBUGMODE;
+ m_delayedRunConfiguration = pro->activeRunConfiguration();
+ //NBS TODO make the build project step take into account project dependencies
+ m_buildManager->buildProject(pro, pro->activeBuildConfiguration());
+ }
+}
+
+void ProjectExplorerPlugin::addToApplicationOutputWindow(RunControl *rc, const QString &line)
+{
+ m_outputPane->appendOutput(rc, line);
+}
+
+void ProjectExplorerPlugin::addErrorToApplicationOutputWindow(RunControl *rc, const QString &error)
+{
+ m_outputPane->appendOutput(rc, error);
+}
+
+void ProjectExplorerPlugin::runControlFinished()
+{
+ if (sender() == m_debuggingRunControl)
+ m_debuggingRunControl = 0;
+
+ updateRunAction();
+}
+
+void ProjectExplorerPlugin::startupProjectChanged()
+{
+ static QPointer<Project> previousStartupProject = 0;
+ Project *project = startupProject();
+ if (project == previousStartupProject)
+ return;
+
+ if (previousStartupProject) {
+ disconnect(previousStartupProject, SIGNAL(activeRunConfigurationChanged()),
+ this, SLOT(updateRunAction()));
+ }
+
+ previousStartupProject = project;
+
+ if (project) {
+ connect(project, SIGNAL(activeRunConfigurationChanged()),
+ this, SLOT(updateRunAction()));
+ }
+
+ updateRunAction();
+}
+
+// NBS TODO implement more than one runner
+IRunConfigurationRunner *ProjectExplorerPlugin::findRunner(QSharedPointer<RunConfiguration> config, const QString &mode)
+{
+ const QList<IRunConfigurationRunner *> runners = m_core->pluginManager()->getObjects<IRunConfigurationRunner>();
+ foreach (IRunConfigurationRunner *runner, runners)
+ if (runner->canRun(config, mode))
+ return runner;
+ return 0;
+}
+
+void ProjectExplorerPlugin::updateRunAction()
+{
+ const Project *project = startupProject();
+ const bool canRun = project && findRunner(project->activeRunConfiguration(), ProjectExplorer::Constants::RUNMODE);
+ const bool canDebug = project && !m_debuggingRunControl && findRunner(project->activeRunConfiguration(), ProjectExplorer::Constants::DEBUGMODE);
+ const bool building = m_buildManager->isBuilding();
+ m_runAction->setEnabled(canRun && !building);
+ m_debugAction->setEnabled(canDebug && !building);
+}
+
+void ProjectExplorerPlugin::cancelBuild()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::cancelBuild";
+
+ if (m_buildManager->isBuilding())
+ m_buildManager->cancel();
+}
+
+void ProjectExplorerPlugin::editDependencies()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::editDependencies";
+
+ m_session->editDependencies();
+}
+
+void ProjectExplorerPlugin::addToRecentProjects(const QString &fileName)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::addToRecentProjects(" << fileName << ")";
+
+ if (fileName.isEmpty())
+ return;
+ QString prettyFileName(QDir::toNativeSeparators(fileName));
+ m_recentProjects.removeAll(prettyFileName);
+ if (m_recentProjects.count() > m_maxRecentProjects)
+ m_recentProjects.removeLast();
+ m_recentProjects.prepend(prettyFileName);
+ QFileInfo fi(prettyFileName);
+ m_lastOpenDirectory = fi.absolutePath();
+}
+
+void ProjectExplorerPlugin::updateRecentProjectMenu()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::updateRecentProjectMenu";
+
+ Core::IActionContainer *aci =
+ m_core->actionManager()->actionContainer(Constants::M_RECENTPROJECTS);
+ QMenu *menu = aci->menu();
+ menu->clear();
+ m_recentProjectsActions.clear();
+
+ menu->setEnabled(!m_recentProjects.isEmpty());
+
+ //projects (ignore sessions, they used to be in this list)
+ foreach (const QString &s, m_recentProjects) {
+ if (s.endsWith(".qws"))
+ continue;
+ QAction *action = menu->addAction(s);
+ m_recentProjectsActions.insert(action, s);
+ connect(action, SIGNAL(triggered()), this, SLOT(openRecentProject()));
+ }
+}
+
+void ProjectExplorerPlugin::openRecentProject()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::openRecentProject()";
+
+ QAction *a = qobject_cast<QAction*>(sender());
+ if (m_recentProjectsActions.contains(a)) {
+ const QString fileName = m_recentProjectsActions.value(a);
+ if (ProjectFileFactory *pf = findProjectFileFactory(fileName))
+ pf->open(fileName);
+ }
+}
+
+void ProjectExplorerPlugin::invalidateProject(Project *project)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::invalidateProject" << project->name();
+ if (m_currentProject == project) {
+ //
+ // Workaround for a bug in QItemSelectionModel
+ // - currentChanged etc are not emitted if the
+ // item is removed from the underlying data model
+ //
+ setCurrent(0, QString(), 0);
+ }
+
+ disconnect(project, SIGNAL(fileListChanged()), this, SIGNAL(fileListChanged()));
+}
+
+void ProjectExplorerPlugin::goToTaskWindow()
+{
+ m_buildManager->gotoTaskWindow();
+}
+
+void ProjectExplorerPlugin::updateContextMenuActions()
+{
+ if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(m_currentNode)) {
+ const bool addFilesEnabled = projectNode->supportedActions().contains(ProjectNode::AddFile);
+ m_addExistingFilesAction->setEnabled(addFilesEnabled);
+ m_addNewFileAction->setEnabled(addFilesEnabled);
+ } else if (FileNode *fileNode = qobject_cast<FileNode*>(m_currentNode)) {
+ const bool removeFileEnabled = fileNode->projectNode()->supportedActions().contains(ProjectNode::RemoveFile);
+ m_removeFileAction->setEnabled(removeFileEnabled);
+ }
+}
+
+void ProjectExplorerPlugin::addNewFile()
+{
+ Q_ASSERT(m_currentNode && m_currentNode->nodeType() == ProjectNodeType);
+ const QString location = QFileInfo(m_currentNode->path()).dir().absolutePath();
+ m_core->showNewItemDialog(tr("New File", "Title of dialog"),
+ Core::BaseFileWizard::findWizardsOfKind(Core::IWizard::FileWizard)
+ + Core::BaseFileWizard::findWizardsOfKind(Core::IWizard::ClassWizard),
+ location);
+}
+
+void ProjectExplorerPlugin::addExistingFiles()
+{
+ Q_ASSERT(m_currentNode && m_currentNode->nodeType() == ProjectNodeType);
+ ProjectNode *projectNode = qobject_cast<ProjectNode*>(m_currentNode);
+ const QString dir = QFileInfo(m_currentNode->path()).dir().absolutePath();
+ QStringList fileNames = QFileDialog::getOpenFileNames(m_core->mainWindow(), tr("Add Existing Files"), dir);
+ if (fileNames.isEmpty())
+ return;
+
+ QHash<FileType, QString> fileTypeToFiles;
+ foreach (const QString &fileName, fileNames) {
+ FileType fileType = typeForFileName(m_core->mimeDatabase(), QFileInfo(fileName));
+ fileTypeToFiles.insertMulti(fileType, fileName);
+ }
+
+ QStringList notAdded;
+ foreach (const FileType type, fileTypeToFiles.uniqueKeys()) {
+ projectNode->addFiles(type, fileTypeToFiles.values(type), &notAdded);
+ }
+ if (!notAdded.isEmpty()) {
+ QString message = tr("Could not add following files to project %1:\n").arg(projectNode->name());
+ QString files = notAdded.join("\n");
+ QMessageBox::warning(m_core->mainWindow(), tr("Add files to project failed"),
+ message + files);
+ foreach (const QString &file, notAdded)
+ fileNames.removeOne(file);
+ }
+
+ if (Core::IVersionControl *vcManager = m_core->vcsManager()->findVersionControlForDirectory(dir)) {
+ const QString files = fileNames.join("\n");
+ QMessageBox::StandardButton button =
+ QMessageBox::question(m_core->mainWindow(), tr("Add to Version Control"),
+ tr("Add files\n%1\nto version control?").arg(files),
+ QMessageBox::Yes | QMessageBox::No);
+ if (button == QMessageBox::Yes) {
+ QStringList notAddedToVc;
+ foreach (const QString file, fileNames) {
+ if (!vcManager->vcsAdd(file))
+ notAddedToVc << file;
+ }
+
+ if (!notAddedToVc.isEmpty()) {
+ const QString message = tr("Could not add following files to version control\n");
+ const QString filesNotAdded = notAddedToVc.join("\n");
+ QMessageBox::warning(m_core->mainWindow(), tr("Add files to version control failed"),
+ message + filesNotAdded);
+ }
+ }
+ }
+}
+
+void ProjectExplorerPlugin::openFile()
+{
+ Q_ASSERT(m_currentNode);
+ m_core->editorManager()->openEditor(m_currentNode->path());
+ m_core->editorManager()->ensureEditorManagerVisible();
+}
+
+void ProjectExplorerPlugin::removeFile()
+{
+ Q_ASSERT(m_currentNode && m_currentNode->nodeType() == FileNodeType);
+ FileNode *fileNode = qobject_cast<FileNode*>(m_currentNode);
+
+ const QString filePath = m_currentNode->path();
+ const QString fileDir = QFileInfo(filePath).dir().absolutePath();
+ RemoveFileDialog removeFileDialog(filePath, m_core->mainWindow());
+
+ if (removeFileDialog.exec() == QDialog::Accepted) {
+ const bool deleteFile = removeFileDialog.isDeleteFileChecked();
+
+ // remove from project
+ ProjectNode *projectNode = fileNode->projectNode();
+ Q_ASSERT(projectNode);
+
+ if (!projectNode->removeFiles(fileNode->fileType(), QStringList(filePath))) {
+ QMessageBox::warning(m_core->mainWindow(), tr("Remove file failed"),
+ tr("Could not remove file %1 from project %2.").arg(filePath).arg(projectNode->name()));
+ return;
+ }
+
+ // remove from version control
+ m_core->vcsManager()->showDeleteDialog(filePath);
+
+ // remove from file system
+ if (deleteFile) {
+ QFile file(filePath);
+
+ if (file.exists()) {
+ // could have been deleted by vc
+ if (!file.remove())
+ QMessageBox::warning(m_core->mainWindow(), tr("Delete file failed"),
+ tr("Could not delete file %1.").arg(filePath));
+ }
+ }
+ }
+}
+
+void ProjectExplorerPlugin::renameFile()
+{
+ QWidget *focusWidget = QApplication::focusWidget();
+ while (focusWidget) {
+ ProjectTreeWidget *treeWidget = qobject_cast<ProjectTreeWidget*>(focusWidget);
+ if (treeWidget) {
+ treeWidget->editCurrentItem();
+ break;
+ }
+ focusWidget = focusWidget->parentWidget();
+ }
+}
+
+void ProjectExplorerPlugin::populateBuildConfigurationMenu()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::populateBuildConfigurationMenu";
+
+ // delete the old actiongroup and all actions that are children of it
+ delete m_buildConfigurationActionGroup;
+ m_buildConfigurationActionGroup = new QActionGroup(m_buildConfigurationMenu);
+ m_buildConfigurationMenu->clear();
+ if (Project *pro = m_currentProject) {
+ const QString &activeBuildConfiguration = pro->activeBuildConfiguration();
+ foreach (const QString &buildConfiguration, pro->buildConfigurations()) {
+ QString displayName = pro->displayNameFor(buildConfiguration);
+ QAction *act = new QAction(displayName, m_buildConfigurationActionGroup);
+ if (debug)
+ qDebug() << "BuildConfiguration " << buildConfiguration << "active: " << activeBuildConfiguration;
+ act->setCheckable(true);
+ act->setChecked(buildConfiguration == activeBuildConfiguration);
+ act->setData(buildConfiguration);
+ m_buildConfigurationMenu->addAction(act);
+ }
+ m_buildConfigurationMenu->setEnabled(true);
+ } else {
+ m_buildConfigurationMenu->setEnabled(false);
+ }
+}
+
+void ProjectExplorerPlugin::buildConfigurationMenuTriggered(QAction *action)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::buildConfigurationMenuTriggered";
+
+ m_currentProject->setActiveBuildConfiguration(action->data().toString());
+}
+
+void ProjectExplorerPlugin::populateRunConfigurationMenu()
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::populateRunConfigurationMenu";
+
+ delete m_runConfigurationActionGroup;
+ m_runConfigurationActionGroup = new QActionGroup(m_runConfigurationMenu);
+ m_runConfigurationMenu->clear();
+
+ const Project *startupProject = m_session->startupProject();
+ QSharedPointer<RunConfiguration> activeRunConfiguration
+ = (startupProject) ? startupProject->activeRunConfiguration() : QSharedPointer<RunConfiguration>(0);
+
+ foreach (const Project *pro, m_session->projects()) {
+ foreach (QSharedPointer<RunConfiguration> runConfiguration, pro->runConfigurations()) {
+ const QString title = QString("%1 (%2)").arg(pro->name(), runConfiguration->name());
+ QAction *act = new QAction(title, m_runConfigurationActionGroup);
+ act->setCheckable(true);
+ act->setData(qVariantFromValue(runConfiguration));
+ act->setChecked(runConfiguration == activeRunConfiguration);
+ m_runConfigurationMenu->addAction(act);
+ if (debug)
+ qDebug() << "RunConfiguration" << runConfiguration << "project:" << pro->name()
+ << "active:" << (runConfiguration == activeRunConfiguration);
+ }
+ }
+
+ m_runConfigurationMenu->setDisabled(m_runConfigurationMenu->actions().isEmpty());
+}
+
+void ProjectExplorerPlugin::runConfigurationMenuTriggered(QAction *action)
+{
+ if (debug)
+ qDebug() << "ProjectExplorerPlugin::runConfigurationMenuTriggered" << action;
+
+ QSharedPointer<RunConfiguration> runConfiguration = qVariantValue<QSharedPointer<RunConfiguration> >(action->data());
+ runConfiguration->project()->setActiveRunConfiguration(runConfiguration);
+ setStartupProject(runConfiguration->project());
+}
+
+void ProjectExplorerPlugin::populateOpenWithMenu()
+{
+ typedef QList<Core::IEditorFactory*> EditorFactoryList;
+
+ m_openWithMenu->clear();
+
+ bool anyMatches = false;
+ const QString fileName = currentNode()->path();
+
+ if (const Core::MimeType mt = m_core->mimeDatabase()->findByFile(QFileInfo(fileName))) {
+ const EditorFactoryList factories = m_core->editorManager()->editorFactories(mt, false);
+ anyMatches = !factories.empty();
+ if (anyMatches) {
+ const QList<Core::IEditor *> editorsOpenForFile = m_core->editorManager()->editorsForFileName(fileName);
+ // Add all suitable editors
+ foreach (Core::IEditorFactory *editorFactory, factories) {
+ // Add action to open with this very editor factory
+ QString const actionTitle(editorFactory->kind());
+ QAction * const action = m_openWithMenu->addAction(actionTitle);
+ action->setData(qVariantFromValue(editorFactory));
+ // File already open in an editor -> only enable that entry since
+ // we currently do not support opening a file in two editors at once
+ if (!editorsOpenForFile.isEmpty()) {
+ bool enabled = false;
+ foreach (Core::IEditor * const openEditor, editorsOpenForFile) {
+ if (editorFactory->kind() == QLatin1String(openEditor->kind()))
+ enabled = true;
+ break;
+ }
+ action->setEnabled(enabled);
+ }
+ }
+ }
+ }
+ m_openWithMenu->setEnabled(anyMatches);
+}
+
+void ProjectExplorerPlugin::openWithMenuTriggered(QAction *action)
+{
+ Q_ASSERT(action != NULL);
+ Core::IEditorFactory * const editorFactory = qVariantValue<Core::IEditorFactory *>(action->data());
+ Q_ASSERT(m_core != NULL);
+ Q_ASSERT(m_core->editorManager() != NULL);
+ Q_ASSERT(editorFactory != NULL);
+ m_core->editorManager()->openEditor(currentNode()->path(), editorFactory->kind());
+ m_core->editorManager()->ensureEditorManagerVisible();
+}
+
+void ProjectExplorerPlugin::updateSessionMenu()
+{
+ m_sessionMenu->clear();
+ const QString &activeSession = m_session->activeSession();
+ foreach(const QString &session, m_session->sessions()) {
+ QAction *act = m_sessionMenu->addAction(session, this, SLOT(setSession()));
+ act->setCheckable(true);
+ if (session == activeSession)
+ act->setChecked(true);
+ }
+ m_sessionMenu->addSeparator();
+ m_sessionMenu->addAction(m_sessionManagerAction);
+
+ m_sessionMenu->setEnabled(true);
+}
+
+void ProjectExplorerPlugin::setSession()
+{
+ QString session = static_cast<QAction *>(sender())->text();
+ if (session != m_session->activeSession())
+ m_session->loadSession(session);
+}
+
+Q_EXPORT_PLUGIN(ProjectExplorerPlugin)
diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h
new file mode 100644
index 0000000000..4f956fc8f4
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer.h
@@ -0,0 +1,280 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTEXPLORER_H
+#define PROJECTEXPLORER_H
+
+#include "project.h"
+#include "session.h"
+#include "projectexplorer_export.h"
+
+#include <extensionsystem/iplugin.h>
+#include <coreplugin/icorelistener.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QList>
+#include <QtCore/QQueue>
+#include <QtCore/QModelIndex>
+#include <QtGui/QMenu>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QTreeWidgetItem>
+
+
+namespace Core {
+class IContext;
+class ICore;
+class IMode;
+class IFileFactory;
+ namespace Internal {
+ class WelcomeMode;
+ }
+}
+
+namespace ProjectExplorer {
+
+class BuildManager;
+class PersistentSettings;
+class RunConfiguration;
+class RunControl;
+class SessionManager;
+class IRunConfigurationRunner;
+
+namespace Internal {
+class ApplicationOutput;
+class OutputPane;
+class ProjectWindow;
+class ProjectFileFactory;
+
+} // namespace Internal
+
+class PROJECTEXPLORER_EXPORT ProjectExplorerPlugin
+ : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ ProjectExplorerPlugin();
+ ~ProjectExplorerPlugin();
+
+ static ProjectExplorerPlugin *instance();
+
+ bool openProject(const QString &fileName);
+ bool openProjects(const QStringList &fileNames);
+
+ SessionManager *session() const;
+
+ Project *currentProject() const;
+ Node *currentNode() const;
+
+ void setCurrentFile(Project *project, const QString &file);
+ void setCurrentNode(Node *node);
+
+ Project *startupProject() const;
+ void setStartupProject(ProjectExplorer::Project *project = 0);
+
+ BuildManager *buildManager() const;
+
+ bool saveModifiedFiles(const QList<Project *> & projects);
+
+ void showContextMenu(const QPoint &globalPos, Node *node);
+
+ //PluginInterface
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ void shutdown();
+
+signals:
+ void aboutToShowContextMenu(ProjectExplorer::Project *project,
+ ProjectExplorer::Node *node);
+
+ // Is emitted when a project has been added/removed,
+ // or the file list of a specific project has changed.
+ void fileListChanged();
+
+ void currentProjectChanged(ProjectExplorer::Project *project);
+ void currentNodeChanged(ProjectExplorer::Node *node, ProjectExplorer::Project *project);
+ void aboutToExecuteProject(ProjectExplorer::Project *project);
+
+private slots:
+ void buildStateChanged(ProjectExplorer::Project * pro);
+ void buildQueueFinished(bool success);
+ void buildProject();
+ void buildSession();
+ void rebuildProject();
+ void rebuildSession();
+ void cleanProject();
+ void cleanSession();
+ void cancelBuild();
+ void debugProject();
+ void editDependencies();
+ bool saveAction(ProjectExplorer::Project *pro = 0);
+ void loadAction();
+ void unloadProject();
+ void clearSession();
+ void newProject();
+ void sessionManager();
+ void populateBuildConfigurationMenu();
+ void buildConfigurationMenuTriggered(QAction *);
+ void populateRunConfigurationMenu();
+ void runConfigurationMenuTriggered(QAction *);
+ void populateOpenWithMenu();
+ void openWithMenuTriggered(QAction *action);
+ void updateSessionMenu();
+ void setSession();
+
+ void restoreSession();
+ void loadSession(const QString &session);
+ void runProject();
+ void savePersistentSettings();
+ void goToTaskWindow();
+
+ void updateContextMenuActions();
+ void addNewFile();
+ void addExistingFiles();
+ void openFile();
+ void removeFile();
+ void renameFile();
+
+ void updateRecentProjectMenu();
+ void openRecentProject();
+
+ void invalidateProject(ProjectExplorer::Project *project);
+
+ void setCurrentFile(const QString &filePath);
+
+ // RunControl
+ void runControlFinished();
+
+ void startupProjectChanged(); // Calls updateRunAction
+ void updateRunAction();
+
+ void addToApplicationOutputWindow(RunControl *, const QString &line);
+ void addErrorToApplicationOutputWindow(RunControl *, const QString &error);
+ void updateTaskActions();
+
+ void loadProject(const QString &project) { openProject(project); }
+ void currentModeChanged(Core::IMode *mode);
+
+private:
+ void setCurrent(Project *project, QString filePath, Node *node);
+
+ QStringList allFilesWithDependencies(Project *pro);
+ IRunConfigurationRunner *findRunner(QSharedPointer<RunConfiguration> config, const QString &mode);
+
+ void updateActions();
+ void addToRecentProjects(const QString &fileName);
+ void updateWelcomePage(Core::Internal::WelcomeMode *welcomeMode);
+ Internal::ProjectFileFactory *findProjectFileFactory(const QString &filename) const;
+
+ static ProjectExplorerPlugin *m_instance;
+
+ QMenu *m_sessionContextMenu;
+ QMenu *m_sessionMenu;
+ QMenu *m_projectMenu;
+ QMenu *m_subProjectMenu;
+ QMenu *m_folderMenu;
+ QMenu *m_fileMenu;
+ QMenu *m_openWithMenu;
+
+ QMultiMap<int, QObject*> m_actionMap;
+ QAction *m_sessionManagerAction;
+ QAction *m_newAction;
+#if 0
+ QAction *m_loadAction;
+#endif
+ QAction *m_unloadAction;
+ QAction *m_clearSession;
+ QAction *m_buildAction;
+ QAction *m_buildSessionAction;
+ QAction *m_rebuildAction;
+ QAction *m_rebuildSessionAction;
+ QAction *m_cleanAction;
+ QAction *m_cleanSessionAction;
+ QAction *m_runAction;
+ QAction *m_cancelBuildAction;
+ QAction *m_debugAction;
+ QAction *m_dependenciesAction;
+ QAction *m_taskAction;
+ QAction *m_addNewFileAction;
+ QAction *m_addExistingFilesAction;
+ QAction *m_openFileAction;
+ QAction *m_removeFileAction;
+ QAction *m_renameFileAction;
+
+ QMenu *m_buildConfigurationMenu;
+ QActionGroup *m_buildConfigurationActionGroup;
+ QMenu *m_runConfigurationMenu;
+ QActionGroup *m_runConfigurationActionGroup;
+
+ Core::ICore *m_core;
+ Internal::ProjectWindow *m_proWindow;
+ SessionManager *m_session;
+
+ Project *m_currentProject;
+ Node *m_currentNode;
+
+ BuildManager *m_buildManager;
+
+ QList<Internal::ProjectFileFactory*> m_fileFactories;
+ QStringList m_profileMimeTypes;
+ Internal::OutputPane *m_outputPane;
+
+ QStringList m_recentProjects;
+ static const int m_maxRecentProjects = 7;
+ QMap<QAction*, QString> m_recentProjectsActions;
+
+ QString m_lastOpenDirectory;
+ QSharedPointer<RunConfiguration> m_delayedRunConfiguration;
+ RunControl *m_debuggingRunControl;
+ QString m_runMode;
+ QString m_projectFilterString;
+};
+
+namespace Internal {
+class CoreListenerCheckingForRunningBuild : public Core::ICoreListener
+{
+ Q_OBJECT
+public:
+ CoreListenerCheckingForRunningBuild(BuildManager *manager);
+
+ bool coreAboutToClose();
+
+private:
+ BuildManager *m_manager;
+};
+}
+
+} // namespace ProjectExplorer
+
+#endif // PROJECTEXPLORER_H
diff --git a/src/plugins/projectexplorer/projectexplorer.pri b/src/plugins/projectexplorer/projectexplorer.pri
new file mode 100644
index 0000000000..45d1e96374
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer.pri
@@ -0,0 +1,3 @@
+include(projectexplorer_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(ProjectExplorer)
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
new file mode 100644
index 0000000000..bbb8a4c74d
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -0,0 +1,115 @@
+TEMPLATE = lib
+TARGET = ProjectExplorer
+QT += xml \
+ script
+include(../../qworkbenchplugin.pri)
+include(projectexplorer_dependencies.pri)
+include(../../../shared/scriptwrapper/scriptwrapper.pri)
+HEADERS += projectexplorer.h \
+ projectexplorer_export.h \
+ projectwindow.h \
+ buildmanager.h \
+ compileoutputwindow.h \
+ taskwindow.h \
+ outputwindow.h \
+ persistentsettings.h \
+ projectfilewizardextension.h \
+ session.h \
+ dependenciesdialog.h \
+ allprojectsfilter.h \
+ buildparserinterface.h \
+ projectexplorerconstants.h \
+ project.h \
+ pluginfilefactory.h \
+ iprojectmanager.h \
+ currentprojectfilter.h \
+ scriptwrappers.h \
+ allprojectsfind.h \
+ buildstep.h \
+ buildconfiguration.h \
+ environment.h \
+ iprojectproperties.h \
+ buildsettingspropertiespage.h \
+ environmenteditmodel.h \
+ processstep.h \
+ abstractprocessstep.h \
+ editorconfiguration.h \
+ editorsettingspropertiespage.h \
+ runconfiguration.h \
+ applicationlauncher.h \
+ consoleprocess.h \
+ abstractprocess.h \
+ applicationrunconfiguration.h \
+ runsettingspropertiespage.h \
+ projecttreewidget.h \
+ foldernavigationwidget.h \
+ customexecutablerunconfiguration.h \
+ buildprogress.h \
+ projectnodes.h \
+ sessiondialog.h \
+ projectwizardpage.h \
+ buildstepspage.h \
+ removefiledialog.h \
+ nodesvisitor.h \
+ projectmodels.h \
+ currentprojectfind.h
+SOURCES += projectexplorer.cpp \
+ projectwindow.cpp \
+ buildmanager.cpp \
+ compileoutputwindow.cpp \
+ taskwindow.cpp \
+ outputwindow.cpp \
+ persistentsettings.cpp \
+ projectfilewizardextension.cpp \
+ session.cpp \
+ dependenciesdialog.cpp \
+ allprojectsfilter.cpp \
+ currentprojectfilter.cpp \
+ scriptwrappers.cpp \
+ allprojectsfind.cpp \
+ project.cpp \
+ pluginfilefactory.cpp \
+ buildstep.cpp \
+ buildconfiguration.cpp \
+ buildparserinterface.cpp \
+ environment.cpp \
+ buildsettingspropertiespage.cpp \
+ environmenteditmodel.cpp \
+ processstep.cpp \
+ abstractprocessstep.cpp \
+ editorconfiguration.cpp \
+ editorsettingspropertiespage.cpp \
+ runconfiguration.cpp \
+ applicationrunconfiguration.cpp \
+ runsettingspropertiespage.cpp \
+ projecttreewidget.cpp \
+ foldernavigationwidget.cpp \
+ customexecutablerunconfiguration.cpp \
+ buildprogress.cpp \
+ projectnodes.cpp \
+ sessiondialog.cpp \
+ projectwizardpage.cpp \
+ buildstepspage.cpp \
+ removefiledialog.cpp \
+ nodesvisitor.cpp \
+ projectmodels.cpp \
+ currentprojectfind.cpp
+FORMS += dependenciesdialog.ui \
+ buildsettingspropertiespage.ui \
+ processstep.ui \
+ editorsettingspropertiespage.ui \
+ runsettingspropertiespage.ui \
+ sessiondialog.ui \
+ projectwizardpage.ui \
+ buildstepspage.ui \
+ removefiledialog.ui
+win32 {
+ SOURCES += consoleprocess_win.cpp \
+ applicationlauncher_win.cpp \
+ winguiprocess.cpp
+ HEADERS += winguiprocess.h
+}
+else:unix:SOURCES += consoleprocess_unix.cpp \
+ applicationlauncher_x11.cpp
+RESOURCES += projectexplorer.qrc
+DEFINES += PROJECTEXPLORER_LIBRARY
diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc
new file mode 100644
index 0000000000..a9e1b3488e
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer.qrc
@@ -0,0 +1,23 @@
+<RCC>
+ <qresource prefix="/projectexplorer" >
+ <file>images/build.png</file>
+ <file>images/build_small.png</file>
+ <file>images/clean.png</file>
+ <file>images/clean_small.png</file>
+ <file>images/closetab.png</file>
+ <file>images/compile_error.png</file>
+ <file>images/compile_unspecified.png</file>
+ <file>images/compile_warning.png</file>
+ <file>images/debugger_start.png</file>
+ <file>images/debugger_start_small.png</file>
+ <file>images/filtericon.png</file>
+ <file>images/insert_line_small.png</file>
+ <file>images/projectexplorer.png</file>
+ <file>images/rebuild.png</file>
+ <file>images/rebuild_small.png</file>
+ <file>images/run.png</file>
+ <file>images/run_small.png</file>
+ <file>images/session.png</file>
+ <file>images/stop.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/projectexplorer/projectexplorer_dependencies.pri b/src/plugins/projectexplorer/projectexplorer_dependencies.pri
new file mode 100644
index 0000000000..674c8bbb36
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer_dependencies.pri
@@ -0,0 +1,5 @@
+include(../../libs/utils/utils.pri)
+include(../../plugins/quickopen/quickopen.pri)
+include(../../plugins/find/find.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
diff --git a/src/plugins/projectexplorer/projectexplorer_export.h b/src/plugins/projectexplorer/projectexplorer_export.h
new file mode 100644
index 0000000000..e554e40ab0
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorer_export.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef PROJECTEXPLORER_EXPORT_H
+#define PROJECTEXPLORER_EXPORT_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(PROJECTEXPLORER_LIBRARY)
+# define PROJECTEXPLORER_EXPORT Q_DECL_EXPORT
+#else
+# define PROJECTEXPLORER_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // PROJECTEXPLORER_EXPORT_H
diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h
new file mode 100644
index 0000000000..04fc727b3f
--- /dev/null
+++ b/src/plugins/projectexplorer/projectexplorerconstants.h
@@ -0,0 +1,180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTEXPLORERCONSTANTS_H
+#define PROJECTEXPLORERCONSTANTS_H
+
+namespace ProjectExplorer {
+namespace Constants {
+
+// modes and their priorities
+const char * const MODE_SESSION = "ProjectExplorer.Mode.Session";
+const int P_MODE_SESSION = 85;
+
+// actions
+const char * const NEWSESSION = "ProjectExplorer.NewSession";
+const char * const NEWPROJECT = "ProjectExplorer.NewProject";
+const char * const LOAD = "ProjectExplorer.Load";
+const char * const UNLOAD = "ProjectExplorer.Unload";
+const char * const CLEARSESSION = "ProjectExplorer.ClearSession";
+const char * const BUILD = "ProjectExplorer.Build";
+const char * const BUILDSESSION = "ProjectExplorer.BuildSession";
+const char * const REBUILD = "ProjectExplorer.Rebuild";
+const char * const REBUILDSESSION = "ProjectExplorer.RebuildSession";
+const char * const CLEAN = "ProjectExplorer.Clean";
+const char * const CLEANSESSION = "ProjectExplorer.CleanSession";
+const char * const BUILDCONFIGURATIONMENU = "ProjectExplorer.BuildConfigurationMenu";
+const char * const CANCELBUILD = "ProjectExplorer.CancelBuild";
+const char * const RUNCONFIGURATIONMENU = "ProjectExplorer.RunConfigurationMenu";
+const char * const DEBUG = "ProjectExplorer.Debug";
+const char * const DEPENDENCIES = "ProjectExplorer.Dependencies";
+const char * const FINDINALLPROJECTS = "ProjectExplorer.FindInAllProjects";
+const char * const GOTOTASKWINDOW = "ProjectExplorer.GoToTaskWindow";
+const char * const SHOWPROPERTIES = "ProjectExplorer.ShowProperties";
+const char * const ADDNEWFILE = "ProjectExplorer.AddNewFile";
+const char * const ADDEXISTINGFILES = "ProjectExplorer.AddExistingFiles";
+const char * const OPENFILE = "ProjectExplorer.OpenFile";
+const char * const REMOVEFILE = "ProjectExplorer.RemoveFile";
+const char * const RENAMEFILE = "ProjectExplorer.RenameFile";
+
+//Run modes
+const char * const RUNMODE = "ProjectExplorer.RunMode";
+const char * const DEBUGMODE = "ProjectExplorer.DebugMode";
+
+// action priorities
+const int P_ACTION_RUN = 100;
+const int P_ACTION_DEBUG = 90;
+const int P_ACTION_BUILDSESSION = 80;
+
+const char * const RUN = "ProjectExplorer.Run";
+
+// context
+const char * const C_PROJECTEXPLORER = "Project Explorer";
+
+// languages
+const char * const LANG_CXX = "CXX";
+
+// menus
+const char * const M_RECENTPROJECTS = "ProjectExplorer.Menu.Recent";
+const char * const M_BUILDPROJECT = "ProjectExplorer.Menu.Build";
+const char * const M_DEBUG = "ProjectExplorer.Menu.Debug";
+const char * const M_SESSION = "ProjectExplorer.Menu.Session";
+
+// toolbars
+const char * const T_BUILDPROJECT = "ProjectExplorer.ToolBar.Build";
+
+// menu groups
+const char * const G_BUILD_SESSION = "ProjectExplorer.Group.BuildSession";
+const char * const G_BUILD_PROJECT = "ProjectExplorer.Group.Build";
+const char * const G_BUILD_OTHER = "ProjectExplorer.Group.Other";
+const char * const G_BUILD_RUN = "ProjectExplorer.Group.Run";
+const char * const G_BUILD_TASK = "ProjectExplorer.Group.BuildTask";
+const char * const G_BUILD_CANCEL = "ProjectExplorer.Group.BuildCancel";
+
+// toolbar groups
+const char * const G_TOOLBAR_CUSTOM = "ProjectExplorer.ToolBarGroup.Custom";
+const char * const G_TOOLBAR_BUILD = "ProjectExplorer.ToolBarGroup.Build";
+const char * const G_TOOLBAR_RUN = "ProjectExplorer.ToolBarGroup.Run";
+const char * const G_TOOLBAR_OTHER = "ProjectExplorer.ToolBarGroup.Other";
+
+// context menus
+const char * const M_SESSIONCONTEXT = "Project.Menu.Session";
+const char * const M_PROJECTCONTEXT = "Project.Menu.Project";
+const char * const M_SUBPROJECTCONTEXT = "Project.Menu.SubProject";
+const char * const M_FOLDERCONTEXT = "Project.Menu.Folder";
+const char * const M_FILECONTEXT = "Project.Menu.File";
+const char * const M_OPENFILEWITHCONTEXT = "Project.Menu.File.OpenWith";
+
+// context menu groups
+const char * const G_SESSION_BUILD = "Session.Group.Build";
+const char * const G_SESSION_FILES = "Session.Group.Files";
+const char * const G_SESSION_OTHER = "Session.Group.Other";
+const char * const G_SESSION_CONFIG = "Session.Group.Config";
+
+const char * const G_PROJECT_OPEN = "Project.Group.Open";
+const char * const G_PROJECT_NEW = "Project.Group.New";
+const char * const G_PROJECT_FILES = "Project.Group.Files";
+const char * const G_PROJECT_BUILD = "Project.Group.Build";
+const char * const G_PROJECT_OTHER = "Project.Group.Other";
+const char * const G_PROJECT_RUN = "Project.Group.Run";
+const char * const G_PROJECT_CONFIG = "Project.Group.Config";
+
+const char * const G_FOLDER_FILES = "ProjectFolder.Group.Files";
+const char * const G_FOLDER_OTHER = "ProjectFolder.Group.Other";
+const char * const G_FOLDER_CONFIG = "ProjectFolder.Group.Config";
+
+const char * const G_FILE_OPEN = "ProjectFile.Group.Open";
+const char * const G_FILE_OTHER = "ProjectFile.Group.Other";
+const char * const G_FILE_CONFIG = "ProjectFile.Group.Config";
+
+// file kind
+const char * const FILE_FACTORY_KIND = "ProjectExplorer.FileFactoryKind";
+
+// wizard kind
+const char * const WIZARD_TYPE_PROJECT = "ProjectExplorer.WizardType.Project";
+
+// icons
+const char * const ICON_BUILD = ":/projectexplorer/images/build.png";
+const char * const ICON_BUILD_SMALL = ":/projectexplorer/images/build_small.png";
+const char * const ICON_CLEAN = ":/projectexplorer/images/clean.png";
+const char * const ICON_CLEAN_SMALL = ":/projectexplorer/images/clean_small.png";
+const char * const ICON_REBUILD = ":/projectexplorer/images/rebuild.png";
+const char * const ICON_REBUILD_SMALL = ":/projectexplorer/images/rebuild_small.png";
+const char * const ICON_RUN = ":/projectexplorer/images/run.png";
+const char * const ICON_RUN_SMALL = ":/projectexplorer/images/run_small.png";
+const char * const ICON_SESSION = ":/projectexplorer/images/session.png";
+const char * const ICON_INSERT_LINE = ":/projectexplorer/images/insert_line_small.png";
+const char * const ICON_DEBUG = ":/projectexplorer/images/debugger_start.png";
+const char * const ICON_DEBUG_SMALL = ":/projectexplorer/images/debugger_start_small.png";
+const char * const ICON_CLOSETAB = ":/projectexplorer/images/closetab.png";
+const char * const ICON_STOP = ":/projectexplorer/images/stop.png";
+
+// find filters
+const char * const FIND_CUR_PROJECT = "ProjectExplorer.FindFilter.CurrentProject";
+const char * const FIND_ALL_PROJECTS = "ProjectExplorer.FindFilter.AllProjects";
+
+const char * const TASK_BUILD = "ProjectExplorer.Task.Build";
+const char * const SESSIONFILE_MIMETYPE = "application/vnd.nokia.xml.qt.creator.session";
+
+
+const char * const PROFILE_MIMETYPE = "application/vnd.nokia.qt.qmakeprofile";
+const char * const C_SOURCE_MIMETYPE = "text/x-csrc";
+const char * const C_HEADER_MIMETYPE = "text/x-chdr";
+const char * const CPP_SOURCE_MIMETYPE = "text/x-c++src";
+const char * const CPP_HEADER_MIMETYPE = "text/x-c++hdr";
+const char * const FORM_MIMETYPE = "application/x-designer";
+const char * const RESOURCE_MIMETYPE = "application/vnd.nokia.xml.qt.resource";
+
+}
+}
+
+#endif //PROJECTEXPLORERCONSTANTS_H
diff --git a/src/plugins/projectexplorer/projectfilewizardextension.cpp b/src/plugins/projectexplorer/projectfilewizardextension.cpp
new file mode 100644
index 0000000000..c00a969e7e
--- /dev/null
+++ b/src/plugins/projectexplorer/projectfilewizardextension.cpp
@@ -0,0 +1,199 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "projectfilewizardextension.h"
+#include "projectexplorer.h"
+#include "projectnodes.h"
+#include "nodesvisitor.h"
+#include "projectwizardpage.h"
+
+#include <coreplugin/basefilewizard.h>
+#include <coreplugin/dialogs/iwizard.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+
+#include <QtCore/QVariant>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QMultiMap>
+
+enum { debugExtension = 0 };
+
+namespace ProjectExplorer {
+
+typedef QList<ProjectNode *> ProjectNodeList;
+
+namespace Internal {
+
+// --------- AllProjectNodesVisitor. Figure out all projects.
+// No sooner said then done.
+class AllProjectNodesVisitor : public NodesVisitor
+{
+ AllProjectNodesVisitor(ProjectNodeList &l) : m_projectNodes(l) {}
+public:
+
+ static ProjectNodeList allProjects(const ProjectExplorerPlugin *pe);
+
+ virtual void visitProjectNode(ProjectNode *node);
+
+private:
+ ProjectNodeList &m_projectNodes;
+};
+
+ProjectNodeList AllProjectNodesVisitor::allProjects(const ProjectExplorerPlugin *pe)
+{
+ ProjectNodeList rc;
+ AllProjectNodesVisitor visitor(rc);
+ pe->session()->sessionNode()->accept(&visitor);
+ return rc;
+}
+
+void AllProjectNodesVisitor::visitProjectNode(ProjectNode *node)
+{
+ if (node->supportedActions().contains(ProjectNode::AddFile))
+ m_projectNodes << node;
+}
+
+// --------- ProjectWizardContext
+struct ProjectWizardContext {
+ Core::IVersionControl *versionControl;
+ ProjectNodeList projects;
+ ProjectWizardPage *page;
+};
+
+// ---- ProjectFileWizardExtension
+ProjectFileWizardExtension::ProjectFileWizardExtension(Core::ICore *core) :
+ m_core(core),
+ m_context(0)
+{
+}
+
+ProjectFileWizardExtension::~ProjectFileWizardExtension()
+{
+ delete m_context;
+}
+
+void ProjectFileWizardExtension::firstExtensionPageShown(const QList<Core::GeneratedFile> &files)
+{
+ if (debugExtension)
+ qDebug() << Q_FUNC_INFO << files.size();
+ // Setup files display and version control depending on path
+ QStringList fileNames;
+ foreach (const Core::GeneratedFile &f, files)
+ fileNames.push_back(f.path());
+
+ const QString directory = QFileInfo(fileNames.front()).absolutePath();
+ m_context->versionControl = m_core->vcsManager()->findVersionControlForDirectory(directory);
+
+ m_context->page->setFilesDisplay(fileNames);
+ m_context->page->setAddToVersionControlEnabled(m_context->versionControl != 0);
+}
+
+static ProjectNode *currentProject()
+{
+ if (Node *currentNode = ProjectExplorerPlugin::instance()->currentNode())
+ if (ProjectNode *currentProjectNode = qobject_cast<ProjectNode *>(currentNode))
+ return currentProjectNode;
+ return 0;
+}
+
+QList<QWizardPage *> ProjectFileWizardExtension::extensionPages(const Core::IWizard *wizard)
+{
+ if (!m_context)
+ m_context = new ProjectWizardContext;
+ // Init context with page and projects
+ m_context->page = new ProjectWizardPage;
+ m_context->versionControl = 0;
+ m_context->projects = AllProjectNodesVisitor::allProjects(ProjectExplorerPlugin::instance());
+ // Set up project list which remains the same over duration of wizard execution
+ // Disable "add project to project"
+ const bool hasProjects = !m_context->projects.empty();
+ if (hasProjects) {
+ // Compile list of names and find current project if there is one
+ QStringList projectNames;
+ ProjectNode *current = currentProject();
+ int currentIndex = -1;
+ const int count = m_context->projects.size();
+ for (int i = 0; i < count; i++) {
+ ProjectNode *pn = m_context->projects.at(i);
+ projectNames.push_back(pn->name());
+ if (current == pn)
+ currentIndex = i;
+ }
+ m_context->page->setProjects(projectNames);
+ if (currentIndex != -1)
+ m_context->page->setCurrentProjectIndex(currentIndex);
+ }
+ m_context->page->setAddToProjectEnabled(hasProjects && wizard->kind() != Core::IWizard::ProjectWizard);
+
+ return QList<QWizardPage *>() << m_context->page;
+}
+
+bool ProjectFileWizardExtension::process(const QList<Core::GeneratedFile> &files, QString *errorMessage)
+{
+ typedef QMultiMap<FileType, QString> TypeFileMap;
+ // Add files to project && version control
+ if (m_context->page->addToProject()) {
+ ProjectNode *project = m_context->projects.at(m_context->page->currentProjectIndex());
+ // Split into lists by file type and add
+ TypeFileMap typeFileMap;
+ foreach (const Core::GeneratedFile &generatedFile, files) {
+ const QString path = generatedFile.path();
+ typeFileMap.insert(typeForFileName(m_core->mimeDatabase(), path), path);
+ }
+ foreach (FileType type, typeFileMap.uniqueKeys()) {
+ const QStringList files = typeFileMap.values(type);
+ if (!project->addFiles(type, files)) {
+ *errorMessage = tr("Failed to add one or more files to project\n'%1' (%2).").
+ arg(project->path(), files.join(QLatin1String(",")));
+ return false;
+ }
+ }
+ }
+ // Add files to version control
+ if (m_context->page->addToVersionControl()) {
+ foreach (const Core::GeneratedFile &generatedFile, files) {
+ if (!m_context->versionControl->vcsAdd(generatedFile.path())) {
+ *errorMessage = tr("Failed to add '%1' to the version control system.").arg(generatedFile.path());
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+}
+}
diff --git a/src/plugins/projectexplorer/projectfilewizardextension.h b/src/plugins/projectexplorer/projectfilewizardextension.h
new file mode 100644
index 0000000000..aa58d5a232
--- /dev/null
+++ b/src/plugins/projectexplorer/projectfilewizardextension.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTFILEWIZARDEXTENSION2_H
+#define PROJECTFILEWIZARDEXTENSION2_H
+
+#include <coreplugin/ifilewizardextension.h>
+
+namespace Core {
+ class ICore;
+}
+
+namespace ProjectExplorer {
+
+namespace Internal {
+
+struct ProjectWizardContext;
+
+/*
+ Adds final page allowing the user to add files to project && version control
+ to BaseFileWizard.
+ */
+class ProjectFileWizardExtension : public Core::IFileWizardExtension
+{
+ Q_OBJECT
+public:
+ explicit ProjectFileWizardExtension(Core::ICore *core);
+ virtual ~ProjectFileWizardExtension();
+
+ virtual QList<QWizardPage *> extensionPages(const Core::IWizard *wizard);
+ virtual bool process(const QList<Core::GeneratedFile> &files, QString *errorMessage);
+
+public slots:
+ virtual void firstExtensionPageShown(const QList<Core::GeneratedFile> &);
+
+private:
+ Core::ICore *m_core;
+ ProjectWizardContext *m_context;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // PROJECTFILEWIZARDEXTENSION2_H
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
new file mode 100644
index 0000000000..f15ad46642
--- /dev/null
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -0,0 +1,1180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "project.h"
+#include "projectmodels.h"
+#include "projectexplorerconstants.h"
+
+#include <coreplugin/fileiconprovider.h>
+
+#include <QtGui/QApplication>
+#include <QtGui/QIcon>
+#include <QtGui/QStyle>
+#include <QtGui/QMessageBox>
+#include <QtGui/QSortFilterProxyModel>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+using Core::FileIconProvider;
+
+namespace {
+ // sorting helper function
+ bool sortNodes(Node *n1, Node *n2) {
+ // Ordering is: project files, project, folder, file
+
+ const NodeType n1Type = n1->nodeType();
+ const NodeType n2Type = n2->nodeType();
+
+ // project files
+ FileNode *file1 = qobject_cast<FileNode*>(n1);
+ FileNode *file2 = qobject_cast<FileNode*>(n2);
+ if (file1 && file1->fileType() == ProjectFileType) {
+ if (file2 && file2->fileType() == ProjectFileType) {
+ const QString fileName1 = QFileInfo(file1->path()).fileName();
+ const QString fileName2 = QFileInfo(file2->path()).fileName();
+
+ if (fileName1 != fileName2)
+ return fileName1 < fileName2;
+ else
+ return file1 < file2;
+ } else {
+ return true; // project file is before everything else
+ }
+ } else {
+ if (file2 && file2->fileType() == ProjectFileType) {
+ return false;
+ }
+ }
+
+ // projects
+ if (n1Type == ProjectNodeType) {
+ if (n2Type == ProjectNodeType) {
+ ProjectNode *project1 = static_cast<ProjectNode*>(n1);
+ ProjectNode *project2 = static_cast<ProjectNode*>(n2);
+
+ if (project1->name() != project2->name())
+ return project1->name() < project2->name(); // sort by name
+ else
+ return project1 < project2; // sort by pointer value
+ } else {
+ return true; // project is before folder & file
+ }
+ }
+ if (n2Type == ProjectNodeType)
+ return false;
+
+ if (n1Type == FolderNodeType) {
+ if (n2Type == FolderNodeType) {
+ FolderNode *folder1 = static_cast<FolderNode*>(n1);
+ FolderNode *folder2 = static_cast<FolderNode*>(n2);
+
+ if (folder1->name() != folder2->name())
+ return folder1->name() < folder2->name();
+ else
+ return folder1 < folder2;
+ } else {
+ return true; // folder is before file
+ }
+ }
+ if (n2Type == FolderNodeType)
+ return false;
+
+ // must be file nodes
+ {
+ const QString filePath1 = n1->path();
+ const QString filePath2 = n2->path();
+
+ const QString fileName1 = QFileInfo(filePath1).fileName();
+ const QString fileName2 = QFileInfo(filePath2).fileName();
+
+ if (fileName1 != fileName2) {
+ return fileName1 < fileName2; // sort by file names
+ } else {
+ if (filePath1 != filePath2) {
+ return filePath1 < filePath2; // sort by path names
+ } else {
+ return n1 < n2; // sort by pointer value
+ }
+ }
+ }
+ return false;
+ }
+}
+
+/*!
+ \class DetailedModel
+
+ A 1:1 mapping of the internal node tree.
+
+ The detailed model shows the complete project file hierarchy and all containing files.
+ */
+
+DetailedModel::DetailedModel(SessionNode *rootNode, QObject *parent)
+ : QAbstractItemModel(parent),
+ m_rootNode(rootNode),
+ //m_startupProject(0),
+ m_folderToAddTo(0)
+{
+ NodesWatcher *watcher = new NodesWatcher(this);
+ m_rootNode->registerWatcher(watcher);
+ connect(watcher, SIGNAL(foldersAboutToBeAdded(FolderNode*, const QList<FolderNode*> &)),
+ this, SLOT(foldersAboutToBeAdded(FolderNode*, const QList<FolderNode*> &)));
+ connect(watcher, SIGNAL(foldersAdded()),
+ this, SLOT(foldersAdded()));
+ connect(watcher, SIGNAL(foldersAboutToBeRemoved(FolderNode*, const QList<FolderNode*> &)),
+ this, SLOT(foldersAboutToBeRemoved(FolderNode*, const QList<FolderNode*> &)));
+ connect(watcher, SIGNAL(filesAboutToBeAdded(FolderNode*, const QList<FileNode*> &)),
+ this, SLOT(filesAboutToBeAdded(FolderNode*, const QList<FileNode*> &)));
+ connect(watcher, SIGNAL(filesAdded()),
+ this, SLOT(filesAdded()));
+ connect(watcher, SIGNAL(filesAboutToBeRemoved(FolderNode*, const QList<FileNode*> &)),
+ this, SLOT(filesAboutToBeRemoved(FolderNode*, const QList<FileNode*> &)));
+}
+
+QModelIndex DetailedModel::index(int row, int column, const QModelIndex &parent) const
+{
+ QModelIndex result;
+ if (!parent.isValid() && row == 0 && column == 0) {
+ result = createIndex(0, 0, m_rootNode);
+ } else if (column == 0) {
+ FolderNode *parentNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ Q_ASSERT(parentNode);
+ result = createIndex(row, 0, m_childNodes.value(parentNode).at(row));
+ }
+ return result;
+}
+
+QModelIndex DetailedModel::parent(const QModelIndex &index) const
+{
+ QModelIndex parentIndex;
+
+ if (Node *node = nodeForIndex(index)) {
+ if (FolderNode *parentFolderNode = node->parentFolderNode()) {
+ if (FolderNode *grandParentFolderNode = parentFolderNode->parentFolderNode()) {
+ Q_ASSERT(m_childNodes.contains(grandParentFolderNode));
+ int row = m_childNodes.value(grandParentFolderNode).indexOf(parentFolderNode);
+ parentIndex = createIndex(row, 0, parentFolderNode);
+ } else {
+ parentIndex = createIndex(0, 0, parentFolderNode);
+ }
+ }
+ }
+
+ return parentIndex;
+}
+
+Qt::ItemFlags DetailedModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags result;
+ if (index.isValid()) {
+ result = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ if (Node *node = nodeForIndex(index)) {
+ if (node->nodeType() == FileNodeType)
+ result |= Qt::ItemIsEditable;
+ }
+ }
+ return result;
+}
+
+QVariant DetailedModel::data(const QModelIndex &index, int role) const
+{
+ QVariant result;
+
+ if (Node *node = nodeForIndex(index)) {
+ FolderNode *folderNode = qobject_cast<FolderNode*>(node);
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ if (folderNode)
+ result = folderNode->name();
+ else
+ result = QFileInfo(node->path()).fileName(); //TODO cache that?
+ break;
+ }
+ case Qt::ToolTipRole: {
+ if (folderNode && (folderNode->nodeType() != ProjectNodeType))
+ result = tr("%1 of project %2").arg(folderNode->name()).arg(folderNode->projectNode()->name());
+ else
+ result = node->path();
+ break;
+ }
+ case Qt::DecorationRole: {
+ if (folderNode)
+ result = folderNode->icon();
+ else
+ result = FileIconProvider::instance()->icon(QFileInfo(node->path()));
+ break;
+ }
+ case Qt::FontRole: {
+ QFont font;
+ if (qobject_cast<ProjectNode*>(folderNode)) {
+ if (index == this->index(0,0) && m_isStartupProject)
+ font.setBold(true);
+ }
+ result = font;
+ break;
+ }
+ case ProjectExplorer::Project::FilePathRole: {
+ result = node->path();
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool DetailedModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ bool result = false;
+
+ if (Node *node = nodeForIndex(index)) {
+ FileNode *fileNode = qobject_cast<FileNode*>(node);
+ if (fileNode && role == Qt::EditRole && !value.toString().isEmpty()) {
+ ProjectNode *projectNode = node->projectNode();
+ QString newPath = QFileInfo(fileNode->path()).dir().absoluteFilePath(value.toString());
+ if (!projectNode->renameFile(fileNode->fileType(), fileNode->path(), newPath))
+ QMessageBox::warning(0, tr("Could not rename file"),
+ tr("Renaming file %1 to %2 failed.").arg(fileNode->path())
+ .arg(value.toString()));
+ }
+ }
+
+ return result;
+}
+
+int DetailedModel::rowCount(const QModelIndex & parent) const
+{
+ int count = 0;
+
+ if (!parent.isValid()) { // root item
+ count = 1;
+ } else {
+ // we can be sure that internal cache
+ // has been updated by fetchMore()
+ FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ if (folderNode && m_childNodes.contains(folderNode))
+ count = m_childNodes.value(folderNode).size();
+ }
+ return count;
+}
+
+int DetailedModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 1;
+}
+
+bool DetailedModel::hasChildren(const QModelIndex &parent) const
+{
+ bool hasChilds = false;
+
+ if (!parent.isValid()) {// root index
+ hasChilds = true;
+ } else {
+ if (FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent))) {
+ if (m_childNodes.contains(folderNode)) // internal cache
+ hasChilds = !m_childNodes.value(folderNode).isEmpty();
+ else {
+ if (!folderNode->subFolderNodes().isEmpty()
+ || !folderNode->fileNodes().isEmpty()) // underlying data
+ hasChilds = true;
+ else {
+ // Make sure add/remove signals are emitted
+ // even for empty nodes (i.e. where canFetchMore
+ // returns false)
+ m_childNodes.insert(folderNode, QList<Node*>());
+ }
+ }
+ }
+ }
+
+ return hasChilds;
+}
+
+/*!
+ Returns true if internal cache has not been built up yet
+ */
+bool DetailedModel::canFetchMore(const QModelIndex & parent) const
+{
+ bool canFetch = false;
+ if (parent.isValid()) {
+ if (FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent))) {
+ canFetch = !m_childNodes.contains(folderNode);
+ }
+ }
+ return canFetch;
+}
+
+/*!
+ Updates internal cache
+ */
+void DetailedModel::fetchMore(const QModelIndex & parent)
+{
+ FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ Q_ASSERT(folderNode);
+ Q_ASSERT(!m_childNodes.contains(folderNode));
+
+ m_childNodes.insert(folderNode, childNodeList(folderNode));
+}
+
+void DetailedModel::reset()
+{
+ // todo:How to implement this correctly?????
+ m_childNodes.clear();
+ QAbstractItemModel::reset();
+}
+
+void DetailedModel::foldersAboutToBeAdded(FolderNode *parentFolder,
+ const QList<FolderNode*> &newFolders)
+{
+ Q_UNUSED(newFolders);
+ Q_ASSERT(parentFolder);
+
+ if (m_childNodes.contains(parentFolder))
+ m_folderToAddTo = parentFolder;
+}
+
+void DetailedModel::foldersAdded()
+{
+ if (m_folderToAddTo) {
+ QList<Node*> newChildNodes = childNodeList(m_folderToAddTo);
+ addToChildNodes(m_folderToAddTo, newChildNodes);
+ m_folderToAddTo = 0;
+ }
+}
+
+void DetailedModel::foldersAboutToBeRemoved(FolderNode *parentFolder,
+ const QList<FolderNode*> &staleFolders)
+{
+ Q_ASSERT(parentFolder);
+
+ if (m_childNodes.contains(parentFolder)) {
+ QList<Node*> newChildNodes = m_childNodes.value(parentFolder);
+ QList<FolderNode*> nodesToRemove = staleFolders;
+ qSort(nodesToRemove.begin(), nodesToRemove.end(), sortNodes);
+
+ QList<Node*>::iterator newListIter = newChildNodes.begin();
+ QList<FolderNode*>::const_iterator toRemoveIter = nodesToRemove.constBegin();
+ for (; toRemoveIter != nodesToRemove.constEnd(); ++toRemoveIter) {
+ while (*newListIter != *toRemoveIter)
+ ++newListIter;
+ newListIter = newChildNodes.erase(newListIter);
+ }
+
+ removeFromChildNodes(parentFolder, newChildNodes);
+
+ // Clear cache for all folders beneath the current folder
+ foreach (FolderNode *folder, staleFolders) {
+ foreach (FolderNode *subFolder, recursiveSubFolders(folder)) {
+ m_childNodes.remove(subFolder);
+ }
+ }
+ }
+}
+
+void DetailedModel::filesAboutToBeAdded(FolderNode *parentFolder,
+ const QList<FileNode*> &newFiles)
+{
+ Q_UNUSED(newFiles);
+ Q_ASSERT(parentFolder);
+
+ if (m_childNodes.contains(parentFolder))
+ m_folderToAddTo = parentFolder;
+}
+
+void DetailedModel::filesAdded()
+{
+ if (m_folderToAddTo) {
+ QList<Node*> newChildNodes = childNodeList(m_folderToAddTo);
+ addToChildNodes(m_folderToAddTo, newChildNodes);
+ m_folderToAddTo = 0;
+ }
+}
+
+void DetailedModel::filesAboutToBeRemoved(FolderNode *parentFolder,
+ const QList<FileNode*> &staleFiles)
+{
+ Q_ASSERT(parentFolder);
+
+ if (m_childNodes.contains(parentFolder)) {
+ QList<Node*> newChildNodes = m_childNodes.value(parentFolder);
+ QList<FileNode*> nodesToRemove = staleFiles;
+ qSort(nodesToRemove.begin(), nodesToRemove.end(), sortNodes);
+
+ QList<Node*>::iterator newListIter = newChildNodes.begin();
+ QList<FileNode*>::const_iterator toRemoveIter = nodesToRemove.constBegin();
+ for (; toRemoveIter != nodesToRemove.constEnd(); ++toRemoveIter) {
+ while (*newListIter != *toRemoveIter)
+ ++newListIter;
+ newListIter = newChildNodes.erase(newListIter);
+ }
+
+ removeFromChildNodes(parentFolder, newChildNodes);
+ }
+}
+
+Node *DetailedModel::nodeForIndex(const QModelIndex &index) const
+{
+ return (Node*)index.internalPointer();
+}
+
+/*!
+ Returns the index corresponding to a node.
+ */
+QModelIndex DetailedModel::indexForNode(const Node *node)
+{
+ if (!node)
+ return QModelIndex();
+
+ if (FolderNode *parentFolder = node->parentFolderNode()) {
+ // iterate recursively
+ QModelIndex parentIndex = indexForNode(parentFolder);
+
+ // update internal cache
+ if (canFetchMore(parentIndex))
+ fetchMore(parentIndex);
+ Q_ASSERT(m_childNodes.contains(parentFolder));
+
+ int row = m_childNodes.value(parentFolder).indexOf(const_cast<Node*>(node));
+ if (row >= 0)
+ return index(row, 0, parentIndex);
+ else
+ return QModelIndex();
+ } else {
+ // root node
+ return index(0, 0);
+ }
+}
+
+QList<Node*> DetailedModel::childNodeList(FolderNode *folderNode) const
+{
+ QList<FolderNode*> folderNodes = folderNode->subFolderNodes();
+ QList<FileNode*> fileNodes = folderNode->fileNodes();
+
+ QList<Node*> nodes;
+ foreach (FolderNode *folderNode, folderNodes)
+ nodes << folderNode;
+ foreach (FileNode *fileNode, fileNodes)
+ nodes << fileNode;
+
+ qSort(nodes.begin(), nodes.end(), sortNodes);
+
+ return nodes;
+}
+
+void DetailedModel::addToChildNodes(FolderNode *parentFolder, QList<Node*> newChildNodes)
+{
+ QList<Node*> childNodes = m_childNodes.value(parentFolder);
+ QModelIndex parentIndex = indexForNode(parentFolder);
+ Q_ASSERT(parentIndex.isValid());
+
+ // position -> nodes, with positions in decreasing order
+ QList<QPair<int, QList<Node*> > > insertions;
+
+ // add nodes that should be added at the end or in between
+ int newIndex = newChildNodes.size() - 1;
+ for (int oldIndex = childNodes.size() - 1;
+ oldIndex >= 0; --oldIndex, --newIndex) {
+ QList<Node*> nodesPerIndex;
+ Node* oldNode = childNodes.at(oldIndex);
+ while (newChildNodes.at(newIndex) != oldNode) {
+ nodesPerIndex.append(newChildNodes.at(newIndex));
+ --newIndex;
+ }
+ if (!nodesPerIndex.isEmpty())
+ insertions.append(QPair<int, QList<Node*> >(oldIndex + 1, nodesPerIndex));
+ }
+ { // add nodes that should be added to the beginning
+ QList<Node*> insertAtStart;
+ while (newIndex >= 0) {
+ insertAtStart.append(newChildNodes.at(newIndex--));
+ }
+ if (!insertAtStart.isEmpty())
+ insertions.append(QPair<int, QList<Node*> >(0, insertAtStart));
+ }
+
+ for (QList<QPair<int, QList<Node*> > >::const_iterator iter = insertions.constBegin();
+ iter != insertions.constEnd(); ++iter) {
+
+ const int key = iter->first;
+ const QList<Node*> nodesToInsert = iter->second;
+
+ beginInsertRows(parentIndex, key, key + nodesToInsert.size() - 1);
+
+ // update internal cache
+ for (QList<Node*>::const_iterator nodeIterator = nodesToInsert.constBegin();
+ nodeIterator != nodesToInsert.constEnd(); ++nodeIterator)
+ childNodes.insert(key, *nodeIterator);
+ m_childNodes.insert(parentFolder, childNodes);
+
+ endInsertRows();
+ }
+
+ Q_ASSERT(childNodes == newChildNodes);
+}
+
+void DetailedModel::removeFromChildNodes(FolderNode *parentFolder, QList<Node*> newChildNodes)
+{
+ QList<Node*> childNodes = m_childNodes.value(parentFolder);
+ QModelIndex parentIndex = indexForNode(parentFolder);
+ Q_ASSERT(parentIndex.isValid());
+
+ // position -> nodes, with positions in decreasing order
+ QList<QPair<int, QList<Node*> > > deletions;
+
+ // add nodes that should be removed at the end or in between
+ int oldIndex = childNodes.size() - 1;
+ for (int newIndex = newChildNodes.size() - 1;
+ newIndex >= 0; --oldIndex, --newIndex) {
+ QList<Node*> nodesPerIndex;
+ Node* newNode = newChildNodes.at(newIndex);
+ while (childNodes.at(oldIndex) != newNode) {
+ nodesPerIndex.append(childNodes.at(oldIndex));
+ --oldIndex;
+ }
+ if (!nodesPerIndex.isEmpty())
+ deletions.append(QPair<int, QList<Node*> >(oldIndex + 1, nodesPerIndex));
+ }
+ { // add nodes that should be removed to the beginning
+ QList<Node*> deleteAtStart;
+ while (oldIndex >= 0) {
+ deleteAtStart.append(childNodes.at(oldIndex--));
+ }
+ if (!deleteAtStart.isEmpty())
+ deletions.append(QPair<int, QList<Node*> >(0, deleteAtStart));
+ }
+
+ for (QList<QPair<int, QList<Node*> > >::const_iterator iter = deletions.constBegin();
+ iter != deletions.constEnd(); ++iter) {
+
+ const int key = iter->first;
+ const QList<Node*> nodes = iter->second;
+
+ beginRemoveRows(parentIndex, key, key + nodes.size() - 1);
+
+ // update internal cache
+ for (int i = nodes.size(); i > 0; --i)
+ childNodes.removeAt(key);
+ m_childNodes.insert(parentFolder, childNodes);
+
+ endRemoveRows();
+ }
+
+ Q_ASSERT(childNodes == newChildNodes);
+}
+
+QList<FolderNode*> DetailedModel::recursiveSubFolders(FolderNode *parentFolder)
+{
+ QList<FolderNode*> subFolders;
+ foreach (FolderNode *subFolder, parentFolder->subFolderNodes()) {
+ subFolders.append(subFolder);
+ subFolders != recursiveSubFolders(subFolder);
+ }
+ return subFolders;
+}
+
+
+/*!
+ \class FlatModel
+
+ The flat model shows only application/library projects.
+
+
+ Shows all application/library projects directly unter the root project
+ This results in a "flattened" view (max 3 hierachies).
+ */
+
+FlatModel::FlatModel(SessionNode *rootNode, QObject *parent)
+ : QAbstractItemModel(parent),
+ m_filterProjects(true),
+ m_filterGeneratedFiles(true),
+ m_rootNode(rootNode),
+ m_startupProject(0),
+ m_parentFolderForChange(0)
+{
+ NodesWatcher *watcher = new NodesWatcher(this);
+ m_rootNode->registerWatcher(watcher);
+
+ connect(watcher, SIGNAL(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)),
+ this, SLOT(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)));
+ connect(watcher, SIGNAL(foldersAdded()),
+ this, SLOT(foldersAdded()));
+
+ connect(watcher, SIGNAL(foldersAboutToBeRemoved(FolderNode *, const QList<FolderNode*> &)),
+ this, SLOT(foldersAboutToBeRemoved(FolderNode *, const QList<FolderNode*> &)));
+ connect(watcher, SIGNAL(foldersRemoved()),
+ this, SLOT(foldersRemoved()));
+
+ connect(watcher, SIGNAL(filesAboutToBeAdded(FolderNode *,const QList<FileNode*> &)),
+ this, SLOT(filesAboutToBeAdded(FolderNode *, const QList<FileNode *> &)));
+ connect(watcher, SIGNAL(filesAdded()),
+ this, SLOT(filesAdded()));
+
+ connect(watcher, SIGNAL(filesAboutToBeRemoved(FolderNode *, const QList<FileNode*> &)),
+ this, SLOT(filesAboutToBeRemoved(FolderNode *, const QList<FileNode*> &)));
+ connect(watcher, SIGNAL(filesRemoved()),
+ this, SLOT(filesRemoved()));
+}
+
+QModelIndex FlatModel::index(int row, int column, const QModelIndex &parent) const
+{
+ QModelIndex result;
+ if (!parent.isValid() && row == 0 && column == 0) { // session
+ result = createIndex(0, 0, m_rootNode);
+ } else if (parent.isValid() && column == 0) {
+ FolderNode *parentNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ Q_ASSERT(parentNode);
+ QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
+ if (it == m_childNodes.constEnd()) {
+ fetchMore(parentNode);
+ it = m_childNodes.constFind(parentNode);
+ }
+
+ if (row < it.value().size())
+ result = createIndex(row, 0, it.value().at(row));
+ }
+// qDebug() << "index of " << row << column << parent.data(Project::FilePathRole) << " is " << result.data(Project::FilePathRole);
+ return result;
+}
+
+QModelIndex FlatModel::parent(const QModelIndex &idx) const
+{
+ QModelIndex parentIndex;
+ if (Node *node = nodeForIndex(idx)) {
+ FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
+ if (parentNode) {
+ FolderNode *grandParentNode = visibleFolderNode(parentNode->parentFolderNode());
+ if (grandParentNode) {
+ QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(grandParentNode);
+ if (it == m_childNodes.constEnd()) {
+ fetchMore(grandParentNode);
+ it = m_childNodes.constFind(grandParentNode);
+ }
+ Q_ASSERT(it != m_childNodes.constEnd());
+ const int row = it.value().indexOf(parentNode);
+ Q_ASSERT(row >= 0);
+ parentIndex = createIndex(row, 0, parentNode);
+ } else {
+ // top level node, parent is session
+ parentIndex = index(0, 0, QModelIndex());
+ }
+ }
+ }
+
+// qDebug() << "parent of " << idx.data(Project::FilePathRole) << " is " << parentIndex.data(Project::FilePathRole);
+
+ return parentIndex;
+}
+
+QVariant FlatModel::data(const QModelIndex &index, int role) const
+{
+ QVariant result;
+
+ if (Node *node = nodeForIndex(index)) {
+ FolderNode *folderNode = qobject_cast<FolderNode*>(node);
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ if (folderNode)
+ result = folderNode->name();
+ else
+ result = QFileInfo(node->path()).fileName(); //TODO cache that?
+ break;
+ }
+ case Qt::ToolTipRole: {
+ result = node->path();
+ break;
+ }
+ case Qt::DecorationRole: {
+ if (folderNode)
+ result = folderNode->icon();
+ else
+ result = FileIconProvider::instance()->icon(QFileInfo(node->path()));
+ break;
+ }
+ case Qt::FontRole: {
+ QFont font;
+ if (node == m_startupProject)
+ font.setBold(true);
+ result = font;
+ break;
+ }
+ case ProjectExplorer::Project::FilePathRole: {
+ result = node->path();
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+int FlatModel::rowCount(const QModelIndex &parent) const
+{
+ int rows = 0;
+ if (!parent.isValid()) {
+ rows = 1;
+ } else {
+ FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ if (folderNode && m_childNodes.contains(folderNode))
+ rows = m_childNodes.value(folderNode).size();
+ }
+ return rows;
+}
+
+int FlatModel::columnCount(const QModelIndex &/*parent*/) const
+{
+ return 1;
+}
+
+bool FlatModel::hasChildren(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return true;
+
+ FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ if (!folderNode)
+ return false;
+
+ QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(folderNode);
+ if (it == m_childNodes.constEnd()) {
+ fetchMore(folderNode);
+ it = m_childNodes.constFind(folderNode);
+ }
+ return !it.value().isEmpty();
+}
+
+bool FlatModel::canFetchMore(const QModelIndex & parent) const
+{
+ if (!parent.isValid()) {
+ return false;
+ } else {
+ if (FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent)))
+ return !m_childNodes.contains(folderNode);
+ else
+ return false;
+ }
+}
+
+void FlatModel::recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
+{
+ foreach (FolderNode *folderNode, startNode->subFolderNodes()) {
+ if (folderNode && !blackList.contains(folderNode))
+ recursiveAddFolderNodesImpl(folderNode, list, blackList);
+ }
+}
+
+void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
+{
+ if (!filter(startNode)) {
+ if (!blackList.contains(startNode))
+ list->append(startNode);
+ } else {
+ foreach (FolderNode *folderNode, startNode->subFolderNodes()) {
+ if (folderNode && !blackList.contains(folderNode))
+ recursiveAddFolderNodesImpl(folderNode, list, blackList);
+ }
+ }
+}
+
+void FlatModel::recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
+{
+ foreach (FolderNode *subFolderNode, startNode->subFolderNodes()) {
+ if (!blackList.contains(subFolderNode))
+ recursiveAddFileNodes(subFolderNode, list, blackList);
+ }
+ foreach (Node *node, startNode->fileNodes()) {
+ if (!blackList.contains(node) && !filter(node))
+ list->append(node);
+ }
+}
+
+QList<Node*> FlatModel::childNodes(FolderNode *parentNode, const QSet<Node*> &blackList) const
+{
+ QList<Node*> nodeList;
+
+ if (parentNode->nodeType() == SessionNodeType) {
+ SessionNode *sessionNode = static_cast<SessionNode*>(parentNode);
+ QList<ProjectNode*> projectList = sessionNode->projectNodes();
+ for (int i = 0; i < projectList.size(); ++i) {
+ if (!blackList.contains(projectList.at(i)))
+ nodeList << projectList.at(i);
+ }
+ } else {
+ recursiveAddFolderNodes(parentNode, &nodeList, blackList);
+ recursiveAddFileNodes(parentNode, &nodeList, blackList + nodeList.toSet());
+ }
+ qSort(nodeList.begin(), nodeList.end(), sortNodes);
+ return nodeList;
+}
+
+void FlatModel::fetchMore(FolderNode *folderNode) const
+{
+ Q_ASSERT(folderNode);
+ Q_ASSERT(!m_childNodes.contains(folderNode));
+
+ QList<Node*> nodeList = childNodes(folderNode);
+ m_childNodes.insert(folderNode, nodeList);
+}
+
+void FlatModel::fetchMore(const QModelIndex &parent)
+{
+ FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
+ Q_ASSERT(folderNode);
+
+ fetchMore(folderNode);
+}
+
+void FlatModel::setStartupProject(ProjectNode *projectNode)
+{
+ if (m_startupProject != projectNode) {
+ QModelIndex oldIndex = (m_startupProject ? indexForNode(m_startupProject) : QModelIndex());
+ QModelIndex newIndex = (projectNode ? indexForNode(projectNode) : QModelIndex());
+ m_startupProject = projectNode;
+ if (oldIndex.isValid())
+ emit dataChanged(oldIndex, oldIndex);
+ if (newIndex.isValid())
+ emit dataChanged(newIndex, newIndex);
+ }
+}
+
+void FlatModel::reset()
+{
+ m_childNodes.clear();
+ QAbstractItemModel::reset();
+}
+
+QModelIndex FlatModel::indexForNode(const Node *node_)
+{
+ // We assume that we are only called for nodes that are represented
+
+ // we use non-const pointers internally
+ Node *node = const_cast<Node*>(node_);
+ if (!node)
+ return QModelIndex();
+
+ if (node == m_rootNode)
+ return createIndex(0, 0, m_rootNode);
+
+ FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
+
+ // Do we have the parent mapped?
+ QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
+ if (it == m_childNodes.constEnd()) {
+ fetchMore(parentNode);
+ it = m_childNodes.constFind(parentNode);
+ }
+ if (it != m_childNodes.constEnd()) {
+ const int row = it.value().indexOf(node);
+ if (row != -1)
+ return createIndex(row, 0, node);
+ }
+ return QModelIndex();
+}
+
+void FlatModel::setProjectFilterEnabled(bool filter)
+{
+ m_filterProjects = filter;
+ reset();
+}
+
+void FlatModel::setGeneratedFilesFilterEnabled(bool filter)
+{
+ m_filterGeneratedFiles = filter;
+ reset();
+}
+
+Node *FlatModel::nodeForIndex(const QModelIndex &index) const
+{
+ if (index.isValid())
+ return (Node*)index.internalPointer();
+ return 0;
+}
+
+/*
+ Returns the first folder node in the ancestors
+ for the given node that is not filtered
+ out by the Flat Model.
+*/
+FolderNode *FlatModel::visibleFolderNode(FolderNode *node) const
+{
+ if (!node)
+ return 0;
+
+ for (FolderNode *folderNode = node;
+ folderNode;
+ folderNode = folderNode->parentFolderNode()) {
+ if (!filter(folderNode))
+ return folderNode;
+ }
+ return 0;
+}
+
+bool FlatModel::filter(Node *node) const
+{
+ bool isHidden = false;
+ if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(node)) {
+ if (m_filterProjects && projectNode->parentFolderNode() != m_rootNode)
+ isHidden = !projectNode->hasTargets();
+ }
+ if (FileNode *fileNode = qobject_cast<FileNode*>(node)) {
+ if (m_filterGeneratedFiles)
+ isHidden = fileNode->isGenerated();
+ }
+
+ return isHidden;
+}
+
+/// slots and all the fun
+void FlatModel::added(FolderNode* parentNode, const QList<Node*> &newNodeList)
+{
+ QModelIndex parentIndex = indexForNode(parentNode);
+ // Old list
+ QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
+ if (it == m_childNodes.constEnd())
+ return;
+ QList<Node *> oldNodeList = it.value();
+
+ // Compare lists and emit signals, and modify m_childNodes on the fly
+ QList<Node *>::const_iterator oldIter = oldNodeList.constBegin();
+ QList<Node *>::const_iterator newIter = newNodeList.constBegin();
+
+ // optimization, check for old list is empty
+ if (oldIter == oldNodeList.constEnd()) {
+ // New Node List is empty, nothing added which intrest us
+ if (newIter == newNodeList.constEnd())
+ return;
+ // So all we need to do is easy
+ beginInsertRows(parentIndex, 0, newNodeList.size() - 1);
+ m_childNodes.insert(parentNode, newNodeList);
+ endInsertRows();
+ return;
+ }
+
+ while(true)
+ {
+ // Skip all that are the same
+ while(*oldIter == *newIter) {
+ ++oldIter;
+ ++newIter;
+ if (oldIter == oldNodeList.constEnd()) {
+ // At end of oldNodeList, sweep up rest of newNodeList
+ QList<Node *>::const_iterator startOfBlock = newIter;
+ newIter = newNodeList.constEnd();
+ int pos = oldIter - oldNodeList.constBegin();
+ int count = newIter - startOfBlock;
+ if (count > 0) {
+ beginInsertRows(parentIndex, pos, pos+count-1);
+ while(startOfBlock != newIter) {
+ oldNodeList.insert(pos, *startOfBlock);
+ ++pos;
+ ++startOfBlock;
+ }
+ m_childNodes.insert(parentNode, oldNodeList);
+ endInsertRows();
+ }
+ return; // Done with the lists, leave the function
+ }
+ }
+
+ QList<Node *>::const_iterator startOfBlock = newIter;
+ while(*oldIter != *newIter)
+ ++newIter;
+ // startOfBlock is the first that was diffrent
+ // newIter points to the new position of oldIter
+ // newIter - startOfBlock is number of new items
+ // oldIter is the position where those are...
+ int pos = oldIter - oldNodeList.constBegin();
+ int count = newIter - startOfBlock;
+ beginInsertRows(parentIndex, pos, pos + count - 1);
+ while(startOfBlock != newIter) {
+ oldNodeList.insert(pos, *startOfBlock);
+ ++pos;
+ ++startOfBlock;
+ }
+ m_childNodes.insert(parentNode, oldNodeList);
+ endInsertRows();
+ oldIter = oldNodeList.constBegin() + pos;
+ }
+}
+
+void FlatModel::removed(FolderNode* parentNode, const QList<Node*> &newNodeList)
+{
+ QModelIndex parentIndex = indexForNode(parentNode);
+ // Old list
+ QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode);
+ if (it == m_childNodes.constEnd())
+ return;
+ QList<Node *> oldNodeList = it.value();
+ // Compare lists and emit signals, and modify m_childNodes on the fly
+ QList<Node *>::const_iterator oldIter = oldNodeList.constBegin();
+ QList<Node *>::const_iterator newIter = newNodeList.constBegin();
+
+ // optimization, check for new list is empty
+ if (newIter == newNodeList.constEnd()) {
+ // New Node List is empty, everything removed
+ if (oldIter == oldNodeList.constEnd())
+ return;
+ // So all we need to do is easy
+ beginRemoveRows(parentIndex, 0, oldNodeList.size() - 1);
+ m_childNodes.insert(parentNode, newNodeList);
+ endRemoveRows();
+ return;
+ }
+
+ while(true)
+ {
+ // Skip all that are the same
+ while(*oldIter == *newIter) {
+ ++oldIter;
+ ++newIter;
+ if (newIter == newNodeList.constEnd()) {
+ // At end of newNodeList, sweep up rest of oldNodeList
+ QList<Node *>::const_iterator startOfBlock = oldIter;
+ oldIter = oldNodeList.constEnd();
+ int pos = startOfBlock - oldNodeList.constBegin();
+ int count = oldIter - startOfBlock;
+ if (count > 0) {
+ beginRemoveRows(parentIndex, pos, pos+count-1);
+ while(startOfBlock != oldIter) {
+ ++startOfBlock;
+ oldNodeList.removeAt(pos);
+ }
+
+ m_childNodes.insert(parentNode, oldNodeList);
+ endRemoveRows();
+ }
+ return; // Done with the lists, leave the function
+ }
+ }
+
+ QList<Node *>::const_iterator startOfBlock = oldIter;
+ while(*oldIter != *newIter)
+ ++oldIter;
+ // startOfBlock is the first that was diffrent
+ // oldIter points to the new position of newIter
+ // oldIter - startOfBlock is number of new items
+ // newIter is the position where those are...
+ int pos = startOfBlock - oldNodeList.constBegin();
+ int count = oldIter - startOfBlock;
+ beginRemoveRows(parentIndex, pos, pos + count - 1);
+ while(startOfBlock != oldIter) {
+ ++startOfBlock;
+ oldNodeList.removeAt(pos);
+ }
+ m_childNodes.insert(parentNode, oldNodeList);
+ endRemoveRows();
+ oldIter = oldNodeList.constBegin() + pos;
+ }
+}
+
+void FlatModel::foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders)
+{
+ Q_UNUSED(newFolders)
+ m_parentFolderForChange = parentFolder;
+}
+
+void FlatModel::foldersAdded()
+{
+ // First found out what the folder is that we are adding the files to
+ FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange);
+
+ // Now get the new list for that folder
+ QList<Node *> newNodeList = childNodes(folderNode);
+
+ added(folderNode, newNodeList);
+}
+
+void FlatModel::foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders)
+{
+ QSet<Node *> blackList;
+ foreach(FolderNode * node, staleFolders)
+ blackList.insert(node);
+
+ FolderNode *folderNode = visibleFolderNode(parentFolder);
+ QList<Node *> newNodeList = childNodes(folderNode, blackList);
+
+ removed(parentFolder, newNodeList);
+ removeFromCache(staleFolders);
+}
+
+void FlatModel::removeFromCache(QList<FolderNode *> list)
+{
+ foreach(FolderNode * fn, list) {
+ removeFromCache(fn->subFolderNodes());
+ m_childNodes.remove(fn);
+ }
+}
+
+void FlatModel::foldersRemoved()
+{
+ // Do nothing
+}
+
+void FlatModel::filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles)
+{
+ Q_UNUSED(newFiles)
+ m_parentFolderForChange = folder;
+}
+
+void FlatModel::filesAdded()
+{
+ // First find out what the folder is that we are adding the files to
+ FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange);
+
+ // Now get the new List for that folder
+ QList<Node *> newNodeList = childNodes(folderNode);
+ added(folderNode, newNodeList);
+}
+
+void FlatModel::filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles)
+{
+ // First found out what the folder (that is the project) is that we are adding the files to
+ FolderNode *folderNode = visibleFolderNode(folder);
+
+ QSet<Node *> blackList;
+ foreach(Node* node, staleFiles)
+ blackList.insert(node);
+
+ // Now get the new List for that folder
+ QList<Node *> newNodeList = childNodes(folderNode, blackList);
+ removed(folderNode, newNodeList);
+}
+
+void FlatModel::filesRemoved()
+{
+ // Do nothing
+}
diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h
new file mode 100644
index 0000000000..ecccefe188
--- /dev/null
+++ b/src/plugins/projectexplorer/projectmodels.h
@@ -0,0 +1,186 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTMODELS_H
+#define PROJECTMODELS_H
+
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QSet>
+
+namespace ProjectExplorer {
+
+class Node;
+class FileNode;
+class FolderNode;
+class ProjectNode;
+class SessionNode;
+
+namespace Internal {
+
+// A 1:1 mapping of the internal data model
+class DetailedModel : public QAbstractItemModel {
+ Q_OBJECT
+public:
+ DetailedModel(SessionNode *rootNode, QObject *parent);
+
+ // QAbstractItemModel
+ QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ Qt::ItemFlags flags(const QModelIndex & index) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ int rowCount(const QModelIndex & parent = QModelIndex()) const;
+ int columnCount(const QModelIndex & parent = QModelIndex()) const;
+ bool hasChildren(const QModelIndex & parent = QModelIndex()) const;
+
+ bool canFetchMore(const QModelIndex & parent) const;
+ void fetchMore(const QModelIndex & parent);
+
+ void reset();
+
+ void setStartupProject(ProjectNode * /* projectNode */) {}
+
+ Node *nodeForIndex(const QModelIndex &index) const;
+ QModelIndex indexForNode(const Node *node);
+
+ public slots:
+ void setProjectFilterEnabled(bool /* filter */) {}
+
+private slots:
+ void foldersAboutToBeAdded(FolderNode *parentFolder,
+ const QList<FolderNode*> &newFolders);
+ void foldersAdded();
+
+ void foldersAboutToBeRemoved(FolderNode *parentFolder,
+ const QList<FolderNode*> &staleFolders);
+
+ void filesAboutToBeAdded(FolderNode *folder,
+ const QList<FileNode*> &newFiles);
+ void filesAdded();
+
+ void filesAboutToBeRemoved(FolderNode *folder,
+ const QList<FileNode*> &staleFiles);
+
+private:
+ QList<Node*> childNodeList(FolderNode *folderNode) const;
+
+ void connectProject(ProjectNode *project);
+ void addToChildNodes(FolderNode *parentFolder, QList<Node*> newList);
+ void removeFromChildNodes(FolderNode *parentFolder, QList<Node*> newList);
+ QList<FolderNode*> recursiveSubFolders(FolderNode *parentFolder);
+
+ SessionNode *m_rootNode;
+ mutable QHash<FolderNode*, QList<Node*> > m_childNodes;
+ bool m_isStartupProject;
+
+ FolderNode *m_folderToAddTo;
+
+ friend class DetailedModelManager;
+};
+
+
+// displays "flattened" view without pri files, subdirs pro files & virtual folders
+// This view is optimized to be used in the edit mode sidebar
+class FlatModel : public QAbstractItemModel {
+ Q_OBJECT
+public:
+ FlatModel(SessionNode *rootNode, QObject *parent);
+
+ // QAbstractItemModel
+ 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;
+
+ int rowCount(const QModelIndex & parent = QModelIndex()) const;
+ int columnCount(const QModelIndex & parent = QModelIndex()) const;
+ bool hasChildren(const QModelIndex & parent = QModelIndex()) const;
+
+ bool canFetchMore(const QModelIndex & parent) const;
+ void fetchMore(const QModelIndex & parent);
+
+ void reset();
+
+ void setStartupProject(ProjectNode *projectNode);
+
+ ProjectExplorer::Node *nodeForIndex(const QModelIndex &index) const;
+ QModelIndex indexForNode(const Node *node);
+
+public slots:
+ void setProjectFilterEnabled(bool filter);
+ void setGeneratedFilesFilterEnabled(bool filter);
+
+private slots:
+ void foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders);
+ void foldersAdded();
+
+ void foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders);
+ void foldersRemoved();
+
+ // files
+ void filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles);
+ void filesAdded();
+
+ void filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles);
+ void filesRemoved();
+
+private:
+ void added(FolderNode* folderNode, const QList<Node*> &newNodeList);
+ void removed(FolderNode* parentNode, const QList<Node*> &newNodeList);
+ void removeFromCache(QList<FolderNode *> list);
+ void fetchMore(FolderNode *foldernode) const;
+
+ void recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const;
+ void recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const;
+ void recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const;
+ QList<Node*> childNodes(FolderNode *parentNode, const QSet<Node*> &blackList = QSet<Node*>()) const;
+
+ FolderNode *visibleFolderNode(FolderNode *node) const;
+ bool filter(Node *node) const;
+
+ bool m_filterProjects;
+ bool m_filterGeneratedFiles;
+
+ SessionNode *m_rootNode;
+ mutable QHash<FolderNode*, QList<Node*> > m_childNodes;
+ ProjectNode *m_startupProject;
+
+ FolderNode *m_parentFolderForChange;
+
+ friend class FlatModelManager;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+
+#endif // PROJECTMODELS_H
diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
new file mode 100644
index 0000000000..39ccf9e710
--- /dev/null
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -0,0 +1,685 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "nodesvisitor.h"
+#include "projectnodes.h"
+#include "projectexplorerconstants.h"
+
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QFileInfo>
+#include <QtGui/QApplication>
+#include <QtGui/QIcon>
+#include <QtGui/QStyle>
+
+using namespace ProjectExplorer;
+
+/*!
+ \class FileNode
+
+ Base class of all nodes in the node hierarchy.
+
+ \see FileNode
+ \see FolderNode
+ \see ProjectNode
+*/
+Node::Node(NodeType nodeType,
+ const QString &filePath)
+ : QObject(),
+ m_nodeType(nodeType),
+ m_projectNode(0),
+ m_folderNode(0),
+ m_path(filePath)
+{
+}
+
+NodeType Node::nodeType() const
+{
+ return m_nodeType;
+}
+
+/*!
+ Project that owns & manages the node. It's the first project in list of ancestors.
+ */
+ProjectNode *Node::projectNode() const
+{
+ return m_projectNode;
+}
+
+/*!
+ Parent in node hierarchy.
+ */
+FolderNode *Node::parentFolderNode() const
+{
+ return m_folderNode;
+}
+
+/*!
+ Path of file or folder in the filesystem the node represents.
+ */
+QString Node::path() const
+{
+ return m_path;
+}
+
+void Node::setNodeType(NodeType type)
+{
+ m_nodeType = type;
+}
+
+void Node::setProjectNode(ProjectNode *project)
+{
+ m_projectNode = project;
+}
+
+void Node::setParentFolderNode(FolderNode *parentFolder)
+{
+ m_folderNode = parentFolder;
+}
+
+void Node::setPath(const QString &path)
+{
+ m_path = path;
+}
+
+/*!
+ \class FileNode
+
+ In-memory presentation of a file. All FileNode's are leaf nodes.
+
+ \see FolderNode
+ \see ProjectNode
+*/
+
+FileNode::FileNode(const QString &filePath,
+ const FileType fileType,
+ bool generated)
+ : Node(FileNodeType, filePath),
+ m_fileType(fileType),
+ m_generated(generated)
+{
+}
+
+FileType FileNode::fileType() const
+{
+ return m_fileType;
+}
+
+/*!
+ Returns true if the file is automatically generated by a compile step.
+ */
+bool FileNode::isGenerated() const
+{
+ return m_generated;
+}
+
+/*!
+ \class FolderNode
+
+ In-memory presentation of a folder. Note that the node itself + all children (files and folders) are "managed" by the owning project.
+
+ \see FileNode
+ \see ProjectNode
+*/
+FolderNode::FolderNode(const QString &folderPath)
+ : Node(FolderNodeType, folderPath),
+ m_folderName(folderPath)
+{
+ m_icon = QApplication::style()->standardIcon(QStyle::SP_DirIcon);
+}
+
+FolderNode::~FolderNode()
+{
+ qDeleteAll(m_subFolderNodes);
+ qDeleteAll(m_fileNodes);
+}
+
+/*
+ The display name that should be used in a view.
+
+
+ \see setFolderName()
+ */
+QString FolderNode::name() const
+{
+ return m_folderName;
+}
+
+/*
+ The icon that should be used in a view. Default is the directory icon (QStyle::S_PDirIcon).
+ \see setIcon()
+ */
+QIcon FolderNode::icon() const
+{
+ return m_icon;
+}
+
+QList<FileNode*> FolderNode::fileNodes() const
+{
+ return m_fileNodes;
+}
+
+QList<FolderNode*> FolderNode::subFolderNodes() const
+{
+ return m_subFolderNodes;
+}
+
+void FolderNode::accept(NodesVisitor *visitor)
+{
+ visitor->visitFolderNode(this);
+ foreach (FolderNode *subFolder, m_subFolderNodes)
+ subFolder->accept(visitor);
+}
+
+void FolderNode::setFolderName(const QString &name)
+{
+ m_folderName = name;
+}
+
+void FolderNode::setIcon(const QIcon &icon)
+{
+ m_icon = icon;
+}
+
+/*!
+ \class ProjectNode
+
+ In-memory presentation of a Project.
+ A concrete subclass must implement the "persistent" stuff
+
+ \see FileNode
+ \see FolderNode
+*/
+
+/*
+ Creates uninitialized ProjectNode object.
+ */
+ProjectNode::ProjectNode(const QString &projectFilePath)
+ : FolderNode(projectFilePath)
+{
+ setNodeType(ProjectNodeType);
+ // project node "manages" itself
+ setProjectNode(this);
+ setFolderName(QFileInfo(m_folderName).fileName());
+}
+
+QList<ProjectNode*> ProjectNode::subProjectNodes() const
+{
+ return m_subProjectNodes;
+}
+
+/*!
+ \function bool ProjectNode::addSubProjects(const QStringList &)
+ */
+
+/*!
+ \function bool ProjectNode::removeSubProjects(const QStringList &)
+ */
+
+/*!
+ \function bool ProjectNode::addFiles(const FileType, const QStringList &, QStringList *)
+ */
+
+/*!
+ \function bool ProjectNode::removeFiles(const FileType, const QStringList &, QStringList *)
+ */
+
+/*!
+ \function bool ProjectNode::renameFile(const FileType, const QString &, const QString &)
+ */
+
+QList<NodesWatcher*> ProjectNode::watchers() const
+{
+ return m_watchers;
+}
+
+/*
+ Registers a watcher for the current project & all sub projects
+ It does not take ownership of the watcher.
+ */
+void ProjectNode::registerWatcher(NodesWatcher *watcher)
+{
+ if (!watcher)
+ return;
+ connect(watcher, SIGNAL(destroyed(QObject *)),
+ this, SLOT(watcherDestroyed(QObject *)));
+ m_watchers.append(watcher);
+ foreach (ProjectNode *subProject, m_subProjectNodes)
+ subProject->registerWatcher(watcher);
+}
+
+/*
+ Removes a watcher for the current project & all sub projects.
+*/
+void ProjectNode::unregisterWatcher(NodesWatcher *watcher)
+{
+ if (!watcher)
+ return;
+ m_watchers.removeOne(watcher);
+ foreach (ProjectNode *subProject, m_subProjectNodes)
+ subProject->unregisterWatcher(watcher);
+}
+
+void ProjectNode::accept(NodesVisitor *visitor)
+{
+ visitor->visitProjectNode(this);
+
+ foreach (FolderNode *folder, m_subFolderNodes)
+ folder->accept(visitor);
+}
+
+/*!
+ Adds project nodes to the hierarchy and emits the corresponding signals.
+ */
+void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
+{
+ if (!subProjects.isEmpty()) {
+ QList<FolderNode*> folderNodes;
+ foreach (ProjectNode *projectNode, subProjects)
+ folderNodes << projectNode;
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAboutToBeAdded(this, folderNodes);
+
+ foreach (ProjectNode *project, subProjects) {
+ Q_ASSERT_X(!project->parentFolderNode(), "addProjectNodes",
+ "Project node has already a parent");
+ project->setParentFolderNode(this);
+ foreach (NodesWatcher *watcher, m_watchers)
+ project->registerWatcher(watcher);
+ m_subFolderNodes.append(project);
+ m_subProjectNodes.append(project);
+ }
+ qSort(m_subFolderNodes.begin(), m_subFolderNodes.end(),
+ sortNodesByPath);
+ qSort(m_subProjectNodes.begin(), m_subProjectNodes.end(),
+ sortNodesByPath);
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAdded();
+ }
+}
+
+/*!
+ Remove project nodes from the hierarchy and emits the corresponding signals.
+ All objects in the argument list are deleted.
+ */
+void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
+{
+ if (!subProjects.isEmpty()) {
+ QList<FolderNode*> toRemove;
+ foreach (ProjectNode *projectNode, subProjects)
+ toRemove << projectNode;
+ qSort(toRemove.begin(), toRemove.end(), sortNodesByPath);
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAboutToBeRemoved(this, toRemove);
+
+ QList<FolderNode*>::const_iterator toRemoveIter = toRemove.constBegin();
+ QList<FolderNode*>::iterator folderIter = m_subFolderNodes.begin();
+ QList<ProjectNode*>::iterator projectIter = m_subProjectNodes.begin();
+ for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
+ while ((*projectIter)->path() != (*toRemoveIter)->path()) {
+ ++projectIter;
+ Q_ASSERT_X(projectIter != m_subProjectNodes.end(), "removeProjectNodes",
+ "Project to remove is not part of specified folder!");
+ }
+ while ((*folderIter)->path() != (*toRemoveIter)->path()) {
+ ++folderIter;
+ Q_ASSERT_X(folderIter != m_subFolderNodes.end(), "removeProjectNodes",
+ "Project to remove is not part of specified folder!");
+ }
+ delete *projectIter;
+ projectIter = m_subProjectNodes.erase(projectIter);
+ folderIter = m_subFolderNodes.erase(folderIter);
+ }
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersRemoved();
+ }
+}
+
+/*!
+ Adds folder nodes to the hierarchy and emits the corresponding signals.
+ */
+void ProjectNode::addFolderNodes(const QList<FolderNode*> &subFolders, FolderNode *parentFolder)
+{
+ Q_ASSERT(parentFolder);
+
+ if (!subFolders.isEmpty()) {
+ const bool emitSignals = (parentFolder->projectNode() == this);
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ watcher->foldersAboutToBeAdded(parentFolder, subFolders);
+
+ foreach (FolderNode *folder, subFolders) {
+ Q_ASSERT_X(!folder->parentFolderNode(), "addFolderNodes",
+ "Project node has already a parent folder");
+ folder->setParentFolderNode(parentFolder);
+ folder->setProjectNode(this);
+ parentFolder->m_subFolderNodes.append(folder);
+
+ // project nodes have to be added via addProjectNodes
+ Q_ASSERT_X(folder->nodeType() != ProjectNodeType, "addFolderNodes",
+ "project nodes have to be added via addProjectNodes");
+ }
+ qSort(parentFolder->m_subFolderNodes.begin(), parentFolder->m_subFolderNodes.end(),
+ sortNodesByPath);
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAdded();
+ }
+}
+
+/*!
+ Remove file nodes from the hierarchy and emits the corresponding signals.
+ All objects in the subFolders list are deleted.
+ */
+void ProjectNode::removeFolderNodes(const QList<FolderNode*> &subFolders,
+ FolderNode *parentFolder)
+{
+ Q_ASSERT(parentFolder);
+
+ if (!subFolders.isEmpty()) {
+ const bool emitSignals = (parentFolder->projectNode() == this);
+
+ QList<FolderNode*> toRemove = subFolders;
+ qSort(toRemove.begin(), toRemove.end(), sortNodesByPath);
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAboutToBeRemoved(parentFolder, toRemove);
+
+ QList<FolderNode*>::const_iterator toRemoveIter = toRemove.constBegin();
+ QList<FolderNode*>::iterator folderIter = parentFolder->m_subFolderNodes.begin();
+ for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
+ Q_ASSERT_X(((*toRemoveIter)->nodeType() != ProjectNodeType), "removeFolderNodes",
+ "project nodes have to be removed via removeProjectNodes");
+ while ((*folderIter)->path() != (*toRemoveIter)->path()) {
+ ++folderIter;
+ Q_ASSERT_X(folderIter != parentFolder->m_subFolderNodes.end(), "removeFileNodes",
+ "Folder to remove is not part of specified folder!");
+ }
+ delete *folderIter;
+ folderIter = parentFolder->m_subFolderNodes.erase(folderIter);
+ }
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersRemoved();
+ }
+}
+
+/*!
+ Adds file nodes to the internal list and emits the corresponding signals.
+ This method should be called within an implementation of the public method addFiles.
+ */
+void ProjectNode::addFileNodes(const QList<FileNode*> &files, FolderNode *folder)
+{
+ Q_ASSERT(folder);
+
+ if (!files.isEmpty()) {
+ const bool emitSignals = (folder->projectNode() == this);
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->filesAboutToBeAdded(folder, files);
+
+ foreach (FileNode *file, files) {
+ Q_ASSERT_X(!file->parentFolderNode(), "addFileNodes",
+ "File node has already a parent folder");
+
+ file->setParentFolderNode(folder);
+ file->setProjectNode(this);
+ folder->m_fileNodes.append(file);
+ }
+ qSort(folder->m_fileNodes.begin(), folder->m_fileNodes.end(), sortNodesByPath);
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->filesAdded();
+ }
+}
+
+/*!
+ Remove file nodes from the internal list and emits the corresponding signals.
+ All objects in the argument list are deleted.
+ This method should be called within an implementation of the public method removeFiles.
+ */
+void ProjectNode::removeFileNodes(const QList<FileNode*> &files, FolderNode *folder)
+{
+ Q_ASSERT(folder);
+
+ if (!files.isEmpty()) {
+ const bool emitSignals = (folder->projectNode() == this);
+
+ QList<FileNode*> toRemove = files;
+ qSort(toRemove.begin(), toRemove.end(), sortNodesByPath);
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->filesAboutToBeRemoved(folder, toRemove);
+
+ QList<FileNode*>::const_iterator toRemoveIter = toRemove.constBegin();
+ QList<FileNode*>::iterator filesIter = folder->m_fileNodes.begin();
+ for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
+ while ((*filesIter)->path() != (*toRemoveIter)->path()) {
+ ++filesIter;
+ Q_ASSERT_X(filesIter != folder->m_fileNodes.end(), "removeFileNodes",
+ "File to remove is not part of specified folder!");
+ }
+ delete *filesIter;
+ filesIter = folder->m_fileNodes.erase(filesIter);
+ }
+
+ if (emitSignals)
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->filesRemoved();
+ }
+}
+
+void ProjectNode::watcherDestroyed(QObject *watcher)
+{
+ // cannot use qobject_cast here
+ unregisterWatcher(static_cast<NodesWatcher*>(watcher));
+}
+
+/*!
+ Sort pointers to FileNodes
+ */
+bool ProjectNode::sortNodesByPath(Node *f1, Node *f2) {
+ return f1->path() < f2->path();
+}
+
+/*!
+ \class SessionNode
+*/
+
+SessionNode::SessionNode(const QString &sessionPath, QObject *parentObject)
+ : FolderNode(sessionPath)
+{
+ setParent(parentObject);
+ setNodeType(SessionNodeType);
+}
+
+QList<NodesWatcher*> SessionNode::watchers() const
+{
+ return m_watchers;
+}
+
+/*
+ Registers a watcher for the complete session tree.
+ It does not take ownership of the watcher.
+*/
+void SessionNode::registerWatcher(NodesWatcher *watcher)
+{
+ if (!watcher)
+ return;
+ connect(watcher, SIGNAL(destroyed(QObject*)),
+ this, SLOT(watcherDestroyed(QObject*)));
+ m_watchers.append(watcher);
+ foreach (ProjectNode *project, m_projectNodes)
+ project->registerWatcher(watcher);
+}
+
+/*
+ Removes a watcher from the complete session tree
+*/
+void SessionNode::unregisterWatcher(NodesWatcher *watcher)
+{
+ if (!watcher)
+ return;
+ m_watchers.removeOne(watcher);
+ foreach (ProjectNode *project, m_projectNodes)
+ project->unregisterWatcher(watcher);
+}
+
+void SessionNode::accept(NodesVisitor *visitor)
+{
+ visitor->visitSessionNode(this);
+ foreach (ProjectNode *project, m_projectNodes)
+ project->accept(visitor);
+}
+
+QList<ProjectNode*> SessionNode::projectNodes() const
+{
+ return m_projectNodes;
+}
+
+void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
+{
+ if (!projectNodes.isEmpty()) {
+ QList<FolderNode*> folderNodes;
+ foreach (ProjectNode *projectNode, projectNodes)
+ folderNodes << projectNode;
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAboutToBeAdded(this, folderNodes);
+
+ foreach (ProjectNode *project, projectNodes) {
+ Q_ASSERT_X(!project->parentFolderNode(), "addProjectNodes",
+ "Project node has already a parent folder");
+ project->setParentFolderNode(this);
+ foreach (NodesWatcher *watcher, m_watchers)
+ project->registerWatcher(watcher);
+ m_subFolderNodes.append(project);
+ m_projectNodes.append(project);
+ }
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAdded();
+ }
+}
+
+void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
+{
+ if (!projectNodes.isEmpty()) {
+ QList<FolderNode*> toRemove;
+ foreach (ProjectNode *projectNode, projectNodes)
+ toRemove << projectNode;
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersAboutToBeRemoved(this, toRemove);
+
+ QList<FolderNode*>::const_iterator toRemoveIter = toRemove.constBegin();
+ QList<FolderNode*>::iterator folderIter = m_subFolderNodes.begin();
+ QList<ProjectNode*>::iterator projectIter = m_projectNodes.begin();
+ for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
+ while ((*projectIter)->path() != (*toRemoveIter)->path()) {
+ ++projectIter;
+ Q_ASSERT_X(projectIter != m_projectNodes.end(), "removeProjectNodes",
+ "Project to remove is not part of specified folder!");
+ }
+ while ((*folderIter)->path() != (*toRemoveIter)->path()) {
+ ++folderIter;
+ Q_ASSERT_X(folderIter != m_subFolderNodes.end(), "removeProjectNodes",
+ "Project to remove is not part of specified folder!");
+ }
+ projectIter = m_projectNodes.erase(projectIter);
+ folderIter = m_subFolderNodes.erase(folderIter);
+ }
+
+ foreach (NodesWatcher *watcher, m_watchers)
+ emit watcher->foldersRemoved();
+ }
+}
+
+void SessionNode::watcherDestroyed(QObject *watcher)
+{
+ // cannot use qobject_cast here
+ unregisterWatcher(static_cast<NodesWatcher*>(watcher));
+}
+
+/*!
+ \class NodesWatcher
+
+ NodesWatcher let you keep track of changes in the tree.
+
+ Add a watcher by calling ProjectNode::registerWatcher() or
+ SessionNode::registerWatcher(). Whenever the tree underneath the
+ ProectNode or SessionNode changes (e.g. nodes are added/removed),
+ the corresponding signals of the NodesWatcher are emitted.
+ Watchers can be removed from the complete tree or a subtree
+ by calling ProjectNode::unregisterWatcher and
+ SessionNode::unregisterWatcher().
+
+ The NodesWatcher is similar to the Observer in the
+ well-known Observer pattern (Booch et al).
+*/
+
+NodesWatcher::NodesWatcher(QObject *parent)
+ : QObject(parent)
+{
+}
+
+// TODO Maybe put this in core, so that all can benefit
+FileType typeForFileName(const Core::MimeDatabase *db, const QFileInfo &file)
+{
+ const Core::MimeType mt = db->findByFile(file);
+ if (!mt)
+ return UnknownFileType;
+
+ const QString typeName = mt.type();
+ if (typeName == QLatin1String(Constants::CPP_SOURCE_MIMETYPE)
+ || typeName == QLatin1String(Constants::C_SOURCE_MIMETYPE))
+ return SourceType;
+ if (typeName == QLatin1String(Constants::CPP_HEADER_MIMETYPE)
+ || typeName == QLatin1String(Constants::C_HEADER_MIMETYPE))
+ return HeaderType;
+ if (typeName == QLatin1String(Constants::RESOURCE_MIMETYPE))
+ return ResourceType;
+ if (typeName == QLatin1String(Constants::FORM_MIMETYPE))
+ return FormType;
+ return UnknownFileType;
+}
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
new file mode 100644
index 0000000000..9eca475c09
--- /dev/null
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -0,0 +1,289 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTNODES_H
+#define PROJECTNODES_H
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtGui/QIcon>
+
+#include "projectexplorer_export.h"
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+QT_END_NAMESPACE
+
+
+namespace Core {
+ class MimeDatabase;
+}
+
+namespace ProjectExplorer {
+
+//
+// = Node hierarchy =
+//
+// The nodes are arranged in a tree where leaves are FileNodes and non-leaves are FolderNodes
+// A Project is a special Folder that manages the files and normal folders underneath it.
+//
+// The Watcher emits signals for structural changes in the hierarchy.
+// A Visitor can be used to traverse all Projects and other Folders.
+//
+
+enum NodeType {
+ FileNodeType = 1,
+ FolderNodeType,
+ ProjectNodeType,
+ SessionNodeType
+};
+
+// File types common for qt projects
+enum FileType {
+ UnknownFileType = 0,
+ HeaderType,
+ SourceType,
+ FormType,
+ ResourceType,
+ ProjectFileType,
+ FileTypeSize
+};
+
+class Node;
+class FileNode;
+class FileContainerNode;
+class FolderNode;
+class ProjectNode;
+class NodesWatcher;
+class NodesVisitor;
+
+class PROJECTEXPLORER_EXPORT Node : public QObject {
+ Q_OBJECT
+public:
+ NodeType nodeType() const;
+ ProjectNode *projectNode() const; // managing project
+ FolderNode *parentFolderNode() const; // parent folder or project
+ QString path() const; // file system path
+
+protected:
+ Node(NodeType nodeType, const QString &path);
+
+ void setNodeType(NodeType type);
+ void setProjectNode(ProjectNode *project);
+ void setParentFolderNode(FolderNode *parentFolder);
+ void setPath(const QString &path);
+
+private:
+ NodeType m_nodeType;
+ ProjectNode *m_projectNode;
+ FolderNode *m_folderNode;
+ QString m_path;
+};
+
+class PROJECTEXPLORER_EXPORT FileNode : public Node {
+ Q_OBJECT
+public:
+ FileNode(const QString &filePath, const FileType fileType, bool generated);
+
+ FileType fileType() const;
+ bool isGenerated() const;
+
+private:
+ // managed by ProjectNode
+ friend class ProjectNode;
+
+ FileType m_fileType;
+ bool m_generated;
+};
+
+class PROJECTEXPLORER_EXPORT FolderNode : public Node {
+ Q_OBJECT
+public:
+ explicit FolderNode(const QString &folderPath);
+ virtual ~FolderNode();
+
+ QString name() const;
+ QIcon icon() const;
+
+ QList<FileNode*> fileNodes() const;
+ QList<FolderNode*> subFolderNodes() const;
+
+ virtual void accept(NodesVisitor *visitor);
+
+protected:
+ void setFolderName(const QString &name);
+ void setIcon(const QIcon &icon);
+
+ QList<FolderNode*> m_subFolderNodes;
+ QList<FileNode*> m_fileNodes;
+
+private:
+ // managed by ProjectNode
+ friend class ProjectNode;
+ QString m_folderName;
+ QIcon m_icon;
+};
+
+class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode
+{
+ Q_OBJECT
+
+public:
+ enum ProjectAction {
+ AddSubProject,
+ RemoveSubProject,
+ AddFile,
+ RemoveFile
+ };
+
+ // all subFolders that are projects
+ QList<ProjectNode*> subProjectNodes() const;
+
+ // determines if the project will be shown in the flat view
+ // TODO find a better name
+ virtual bool hasTargets() const = 0;
+
+ virtual QList<ProjectAction> supportedActions() const = 0;
+
+ virtual bool addSubProjects(const QStringList &proFilePaths) = 0;
+
+ virtual bool removeSubProjects(const QStringList &proFilePaths) = 0;
+
+ virtual bool addFiles(const FileType fileType,
+ const QStringList &filePaths,
+ QStringList *notAdded = 0) = 0;
+ // TODO: Maybe remove fileType, can be detected by project
+ virtual bool removeFiles(const FileType fileType,
+ const QStringList &filePaths,
+ QStringList *notRemoved = 0) = 0;
+ virtual bool renameFile(const FileType fileType,
+ const QString &filePath,
+ const QString &newFilePath) = 0;
+
+ QList<NodesWatcher*> watchers() const;
+ void registerWatcher(NodesWatcher *watcher);
+ void unregisterWatcher(NodesWatcher *watcher);
+
+ void accept(NodesVisitor *visitor);
+
+ static bool sortNodesByPath(Node *n1, Node *n2);
+
+protected:
+ // this is just the in-memory representation, a subclass
+ // will add the persistent stuff
+ explicit ProjectNode(const QString &projectFilePath);
+
+ // to be called in implementation of
+ // the corresponding public methods
+ void addProjectNodes(const QList<ProjectNode*> &subProjects);
+ void removeProjectNodes(const QList<ProjectNode*> &subProjects);
+
+ void addFolderNodes(const QList<FolderNode*> &subFolders, FolderNode *parentFolder);
+ void removeFolderNodes(const QList<FolderNode*> &subFolders, FolderNode *parentFolder);
+
+ void addFileNodes(const QList<FileNode*> &files, FolderNode *parentFolder);
+ void removeFileNodes(const QList<FileNode*> &files, FolderNode *parentFolder);
+
+private slots:
+ void watcherDestroyed(QObject *watcher);
+
+private:
+ QList<ProjectNode*> m_subProjectNodes;
+ QList<NodesWatcher*> m_watchers;
+
+ // let SessionNode call setParentFolderNode
+ friend class SessionNode;
+};
+
+class PROJECTEXPLORER_EXPORT SessionNode : public FolderNode {
+ Q_OBJECT
+public:
+ SessionNode(const QString &sessionFilePath, QObject *parentObject);
+
+ QList<ProjectNode*> projectNodes() const;
+
+ QList<NodesWatcher*> watchers() const;
+ void registerWatcher(NodesWatcher *watcher);
+ void unregisterWatcher(NodesWatcher *watcher);
+
+ void accept(NodesVisitor *visitor);
+
+protected:
+ void addProjectNodes(const QList<ProjectNode*> &projectNodes);
+ void removeProjectNodes(const QList<ProjectNode*> &projectNodes);
+
+private slots:
+ void watcherDestroyed(QObject *watcher);
+
+private:
+ QList<ProjectNode*> m_projectNodes;
+ QList<NodesWatcher*> m_watchers;
+};
+
+class PROJECTEXPLORER_EXPORT NodesWatcher : public QObject {
+ Q_OBJECT
+public:
+ explicit NodesWatcher(QObject *parent = 0);
+
+signals:
+ // folders & projects
+ void foldersAboutToBeAdded(FolderNode *parentFolder,
+ const QList<FolderNode*> &newFolders);
+ void foldersAdded();
+
+ void foldersAboutToBeRemoved(FolderNode *parentFolder,
+ const QList<FolderNode*> &staleFolders);
+ void foldersRemoved();
+
+ // files
+ void filesAboutToBeAdded(FolderNode *folder,
+ const QList<FileNode*> &newFiles);
+ void filesAdded();
+
+ void filesAboutToBeRemoved(FolderNode *folder,
+ const QList<FileNode*> &staleFiles);
+ void filesRemoved();
+
+private:
+
+ // let project & session emit signals
+ friend class ProjectNode;
+ friend class SessionNode;
+};
+
+
+} // namespace ProjectExplorer
+
+// HACK: THERE SHOULD BE ONE PLACE TO MAKE THE FILE ENDING->FILE TYPE ASSOCIATION
+ProjectExplorer::FileType typeForFileName(const Core::MimeDatabase *db, const QFileInfo &file);
+
+#endif // PROJECTNODES_H
diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp
new file mode 100644
index 0000000000..108c8fd1aa
--- /dev/null
+++ b/src/plugins/projectexplorer/projecttreewidget.cpp
@@ -0,0 +1,327 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "projecttreewidget.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+#include "projectmodels.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtGui/QHeaderView>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QToolButton>
+#include <QtGui/QFocusEvent>
+#include <QtCore/QDebug>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+namespace {
+ bool debug = false;
+}
+
+class ProjectTreeView : public QTreeView
+{
+public:
+ ProjectTreeView()
+ {
+ setEditTriggers(QAbstractItemView::EditKeyPressed);
+ setFrameStyle(QFrame::NoFrame);
+ setIndentation(indentation() * 9/10);
+ {
+ QHeaderView *treeHeader = header();
+ treeHeader->setVisible(false);
+ treeHeader->setResizeMode(QHeaderView::ResizeToContents);
+ treeHeader->setStretchLastSection(true);
+ }
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ setUniformRowHeights(true);
+ setTextElideMode(Qt::ElideNone);
+// setExpandsOnDoubleClick(false);
+ }
+
+protected:
+ // This is a workaround to stop Qt from redrawing the project tree every
+ // time the user opens or closes a menu when it has focus. Would be nicer to
+ // fix it in Qt.
+ void focusInEvent(QFocusEvent *event)
+ {
+ if (event->reason() != Qt::PopupFocusReason)
+ QTreeView::focusInEvent(event);
+ }
+
+ void focusOutEvent(QFocusEvent *event)
+ {
+ if (event->reason() != Qt::PopupFocusReason)
+ QTreeView::focusOutEvent(event);
+ }
+};
+
+/*!
+ /class ProjectTreeWidget
+
+ Shows the projects in form of a tree.
+ */
+ProjectTreeWidget::ProjectTreeWidget(Core::ICore *core, QWidget *parent)
+ : QWidget(parent),
+ m_core(core),
+ m_explorer(ProjectExplorerPlugin::instance()),
+ m_view(0),
+ m_model(0),
+ m_filterProjectsAction(0),
+ m_autoSync(false)
+{
+ m_model = new FlatModel(m_explorer->session()->sessionNode(), this);
+
+ m_view = new ProjectTreeView;
+ m_view->setModel(m_model);
+ setFocusProxy(m_view);
+ initView();
+
+ QVBoxLayout *layout = new QVBoxLayout();
+ layout->addWidget(m_view);
+ layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(layout);
+
+ m_filterProjectsAction = new QAction(tr("Simplify tree"), this);
+ m_filterProjectsAction->setCheckable(true);
+ m_filterProjectsAction->setChecked(false); // default is the traditional complex tree
+ connect(m_filterProjectsAction, SIGNAL(toggled(bool)), this, SLOT(setProjectFilter(bool)));
+
+ m_filterGeneratedFilesAction = new QAction(tr("Hide generated files"), this);
+ m_filterGeneratedFilesAction->setCheckable(true);
+ m_filterGeneratedFilesAction->setChecked(true);
+ connect(m_filterGeneratedFilesAction, SIGNAL(toggled(bool)), this, SLOT(setGeneratedFilesFilter(bool)));
+
+ // connections
+ connect(m_model, SIGNAL(modelReset()),
+ this, SLOT(initView()));
+ connect(m_view, SIGNAL(activated(const QModelIndex&)),
+ this, SLOT(openItem(const QModelIndex&)));
+ connect(m_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
+ this, SLOT(handleCurrentItemChange(const QModelIndex&)));
+ connect(m_view, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(showContextMenu(const QPoint&)));
+ connect(m_explorer->session(), SIGNAL(singleProjectAdded(ProjectExplorer::Project *)),
+ this, SLOT(handleProjectAdded(ProjectExplorer::Project *)));
+ connect(m_explorer->session(), SIGNAL(startupProjectChanged(ProjectExplorer::Project *)),
+ this, SLOT(startupProjectChanged(ProjectExplorer::Project *)));
+
+ setAutoSynchronization(true);
+}
+
+void ProjectTreeWidget::toggleAutoSynchronization()
+{
+ setAutoSynchronization(!m_autoSync);
+}
+
+bool ProjectTreeWidget::autoSynchronization() const
+{
+ return m_autoSync;
+}
+
+void ProjectTreeWidget::setAutoSynchronization(bool sync, bool syncNow)
+{
+ if (sync == m_autoSync)
+ return;
+
+ m_autoSync = sync;
+
+ if (debug)
+ qDebug() << (m_autoSync ? "Enabling auto synchronization" : "Disabling auto synchronization");
+ if (m_autoSync) {
+ connect(m_explorer, SIGNAL(currentNodeChanged(ProjectExplorer::Node*, ProjectExplorer::Project*)),
+ this, SLOT(setCurrentItem(ProjectExplorer::Node*, ProjectExplorer::Project*)));
+ if (syncNow)
+ setCurrentItem(m_explorer->currentNode(), m_explorer->currentProject());
+ } else {
+ disconnect(m_explorer, SIGNAL(currentNodeChanged(ProjectExplorer::Node*, ProjectExplorer::Project*)),
+ this, SLOT(setCurrentItem(ProjectExplorer::Node*, ProjectExplorer::Project*)));
+ }
+}
+
+void ProjectTreeWidget::editCurrentItem()
+{
+ if (!m_view->selectionModel()->selectedIndexes().isEmpty())
+ m_view->edit(m_view->selectionModel()->selectedIndexes().first());
+}
+
+void ProjectTreeWidget::setCurrentItem(Node *node, Project *project)
+{
+ if (debug)
+ qDebug() << "ProjectTreeWidget::setCurrentItem(" << (project ? project->name() : "0")
+ << ", " << (node ? node->path() : "0") << ")";
+ if (!project) {
+ m_view->selectionModel()->reset();
+ return;
+ }
+
+ const QModelIndex mainIndex = m_model->indexForNode(node);
+
+ if (!mainIndex.isValid()) {
+ if (debug)
+ qDebug() << "no main index, clear selection";
+ m_view->selectionModel()->clearSelection();
+ } else if (mainIndex != m_view->selectionModel()->currentIndex()) {
+ QItemSelectionModel *selections = m_view->selectionModel();
+ if (debug)
+ qDebug() << "ProjectTreeWidget - changing selection";
+
+ selections->setCurrentIndex(mainIndex, QItemSelectionModel::SelectCurrent
+ | QItemSelectionModel::Clear);
+ m_view->scrollTo(mainIndex);
+ }
+}
+
+void ProjectTreeWidget::handleCurrentItemChange(const QModelIndex &current)
+{
+ Node *node = m_model->nodeForIndex(current);
+ Q_ASSERT(node);
+
+ bool autoSync = autoSynchronization();
+ setAutoSynchronization(false);
+ m_explorer->setCurrentNode(node);
+ setAutoSynchronization(autoSync, false);
+}
+
+void ProjectTreeWidget::showContextMenu(const QPoint &pos)
+{
+ QModelIndex index = m_view->indexAt(pos);
+ Node *node = m_model->nodeForIndex(index);
+ m_explorer->showContextMenu(m_view->mapToGlobal(pos), node);
+}
+
+void ProjectTreeWidget::handleProjectAdded(ProjectExplorer::Project *project)
+{
+ Node *node = project->rootProjectNode();
+ QModelIndex idx = m_model->indexForNode(node);
+ m_view->setExpanded(idx, true);
+}
+
+void ProjectTreeWidget::startupProjectChanged(ProjectExplorer::Project *project)
+{
+ if (project) {
+ ProjectNode *node = project->rootProjectNode();
+ m_model->setStartupProject(node);
+ } else {
+ m_model->setStartupProject(0);
+ }
+}
+
+void ProjectTreeWidget::initView()
+{
+ QModelIndex sessionIndex = m_model->index(0, 0);
+
+ // hide root folder
+ m_view->setRootIndex(sessionIndex);
+
+ while (m_model->canFetchMore(sessionIndex))
+ m_model->fetchMore(sessionIndex);
+
+ // expand top level projects
+ for (int i = 0; i < m_model->rowCount(sessionIndex); ++i) {
+ m_view->expand(m_model->index(i, 0, sessionIndex));
+ }
+
+ setCurrentItem(m_explorer->currentNode(), m_explorer->currentProject());
+}
+
+void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
+{
+ Node *node = m_model->nodeForIndex(mainIndex);
+ if (node->nodeType() == FileNodeType) {
+ m_core->editorManager()->openEditor(node->path());
+ m_core->editorManager()->ensureEditorManagerVisible();
+ }
+}
+
+void ProjectTreeWidget::setProjectFilter(bool filter)
+{
+ m_model->setProjectFilterEnabled(filter);
+ m_filterProjectsAction->setChecked(filter);
+}
+
+void ProjectTreeWidget::setGeneratedFilesFilter(bool filter)
+{
+ m_model->setGeneratedFilesFilterEnabled(filter);
+ m_filterGeneratedFilesAction->setChecked(filter);
+}
+
+ProjectTreeWidgetFactory::ProjectTreeWidgetFactory(Core::ICore *core)
+ : m_core(core)
+{
+}
+
+ProjectTreeWidgetFactory::~ProjectTreeWidgetFactory()
+{
+}
+
+QString ProjectTreeWidgetFactory::displayName()
+{
+ return tr("Projects");
+}
+
+QKeySequence ProjectTreeWidgetFactory::activationSequence()
+{
+ return QKeySequence(Qt::ALT + Qt::Key_X);
+}
+
+Core::NavigationView ProjectTreeWidgetFactory::createWidget()
+{
+ Core::NavigationView n;
+ ProjectTreeWidget *ptw = new ProjectTreeWidget(m_core);
+ n.widget = ptw;
+
+ QToolButton *filter = new QToolButton;
+ filter->setProperty("type", "dockbutton");
+ filter->setIcon(QIcon(":/projectexplorer/images/filtericon.png"));
+ filter->setToolTip(tr("Filter tree"));
+ filter->setPopupMode(QToolButton::InstantPopup);
+ QMenu *filterMenu = new QMenu(filter);
+ filterMenu->addAction(ptw->m_filterProjectsAction);
+ filterMenu->addAction(ptw->m_filterGeneratedFilesAction);
+ filter->setMenu(filterMenu);
+
+ QToolButton *toggleSync = new QToolButton;
+ toggleSync->setProperty("type", "dockbutton");
+ toggleSync->setIcon(QIcon(":/qworkbench/images/linkicon.png"));
+ toggleSync->setCheckable(true);
+ toggleSync->setChecked(ptw->autoSynchronization());
+ toggleSync->setToolTip(tr("Synchronize with Editor"));
+ connect(toggleSync, SIGNAL(clicked(bool)), ptw, SLOT(toggleAutoSynchronization()));
+
+ n.doockToolBarWidgets << filter << toggleSync;
+ return n;
+}
+
diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h
new file mode 100644
index 0000000000..a1ede3b8ab
--- /dev/null
+++ b/src/plugins/projectexplorer/projecttreewidget.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTTREEWIDGET_H
+#define PROJECTTREEWIDGET_H
+
+#include <coreplugin/inavigationwidgetfactory.h>
+
+#include <QtGui/QWidget>
+#include <QtGui/QTreeView>
+
+namespace Core {
+class ICore;
+}
+
+namespace ProjectExplorer {
+
+class ProjectExplorerPlugin;
+class Project;
+class Node;
+
+namespace Internal {
+
+class FlatModel;
+
+class ProjectTreeWidget : public QWidget {
+ Q_OBJECT
+public:
+ ProjectTreeWidget(Core::ICore *core, QWidget *parent = 0);
+
+ bool autoSynchronization() const;
+ void setAutoSynchronization(bool sync, bool syncNow = true);
+
+public slots:
+ void toggleAutoSynchronization();
+ void editCurrentItem();
+
+private slots:
+ void setCurrentItem(ProjectExplorer::Node *node, ProjectExplorer::Project *project);
+ void setProjectFilter(bool filter);
+ void setGeneratedFilesFilter(bool filter);
+
+ void handleCurrentItemChange(const QModelIndex &current);
+ void showContextMenu(const QPoint &pos);
+ void openItem(const QModelIndex &mainIndex);
+ void handleProjectAdded(ProjectExplorer::Project *project);
+ void startupProjectChanged(ProjectExplorer::Project *project);
+ void initView();
+
+private:
+ Core::ICore *m_core;
+ ProjectExplorerPlugin *m_explorer;
+ QTreeView *m_view;
+ FlatModel *m_model;
+ QAction *m_filterProjectsAction;
+ QAction *m_filterGeneratedFilesAction;
+
+ QModelIndex m_subIndex;
+ QString m_modelId;
+ bool m_autoSync;
+
+ friend class ProjectTreeWidgetFactory;
+};
+
+class ProjectTreeWidgetFactory : public Core::INavigationWidgetFactory
+{
+public:
+ ProjectTreeWidgetFactory(Core::ICore *core);
+ virtual ~ProjectTreeWidgetFactory();
+ virtual QString displayName();
+ virtual QKeySequence activationSequence();
+ virtual Core::NavigationView createWidget();
+private:
+ Core::ICore *m_core;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // PROJECTTREEWIDGET_H
diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp
new file mode 100644
index 0000000000..94532c4131
--- /dev/null
+++ b/src/plugins/projectexplorer/projectwindow.cpp
@@ -0,0 +1,273 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "project.h"
+#include "projectwindow.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+#include "iprojectproperties.h"
+#include "session.h"
+#include "projecttreewidget.h"
+
+#include <coreplugin/minisplitter.h>
+#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/icore.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QBoxLayout>
+#include <QtGui/QComboBox>
+#include <QtGui/QTabWidget>
+#include <QtGui/QToolBar>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QHeaderView>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+namespace {
+bool debug = false;
+}
+
+ProjectWindow::ProjectWindow(Core::ICore *core,
+ QWidget *parent) :
+ QWidget(parent),
+ m_core(core)
+{
+ setWindowTitle(tr("Project Explorer"));
+ setWindowIcon(QIcon(":/projectexplorer/images/projectexplorer.png"));
+
+ ExtensionSystem::PluginManager *pm = m_core->pluginManager();
+ ProjectExplorerPlugin *projectExplorer = m_projectExplorer = pm->getObject<ProjectExplorerPlugin>();
+ m_session = projectExplorer->session();
+
+ connect(m_session, SIGNAL(sessionLoaded()), this, SLOT(restoreStatus()));
+ connect(m_session, SIGNAL(aboutToSaveSession()), this, SLOT(saveStatus()));
+
+ m_treeWidget = new QTreeWidget(this);
+ m_treeWidget->setFrameStyle(QFrame::NoFrame);
+ m_treeWidget->setRootIsDecorated(false);
+ m_treeWidget->header()->setResizeMode(QHeaderView::ResizeToContents);
+ m_treeWidget->setHeaderLabels(QStringList()
+ << tr("Projects")
+ << tr("Startup")
+ << tr("Path")
+ );
+
+ connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
+ this, SLOT(handleItem(QTreeWidgetItem*, int)), Qt::QueuedConnection);
+ connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem *)),
+ this, SLOT(handleCurrentItemChanged(QTreeWidgetItem*)));
+
+ QWidget *panelsWidget = new QWidget;
+ m_panelsTabWidget = new QTabWidget;
+ m_panelsTabWidget->setDocumentMode(true);
+ QVBoxLayout *panelsLayout = new QVBoxLayout(panelsWidget);
+
+ panelsLayout->setSpacing(0);
+ panelsLayout->setContentsMargins(0, panelsLayout->margin(), 0, 0);
+ panelsLayout->addWidget(m_panelsTabWidget);
+
+ QWidget *dummy = new QWidget;
+ QVBoxLayout *dummyLayout = new QVBoxLayout(dummy);
+ dummyLayout->setMargin(0);
+ dummyLayout->setSpacing(0);
+ dummyLayout->addWidget(new QToolBar(dummy));
+ dummyLayout->addWidget(m_treeWidget);
+
+ QSplitter *splitter = new Core::MiniSplitter;
+ splitter->setOrientation(Qt::Vertical);
+ splitter->addWidget(dummy);
+ splitter->addWidget(panelsWidget);
+
+
+
+ // make sure that the tree treewidget has same size policy as qtabwidget
+ m_treeWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
+ const int treeWidgetMinSize = m_treeWidget->minimumSizeHint().height();
+ splitter->setSizes(QList<int>() << treeWidgetMinSize << splitter->height() - treeWidgetMinSize);
+
+ QVBoxLayout *topLayout = new QVBoxLayout(this);
+ topLayout->setMargin(0);
+ topLayout->setSpacing(0);
+ topLayout->addWidget(splitter);
+
+ connect(m_session, SIGNAL(sessionLoaded()), this, SLOT(updateTreeWidget()));
+ connect(m_session, SIGNAL(startupProjectChanged(ProjectExplorer::Project*)), this, SLOT(updateTreeWidget()));
+ connect(m_session, SIGNAL(projectAdded(ProjectExplorer::Project*)), this, SLOT(updateTreeWidget()));
+ connect(m_session, SIGNAL(projectRemoved(ProjectExplorer::Project*)), this, SLOT(updateTreeWidget()));
+}
+
+ProjectWindow::~ProjectWindow()
+{
+}
+
+void ProjectWindow::restoreStatus()
+{
+ const QVariant lastPanel = m_session->value(QLatin1String("ProjectWindow/Panel"));
+ if (lastPanel.isValid()) {
+ const int index = lastPanel.toInt();
+ if (index < m_panelsTabWidget->count())
+ m_panelsTabWidget->setCurrentIndex(index);
+ }
+}
+
+void ProjectWindow::saveStatus()
+{
+ m_session->setValue(QLatin1String("ProjectWindow/Panel"), m_panelsTabWidget->currentIndex());
+}
+
+void ProjectWindow::showProperties(ProjectExplorer::Project *project, const QModelIndex & /* subIndex */)
+{
+ if (debug)
+ qDebug() << "ProjectWindow - showProperties called";
+
+ // Remove the tabs from the tab widget first
+ while (m_panelsTabWidget->count() > 0)
+ m_panelsTabWidget->removeTab(0);
+
+ while (m_panels.count()) {
+ PropertiesPanel *panel = m_panels.at(0);
+ m_panels.removeOne(panel);
+ delete panel;
+ }
+
+ if (project) {
+ QList<IPanelFactory *> pages =
+ ExtensionSystem::PluginManager::instance()->getObjects<IPanelFactory>();
+ foreach (IPanelFactory *panelFactory, pages) {
+ if (panelFactory->supports(project)) {
+ PropertiesPanel *panel = panelFactory->createPanel(project);
+ if (debug)
+ qDebug() << "ProjectWindow - setting up project properties tab " << panel->name();
+
+ m_panels.append(panel);
+ m_panelsTabWidget->addTab(panel->widget(), panel->name());
+ }
+ }
+ }
+}
+
+void ProjectWindow::updateTreeWidget()
+{
+ // This setFocus prevents a crash, which I (daniel) spend the better part of a day tracking down.
+ // To explain: Consider the case that a widget on either the build or run settings has Focus
+ // Us clearing the m_treewidget will emit a currentItemChanged(0) signal
+ // Which is connected to showProperties
+ // showProperties will now remove the widget that has focus from m_panelsTabWidget, so the treewidget
+ // gets focus, which will in focusIn select the first entry (due to QTreeWidget::clear() implementation,
+ // there are still items in the model) which emits another currentItemChanged() signal
+ // That one runs fully thorough and deletes all widgets, even that one that we are currently removing
+ // from m_panelsTabWidget.
+ // To prevent that, we simply prevent the focus switching....
+ m_treeWidget->setFocus();
+ m_treeWidget->clear();
+
+ foreach(Project *project, m_session->projects()) {
+ const QFileInfo fileInfo(project->file()->fileName());
+
+ QTreeWidgetItem *item = new QTreeWidgetItem();
+ item->setText(0, fileInfo.baseName());
+ item->setIcon(0, Core::FileIconProvider::instance()->icon(fileInfo));
+ item->setText(2, fileInfo.filePath());
+
+ if (project->isApplication()) {
+ bool checked = (m_session->startupProject() == project);
+ item->setCheckState(1, checked ? Qt::Checked : Qt::Unchecked);
+ }
+
+ m_treeWidget->addTopLevelItem(item);
+
+ if (m_projectExplorer->currentProject() == project) {
+ m_treeWidget->setCurrentItem(item, 0, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ }
+ }
+
+
+ if (!m_treeWidget->currentItem()) {
+ if (m_treeWidget->topLevelItemCount() > 0)
+ m_treeWidget->setCurrentItem(m_treeWidget->topLevelItem(0), 0, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ else
+ handleCurrentItemChanged(0);
+ }
+
+
+ // Hack around Qt bug
+ m_treeWidget->viewport()->update();
+}
+
+
+Project *ProjectWindow::findProject(const QString &path) const
+{
+ QList<Project*> projects = m_session->projects();
+ foreach(Project* project, projects) {
+ if (project->file()->fileName() == path) {
+ return project;
+ }
+ }
+ return 0;
+ }
+
+
+void ProjectWindow::handleCurrentItemChanged(QTreeWidgetItem *current)
+{
+ if (current) {
+ QString path = current->text(2);
+ if (Project *project = findProject(path)) {
+
+ m_projectExplorer->setCurrentFile(project, path);
+ showProperties(project, QModelIndex());
+ return;
+ }
+ }
+
+ // we only get here if either current is zero or we didn't find a project for the path
+ m_projectExplorer->setCurrentFile(0, QString());
+ showProperties(0, QModelIndex());
+}
+
+
+void ProjectWindow::handleItem(QTreeWidgetItem *item, int column)
+{
+ if (!item || column != 1) // startup project
+ return;
+
+ const QString path = item->text(2);
+ Project *project = findProject(path);
+
+ if (project && project->isApplication()) {
+ if (!(item->checkState(1) == Qt::Checked)) {
+ item->setCheckState(1, Qt::Checked); // uncheck not supported
+ } else {
+ m_session->setStartupProject(project);
+ }
+ }
+}
diff --git a/src/plugins/projectexplorer/projectwindow.h b/src/plugins/projectexplorer/projectwindow.h
new file mode 100644
index 0000000000..6f402008fb
--- /dev/null
+++ b/src/plugins/projectexplorer/projectwindow.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTWINDOW_H
+#define PROJECTWINDOW_H
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QModelIndex;
+class QTabWidget;
+class QTreeWidget;
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace ProjectExplorer {
+
+class Project;
+class PropertiesPanel;
+class ProjectExplorerPlugin;
+class SessionManager;
+
+namespace Internal {
+
+
+class ProjectWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ProjectWindow(Core::ICore *core, QWidget *parent = 0);
+ ~ProjectWindow();
+
+private slots:
+ void showProperties(ProjectExplorer::Project *project, const QModelIndex &subIndex);
+ void restoreStatus();
+ void saveStatus();
+
+ void updateTreeWidget();
+ void handleItem(QTreeWidgetItem *item, int column);
+ void handleCurrentItemChanged(QTreeWidgetItem *);
+
+private:
+ Core::ICore *m_core;
+ SessionManager *m_session;
+ ProjectExplorerPlugin *m_projectExplorer;
+
+ QTreeWidget* m_treeWidget;
+ QTabWidget *m_panelsTabWidget;
+
+ QList<PropertiesPanel*> m_panels;
+
+ Project *findProject(const QString &path) const;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // PROJECTWINDOW_H
diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp
new file mode 100644
index 0000000000..91cb17690d
--- /dev/null
+++ b/src/plugins/projectexplorer/projectwizardpage.cpp
@@ -0,0 +1,121 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "projectwizardpage.h"
+#include "ui_projectwizardpage.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+
+using namespace ProjectExplorer;
+using namespace Internal;
+
+ProjectWizardPage::ProjectWizardPage(QWidget *parent) :
+ QWizardPage(parent),
+ m_ui(new Ui::WizardPage)
+{
+ m_ui->setupUi(this);
+
+ connect(m_ui->addToProjectCheckBox, SIGNAL(toggled(bool)),
+ m_ui->projectComboBox, SLOT(setEnabled(bool)));
+}
+
+ProjectWizardPage::~ProjectWizardPage()
+{
+ delete m_ui;
+}
+
+void ProjectWizardPage::setProjects(const QStringList &l)
+{
+ m_ui->projectComboBox->clear();
+ m_ui->projectComboBox->addItems(l);
+}
+
+void ProjectWizardPage::setAddToProjectEnabled(bool b)
+{
+ m_ui->projectLabel->setEnabled(b);
+ m_ui->addToProjectLabel->setEnabled(b);
+ m_ui->addToProjectCheckBox->setChecked(b);
+ m_ui->addToProjectCheckBox->setEnabled(b);
+ m_ui->projectComboBox->setEnabled(b);
+}
+
+int ProjectWizardPage::currentProjectIndex() const
+{
+ return m_ui->projectComboBox->currentIndex();
+}
+
+void ProjectWizardPage::setCurrentProjectIndex(int i)
+{
+ m_ui->projectComboBox->setCurrentIndex(i);
+}
+
+bool ProjectWizardPage::addToProject() const
+{
+ return m_ui->addToProjectCheckBox->isChecked();
+}
+
+bool ProjectWizardPage::addToVersionControl() const
+{
+ return m_ui->addToVersionControlCheckBox->isChecked();
+}
+
+void ProjectWizardPage::setAddToVersionControlEnabled(bool b)
+{
+ m_ui->addToVersionControlLabel->setEnabled(b);
+ m_ui->addToVersionControlCheckBox->setChecked(b);
+ m_ui->addToVersionControlCheckBox->setEnabled(b);
+}
+
+void ProjectWizardPage::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void ProjectWizardPage::setFilesDisplay(const QStringList &files)
+{
+ QString fileMessage; {
+ QTextStream str(&fileMessage);
+ str << "<html>Files to be added:<pre>";
+ const QStringList::const_iterator cend = files.constEnd();
+ for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it)
+ str << *it << '\n';
+ str << "</pre>";
+ }
+ m_ui->filesLabel->setText(fileMessage);
+}
diff --git a/src/plugins/projectexplorer/projectwizardpage.h b/src/plugins/projectexplorer/projectwizardpage.h
new file mode 100644
index 0000000000..88e2d43d86
--- /dev/null
+++ b/src/plugins/projectexplorer/projectwizardpage.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTWIZARDPAGE_H
+#define PROJECTWIZARDPAGE_H
+
+#include <QtGui/QWizardPage>
+
+namespace Core {
+ class IVersionControl;
+ class SCCManager;
+ class FileManager;
+}
+
+namespace ProjectExplorer {
+
+class ProjectNode;
+
+namespace Internal {
+
+namespace Ui {
+class WizardPage;
+}
+
+class ProjectWizardPage : public QWizardPage {
+ Q_OBJECT
+ Q_DISABLE_COPY(ProjectWizardPage)
+public:
+ explicit ProjectWizardPage(QWidget *parent = 0);
+ virtual ~ProjectWizardPage();
+
+ void setProjects(const QStringList &);
+ void setCurrentProjectIndex(int);
+ int currentProjectIndex() const;
+
+ void setAddToProjectEnabled(bool b);
+ bool addToProject() const;
+
+ bool addToVersionControl() const;
+ void setAddToVersionControlEnabled(bool b);
+
+ void setFilesDisplay(const QStringList &files);
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private:
+ Ui::WizardPage *m_ui;
+};
+
+}
+}
+
+#endif // PROJECTWIZARDPAGE_H
diff --git a/src/plugins/projectexplorer/projectwizardpage.ui b/src/plugins/projectexplorer/projectwizardpage.ui
new file mode 100644
index 0000000000..bc31f8c49e
--- /dev/null
+++ b/src/plugins/projectexplorer/projectwizardpage.ui
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::WizardPage</class>
+ <widget class="QWizardPage" name="ProjectExplorer::Internal::WizardPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>619</width>
+ <height>414</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>WizardPage</string>
+ </property>
+ <property name="title">
+ <string>Project management</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="addToProjectLabel">
+ <property name="text">
+ <string>&amp;Add to Project</string>
+ </property>
+ <property name="buddy">
+ <cstring>addToProjectCheckBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="addToProjectCheckBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="projectLabel">
+ <property name="text">
+ <string>&amp;Project</string>
+ </property>
+ <property name="buddy">
+ <cstring>projectComboBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="projectComboBox"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="addToVersionControlLabel">
+ <property name="text">
+ <string>Add to &amp;version control</string>
+ </property>
+ <property name="buddy">
+ <cstring>addToVersionControlCheckBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="addToVersionControlCheckBox"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>601</width>
+ <height>157</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="filesLabel">
+ <property name="text">
+ <string>The following files will be added:
+f1
+f2
+</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/projectexplorer/removefiledialog.cpp b/src/plugins/projectexplorer/removefiledialog.cpp
new file mode 100644
index 0000000000..b96a51190a
--- /dev/null
+++ b/src/plugins/projectexplorer/removefiledialog.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "removefiledialog.h"
+#include "ui_removefiledialog.h"
+
+using namespace ProjectExplorer::Internal;
+
+RemoveFileDialog::RemoveFileDialog(const QString &filePath, QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::RemoveFileDialog)
+{
+ m_ui->setupUi(this);
+ m_ui->fileNameLabel->setText(filePath);
+
+ // TODO
+ m_ui->removeVCCheckBox->setVisible(false);
+}
+
+RemoveFileDialog::~RemoveFileDialog()
+{
+ delete m_ui;
+}
+
+bool RemoveFileDialog::isDeleteFileChecked() const
+{
+ return m_ui->deleteFileCheckBox->isChecked();
+}
+
+void RemoveFileDialog::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/plugins/projectexplorer/removefiledialog.h b/src/plugins/projectexplorer/removefiledialog.h
new file mode 100644
index 0000000000..a3b608f428
--- /dev/null
+++ b/src/plugins/projectexplorer/removefiledialog.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef REMOVEFILEDIALOG_H
+#define REMOVEFILEDIALOG_H
+
+#include <QtGui/QDialog>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+namespace Ui {
+ class RemoveFileDialog;
+}
+
+class RemoveFileDialog : public QDialog {
+ Q_OBJECT
+ Q_DISABLE_COPY(RemoveFileDialog)
+public:
+ explicit RemoveFileDialog(const QString &filePath, QWidget *parent = 0);
+ virtual ~RemoveFileDialog();
+
+ bool isDeleteFileChecked() const;
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private:
+ Ui::RemoveFileDialog *m_ui;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // REMOVEFILEDIALOG_H
diff --git a/src/plugins/projectexplorer/removefiledialog.ui b/src/plugins/projectexplorer/removefiledialog.ui
new file mode 100644
index 0000000000..6f5ecee1d4
--- /dev/null
+++ b/src/plugins/projectexplorer/removefiledialog.ui
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::RemoveFileDialog</class>
+ <widget class="QDialog" name="ProjectExplorer::Internal::RemoveFileDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>237</width>
+ <height>171</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Remove File</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="fileToDeleteLabel">
+ <property name="text">
+ <string>File to delete:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="fileNameLabel">
+ <property name="font">
+ <font>
+ <family>Courier New</family>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">placeholder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="deleteFileCheckBox">
+ <property name="text">
+ <string>&amp;Delete file permanently</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="removeVCCheckBox">
+ <property name="text">
+ <string>&amp;Remove from Version Control</string>
+ </property>
+ </widget>
+ </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>
+ <resources>
+ <include location="../../libs/cplusplus/cplusplus.qrc"/>
+ <include location="../../libs/extensionsystem/pluginview.qrc"/>
+ <include location="../bookmarks/bookmarks.qrc"/>
+ <include location="../coreplugin/core.qrc"/>
+ <include location="../coreplugin/fancyactionbar.qrc"/>
+ <include location="../cppeditor/cppeditor.qrc"/>
+ <include location="../cpptools/cpptools.qrc"/>
+ <include location="../designer/designer.qrc"/>
+ <include location="../find/find.qrc"/>
+ <include location="../gdbdebugger/gdbdebugger.qrc"/>
+ <include location="../help/help.qrc"/>
+ <include location="../perforce/perforce.qrc"/>
+ <include location="projectexplorer.qrc"/>
+ <include location="../../../shared/proparser/proparser.qrc"/>
+ <include location="../qt4projectmanager/qt4projectmanager.qrc"/>
+ <include location="../qt4projectmanager/wizards/wizards.qrc"/>
+ <include location="../quickopen/quickopen.qrc"/>
+ <include location="../resourceeditor/resourceeditor.qrc"/>
+ <include location="../texteditor/texteditor.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProjectExplorer::Internal::RemoveFileDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProjectExplorer::Internal::RemoveFileDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
new file mode 100644
index 0000000000..612fc64bc3
--- /dev/null
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "runconfiguration.h"
+#include "project.h"
+
+#include <QtCore/QTimer>
+
+#ifdef Q_OS_MAC
+#include <Carbon/Carbon.h>
+#endif
+
+#include <QtDebug>
+
+using namespace ProjectExplorer;
+
+// RunConfiguration
+RunConfiguration::RunConfiguration(Project *project)
+ : m_project(project)
+{
+}
+
+RunConfiguration::~RunConfiguration()
+{
+}
+
+Project *RunConfiguration::project() const
+{
+ return m_project.data();
+}
+
+QString RunConfiguration::name() const
+{
+ return m_name;
+}
+
+void RunConfiguration::setName(const QString &name)
+{
+ m_name = name;
+ emit nameChanged();
+}
+
+void RunConfiguration::save(PersistentSettingsWriter &writer) const
+{
+ writer.saveValue("RunConfiguration.name", m_name);
+}
+
+void RunConfiguration::restore(const PersistentSettingsReader &reader)
+{
+ QVariant var = reader.restoreValue("RunConfiguration.name");
+ if (var.isValid() && !var.toString().isEmpty())
+ m_name = var.toString();
+}
+
+
+IRunConfigurationFactory::IRunConfigurationFactory()
+{
+}
+
+IRunConfigurationFactory::~IRunConfigurationFactory()
+{
+}
+
+IRunConfigurationRunner::IRunConfigurationRunner()
+{
+}
+
+IRunConfigurationRunner::~IRunConfigurationRunner()
+{
+}
+
+RunControl::RunControl(QSharedPointer<RunConfiguration> runConfiguration)
+ : m_runConfiguration(runConfiguration)
+{
+}
+
+QSharedPointer<RunConfiguration> RunControl::runConfiguration()
+{
+ return m_runConfiguration;
+}
+
+RunControl::~RunControl()
+{
+}
+
+void RunControl::bringApplicationToForeground(qint64 pid)
+{
+#ifdef Q_OS_MAC
+ m_internalPid = pid;
+ m_foregroundCount = 0;
+ bringApplicationToForegroundInternal();
+#endif
+}
+
+void RunControl::bringApplicationToForegroundInternal()
+{
+#ifdef Q_OS_MAC
+ ProcessSerialNumber psn;
+ GetProcessForPID(m_internalPid, &psn);
+ if (SetFrontProcess(&psn) == procNotFound && m_foregroundCount < 15) {
+ // somehow the mac/carbon api says
+ // "-600 no eligible process with specified process id"
+ // if we call SetFrontProcess too early
+ ++m_foregroundCount;
+ QTimer::singleShot(200, this, SLOT(bringApplicationToForegroundInternal()));
+ return;
+ }
+#endif
+}
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
new file mode 100644
index 0000000000..67b9299ff0
--- /dev/null
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RUNCONFIGURATION_H
+#define RUNCONFIGURATION_H
+
+#include "projectexplorer_export.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMetaType>
+#include <QtCore/QPointer>
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+
+class Project;
+class PersistentSettingsReader;
+class PersistentSettingsWriter;
+
+class RunControl;
+
+/* Base class for a run configuration. A run configuration specifies how a
+ * project should be run, while the runner (see below) does the actual running.
+ *
+ * Note that all RunControls and the project hold a shared pointer to the RunConfiguration.
+ * That is the lifetime of the RunConfiguration might exceed the life of the project.
+ * The user might still have a RunControl running (or output tab of that RunControl open)
+ * and yet unloaded the project.
+ * Also a RunConfiguration might be already removed from the list of RunConfigurations
+ * for a project, but stil be runnable via the output tab.
+
+*/
+class PROJECTEXPLORER_EXPORT RunConfiguration : public QObject
+{
+ Q_OBJECT
+public:
+ RunConfiguration(Project *project);
+ virtual ~RunConfiguration();
+ Project *project() const;
+
+ // The type of this RunConfiguration, e.g. "ProjectExplorer.ApplicationRunConfiguration"
+ virtual QString type() const = 0;
+ // Name shown to the user
+ QString name() const;
+ void setName(const QString &name);
+
+ // Returns the widget used to configure this run configuration. Ownership is transferred to the caller
+ virtual QWidget *configurationWidget() = 0;
+
+ virtual void save(PersistentSettingsWriter &writer) const;
+ virtual void restore(const PersistentSettingsReader &reader);
+signals:
+ void nameChanged();
+private:
+ QPointer<Project> m_project;
+ QString m_name;
+};
+
+/* The run configuration factory is used for restoring run configurations from
+ * settings. And used to create new runconfigurations in the "Run Settings" Dialog.
+ * For the first case bool canCreate(const QString &type) and
+ * QSharedPointer<RunConfiguration> create(Project *project, QString type) are used.
+ * For the second type the functions QStringList canCreate(Project *pro) and
+ * QString nameForType(const QString&) are used to generate a list of creatable
+ * RunConfigurations, and create(..) is used to create it.
+ */
+class PROJECTEXPLORER_EXPORT IRunConfigurationFactory : public QObject
+{
+ Q_OBJECT
+public:
+ IRunConfigurationFactory();
+ virtual ~IRunConfigurationFactory();
+ // used to recreate the runConfigurations when restoring settings
+ virtual bool canCreate(const QString &type) const = 0;
+ // used to show the list of possible additons to a project, returns a list of types
+ virtual QStringList canCreate(Project *pro) const = 0;
+ // used to translate the types to names to display to the user
+ virtual QString nameForType(const QString &type) const = 0;
+ virtual QSharedPointer<RunConfiguration> create(Project *project, const QString &type) = 0;
+
+};
+
+class PROJECTEXPLORER_EXPORT IRunConfigurationRunner : public QObject
+{
+ Q_OBJECT
+public:
+ IRunConfigurationRunner();
+ virtual ~IRunConfigurationRunner();
+ virtual bool canRun(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode) = 0;
+ virtual RunControl* run(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode) = 0;
+
+ virtual QString displayName() const = 0;
+
+ // Returns the widget used to configure this runner. Ownership is transferred to the caller
+ virtual QWidget *configurationWidget(QSharedPointer<RunConfiguration> runConfiguration) = 0;
+};
+
+/* Each instance of this class represents one item that is run.
+ */
+class PROJECTEXPLORER_EXPORT RunControl : public QObject {
+ Q_OBJECT
+public:
+ RunControl(QSharedPointer<RunConfiguration> runConfiguration);
+ virtual ~RunControl();
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual bool isRunning() const = 0;
+ QSharedPointer<RunConfiguration> runConfiguration();
+signals:
+ void addToOutputWindow(RunControl *, const QString &line);
+ void error(RunControl *, const QString &error);
+ void started();
+ void finished();
+public slots:
+ void bringApplicationToForeground(qint64 pid);
+private slots:
+ void bringApplicationToForegroundInternal();
+
+private:
+ QSharedPointer<RunConfiguration> m_runConfiguration;
+
+#ifdef Q_OS_MAC
+ //these two are used to bring apps in the foreground on Mac
+ qint64 m_internalPid;
+ int m_foregroundCount;
+#endif
+};
+
+} // namespace ProjectExplorer
+
+// Allow a RunConfiguration to be stored in a QVariant
+Q_DECLARE_METATYPE(ProjectExplorer::RunConfiguration*)
+
+#endif // RUNCONFIGURATION_H
diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.cpp b/src/plugins/projectexplorer/runsettingspropertiespage.cpp
new file mode 100644
index 0000000000..607e8b8cb9
--- /dev/null
+++ b/src/plugins/projectexplorer/runsettingspropertiespage.cpp
@@ -0,0 +1,292 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "runsettingspropertiespage.h"
+#include "runconfiguration.h"
+
+#include "ui_runsettingspropertiespage.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QDebug>
+#include <QtCore/QPair>
+
+namespace ProjectExplorer {
+namespace Internal {
+struct FactoryAndType
+{
+ ProjectExplorer::IRunConfigurationFactory *factory;
+ QString type;
+};
+} // namespace
+} // namespace
+
+Q_DECLARE_METATYPE(ProjectExplorer::Internal::FactoryAndType);
+
+namespace ProjectExplorer {
+namespace Internal {
+
+/*! A model to represent the run configurations of a project. */
+class RunConfigurationsModel : public QAbstractListModel
+{
+public:
+ RunConfigurationsModel(QObject *parent = 0)
+ : QAbstractListModel(parent)
+ {}
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ void setRunConfigurations(const QList<QSharedPointer<RunConfiguration> > &runConfigurations);
+ void nameChanged(RunConfiguration *rc);
+
+private:
+ QList<QSharedPointer<RunConfiguration> > m_runConfigurations;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+using ExtensionSystem::PluginManager;
+
+///
+/// RunSettingsPanelFactory
+///
+
+bool RunSettingsPanelFactory::supports(Project * /* project */)
+{
+ return true;
+}
+
+PropertiesPanel *RunSettingsPanelFactory::createPanel(Project *project)
+{
+ return new RunSettingsPanel(project);
+}
+
+///
+/// RunSettingsPanel
+///
+
+RunSettingsPanel::RunSettingsPanel(Project *project)
+ : PropertiesPanel(),
+ m_widget(new RunSettingsWidget(project))
+{
+}
+
+RunSettingsPanel::~RunSettingsPanel()
+{
+ delete m_widget;
+}
+
+QString RunSettingsPanel::name() const
+{
+ return tr("Run Settings");
+}
+
+QWidget *RunSettingsPanel::widget()
+{
+ return m_widget;
+}
+
+///
+/// RunConfigurationsModel
+///
+
+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::nameChanged(RunConfiguration *rc)
+{
+ for (int i = 0; i<m_runConfigurations.size(); ++i) {
+ if (m_runConfigurations.at(i).data() == 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()) {
+ QSharedPointer<RunConfiguration> c = m_runConfigurations.at(row);
+ return c->name();
+ }
+ }
+
+ return QVariant();
+}
+
+void RunConfigurationsModel::setRunConfigurations(const QList<QSharedPointer<RunConfiguration> > &runConfigurations)
+{
+ m_runConfigurations = runConfigurations;
+ reset();
+}
+
+
+///
+/// RunSettingsWidget
+///
+
+RunSettingsWidget::RunSettingsWidget(Project *project)
+ : m_project(project)
+ , m_runConfigurationsModel(new RunConfigurationsModel(this))
+ , m_runConfigurationWidget(0)
+{
+ m_ui = new Ui::RunSettingsPropertiesPage;
+ m_ui->setupUi(this);
+ m_addMenu = new QMenu(m_ui->addToolButton);
+ m_ui->addToolButton->setIcon(QIcon(":/qworkbench/images/plus.png"));
+ m_ui->addToolButton->setMenu(m_addMenu);
+ m_ui->removeToolButton->setIcon(QIcon(":/qworkbench/images/minus.png"));
+ m_ui->runConfigurationCombo->setModel(m_runConfigurationsModel);
+
+ connect(m_addMenu, SIGNAL(aboutToShow()),
+ this, SLOT(aboutToShowAddMenu()));
+ connect(m_ui->runConfigurationCombo, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(activateRunConfiguration(int)));
+ connect(m_ui->removeToolButton, SIGNAL(clicked(bool)),
+ this, SLOT(removeRunConfiguration()));
+
+ initRunConfigurationComboBox();
+ const QList<QSharedPointer<RunConfiguration> > runConfigurations = m_project->runConfigurations();
+ for (int i=0; i<runConfigurations.size(); ++i) {
+ connect(runConfigurations.at(i).data(), SIGNAL(nameChanged()),
+ this, SLOT(nameChanged()));
+ }
+
+ // TODO: Add support for custom runner configuration widgets once we have some
+ /*
+ QList<IRunConfigurationRunner *> runners = PluginManager::instance()->getObjects<IRunConfigurationRunner>();
+ foreach (IRunConfigurationRunner * runner, runners) {
+ if (runner->canRun(activeRunConfiguration))
+ m_ui->layout->addWidget(runner->configurationWidget(activeRunConfiguration));
+ }
+ */
+}
+
+RunSettingsWidget::~RunSettingsWidget()
+{
+ delete m_ui;
+}
+
+void RunSettingsWidget::aboutToShowAddMenu()
+{
+ m_addMenu->clear();
+ QList<IRunConfigurationFactory *> factories = ExtensionSystem::PluginManager::instance()->getObjects<IRunConfigurationFactory>();
+ foreach (IRunConfigurationFactory * factory, factories) {
+ QStringList types = factory->canCreate(m_project);
+ foreach (const QString &type, types) {
+ QAction *action = m_addMenu->addAction(factory->nameForType(type));;
+ FactoryAndType fat;
+ fat.factory = factory;
+ fat.type = type;
+ QVariant v;
+ v.setValue(fat);
+ action->setData(v);
+ connect(action, SIGNAL(triggered()),
+ this, SLOT(addRunConfiguration()));
+ }
+ }
+}
+
+void RunSettingsWidget::addRunConfiguration()
+{
+ QAction *act = qobject_cast<QAction *>(sender());
+ if (!act)
+ return;
+ FactoryAndType fat = act->data().value<FactoryAndType>();
+ QSharedPointer<RunConfiguration> newRC = fat.factory->create(m_project, fat.type);
+ if (!newRC)
+ return;
+ m_project->addRunConfiguration(newRC);
+ m_project->setActiveRunConfiguration(newRC);
+ initRunConfigurationComboBox();
+ connect(newRC.data(), SIGNAL(nameChanged()),
+ this, SLOT(nameChanged()));
+}
+
+void RunSettingsWidget::removeRunConfiguration()
+{
+ int index = m_ui->runConfigurationCombo->currentIndex();
+ QSharedPointer<RunConfiguration> rc = m_project->runConfigurations().at(index);
+ disconnect(rc.data(), SIGNAL(nameChanged()),
+ this, SLOT(nameChanged()));
+ m_project->removeRunConfiguration(rc);
+ initRunConfigurationComboBox();
+}
+
+void RunSettingsWidget::initRunConfigurationComboBox()
+{
+ const QList<QSharedPointer<RunConfiguration> > runConfigurations = m_project->runConfigurations();
+ QSharedPointer<RunConfiguration> activeRunConfiguration = m_project->activeRunConfiguration();
+ m_runConfigurationsModel->setRunConfigurations(runConfigurations);
+ // Make sure the active run configuration is selected in the combo
+ for (int i = 0; i < runConfigurations.size(); ++i) {
+ if (runConfigurations.at(i) == activeRunConfiguration)
+ m_ui->runConfigurationCombo->setCurrentIndex(i);
+ }
+ m_ui->removeToolButton->setEnabled(runConfigurations.size() > 1);
+}
+
+void RunSettingsWidget::activateRunConfiguration(int index)
+{
+ Q_ASSERT(m_project);
+ const QList<QSharedPointer<RunConfiguration> > runConfigurations = m_project->runConfigurations();
+ Q_ASSERT(index < runConfigurations.size());
+ QSharedPointer<RunConfiguration> selectedRunConfiguration = runConfigurations.at(index);
+
+ // Change the active run configuration of the project
+ m_project->setActiveRunConfiguration(selectedRunConfiguration);
+
+ // Update the run configuration configuration widget
+ delete m_runConfigurationWidget;
+ m_runConfigurationWidget = selectedRunConfiguration->configurationWidget();
+ m_ui->groupBox->layout()->addWidget(m_runConfigurationWidget);
+}
+
+void RunSettingsWidget::nameChanged()
+{
+ RunConfiguration *rc = qobject_cast<RunConfiguration *>(sender());
+ m_runConfigurationsModel->nameChanged(rc);
+}
diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.h b/src/plugins/projectexplorer/runsettingspropertiespage.h
new file mode 100644
index 0000000000..50ed3f4978
--- /dev/null
+++ b/src/plugins/projectexplorer/runsettingspropertiespage.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RUNSETTINGSPROPERTIESPAGE_H
+#define RUNSETTINGSPROPERTIESPAGE_H
+
+#include "iprojectproperties.h"
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+namespace Internal {
+
+namespace Ui {
+class RunSettingsPropertiesPage;
+}
+
+class RunConfigurationsModel;
+class RunSettingsWidget;
+
+class RunSettingsPanelFactory : public IPanelFactory
+{
+public:
+ virtual bool supports(Project *project);
+ PropertiesPanel *createPanel(Project *project);
+};
+
+class RunSettingsPanel : public PropertiesPanel
+{
+ Q_OBJECT
+public:
+ RunSettingsPanel(Project *project);
+ ~RunSettingsPanel();
+
+ QString name() const;
+ QWidget *widget();
+private:
+ RunSettingsWidget *m_widget;
+};
+
+class RunSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ RunSettingsWidget(Project *project);
+ ~RunSettingsWidget();
+
+private slots:
+ void activateRunConfiguration(int index);
+ void aboutToShowAddMenu();
+ void addRunConfiguration();
+ void removeRunConfiguration();
+ void nameChanged();
+
+private:
+ void initRunConfigurationComboBox();
+ Project *m_project;
+ RunConfigurationsModel *m_runConfigurationsModel;
+ Ui::RunSettingsPropertiesPage *m_ui;
+ QWidget *m_runConfigurationWidget;
+ QMenu *m_addMenu;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // RUNSETTINGSPROPERTIESPAGE_H
diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.ui b/src/plugins/projectexplorer/runsettingspropertiespage.ui
new file mode 100644
index 0000000000..a973085873
--- /dev/null
+++ b/src/plugins/projectexplorer/runsettingspropertiespage.ui
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::RunSettingsPropertiesPage</class>
+ <widget class="QWidget" name="ProjectExplorer::Internal::RunSettingsPropertiesPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>521</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="layout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Run &amp;configuration:</string>
+ </property>
+ <property name="buddy">
+ <cstring>runConfigurationCombo</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="runConfigurationCombo">
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToMinimumContentsLength</enum>
+ </property>
+ <property name="minimumContentsLength">
+ <number>30</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="addToolButton">
+ <property name="text">
+ <string>+</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="removeToolButton">
+ <property name="text">
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Settings</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2"/>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/projectexplorer/scriptwrappers.cpp b/src/plugins/projectexplorer/scriptwrappers.cpp
new file mode 100644
index 0000000000..307fb6e650
--- /dev/null
+++ b/src/plugins/projectexplorer/scriptwrappers.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "scriptwrappers.h"
+
diff --git a/src/plugins/projectexplorer/scriptwrappers.h b/src/plugins/projectexplorer/scriptwrappers.h
new file mode 100644
index 0000000000..4eb59f6ec5
--- /dev/null
+++ b/src/plugins/projectexplorer/scriptwrappers.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROJECTEXPLORER_SCRIPT_WRAPPER_H
+#define PROJECTEXPLORER_SCRIPT_WRAPPER_H
+
+#endif
diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp
new file mode 100644
index 0000000000..d0e27317e3
--- /dev/null
+++ b/src/plugins/projectexplorer/session.cpp
@@ -0,0 +1,1109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "dependenciesdialog.h"
+#include "project.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+#include "nodesvisitor.h"
+#include "session.h"
+#include "editorconfiguration.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/imode.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <coreplugin/modemanager.h>
+#include <utils/listutils.h>
+
+#include <texteditor/itexteditor.h>
+
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QFuture>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+
+namespace {
+ bool debug = false;
+}
+
+/* SessionFile definitions */
+namespace ProjectExplorer {
+namespace Internal {
+
+class SessionFile
+ : public Core::IFile
+{
+ Q_OBJECT
+
+public:
+ SessionFile(Core::ICore *core);
+
+ bool load(const QString &fileName);
+ bool save(const QString &fileName = QString());
+
+ 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;
+
+ void modified(Core::IFile::ReloadBehavior *behavior);
+
+public slots:
+ void sessionLoadingProgress();
+
+
+private:
+ const QString m_mimeType;
+ Core::ICore *m_core;
+
+ QString m_fileName;
+ QList<Project *> m_projects;
+ Project *m_startupProject;
+ QMap<QString, QStringList> m_depMap;
+
+ QMap<QString, QVariant> m_values;
+
+ QFutureInterface<void> future;
+ friend class ProjectExplorer::SessionManager;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+using namespace ProjectExplorer;
+using Internal::SessionFile;
+using Internal::DependenciesDialog;
+
+
+void SessionFile::sessionLoadingProgress()
+{
+ future.setProgressValue(future.progressValue() + 1);
+ QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+}
+
+SessionFile::SessionFile(Core::ICore *core) :
+ m_mimeType(QLatin1String(ProjectExplorer::Constants::SESSIONFILE_MIMETYPE)),
+ m_core(core),
+ m_startupProject(0)
+{
+}
+
+QString SessionFile::mimeType() const
+{
+ return m_mimeType;
+}
+
+bool SessionFile::load(const QString &fileName)
+{
+ Q_ASSERT(!fileName.isEmpty());
+
+ if (debug)
+ qDebug() << "SessionFile::load " << fileName;
+
+
+
+ m_fileName = fileName;
+
+ // NPE: Load the session in the background?
+ // NPE: Let FileManager monitor filename
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+
+
+ PersistentSettingsReader reader;
+ if (!reader.load(m_fileName)) {
+ qWarning() << "SessionManager::load failed!" << fileName;
+ QApplication::restoreOverrideCursor();
+ return false;
+ }
+
+ m_core->progressManager()->addTask(future.future(), tr("Session"),
+ QLatin1String("ProjectExplorer.SessionFile.Load"),
+ Core::ProgressManagerInterface::CloseOnSuccess);
+
+ const QStringList &keys = reader.restoreValue(QLatin1String("valueKeys")).toStringList();
+ foreach (const QString &key, keys) {
+ QVariant value = reader.restoreValue("value-" + key);
+ m_values.insert(key, value);
+ }
+
+ QStringList fileList =
+ reader.restoreValue(QLatin1String("ProjectList")).toStringList();
+ QString configDir = QFileInfo(m_core->settings()->fileName()).path();
+ QMutableStringListIterator it(fileList);
+ while (it.hasNext()) {
+ const QString &file = it.next();
+ if (QFileInfo(file).isRelative()) {
+ // We used to write relative paths into the session file
+ // relative to the session files, and those were stored in the
+ // config dir
+ it.setValue(configDir + "/" + file);
+ }
+ }
+
+
+ int openEditorsCount = reader.restoreValue(QLatin1String("OpenEditors")).toInt();
+
+ future.setProgressRange(0, fileList.count() + openEditorsCount + 2);
+ future.setProgressValue(1);
+
+ // indirectly adds projects to session
+ if (!fileList.isEmpty())
+ ProjectExplorerPlugin::instance()->openProjects(fileList);
+
+ sessionLoadingProgress();
+
+ // convert the relative paths in the dependency map to absolute paths
+ QMap<QString, QVariant> depMap = reader.restoreValue(QLatin1String("ProjectDependencies")).toMap();
+ QMap<QString, QVariant>::const_iterator i = depMap.constBegin();
+ while (i != depMap.constEnd()) {
+ const QString &key = i.key();
+ QStringList values;
+ foreach (const QString &value, i.value().toStringList()) {
+ values << value;
+ }
+ m_depMap.insert(key, values);
+ ++i;
+ }
+
+ // find and set the startup project
+ const QString startupProject = reader.restoreValue(QLatin1String("StartupProject")).toString();
+ if (!startupProject.isEmpty()) {
+ const QString startupProjectPath = startupProject;
+ foreach (Project *pro, m_projects) {
+ if (QDir::cleanPath(pro->file()->fileName()) == startupProjectPath) {
+ m_startupProject = pro;
+ break;
+ }
+ }
+ if (!m_startupProject)
+ qWarning() << "Could not find startup project" << startupProjectPath;
+ }
+
+
+ const QVariant &editorsettings = reader.restoreValue(QLatin1String("EditorSettings"));
+ if (editorsettings.isValid()) {
+ connect(m_core->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
+ this, SLOT(sessionLoadingProgress()));
+ m_core->editorManager()->restoreState(
+ QByteArray::fromBase64(editorsettings.toByteArray()));
+ disconnect(m_core->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
+ this, SLOT(sessionLoadingProgress()));
+ }
+
+ if (debug)
+ qDebug() << "SessionFile::load finished" << fileName;
+
+
+ future.reportFinished();
+ QApplication::restoreOverrideCursor();
+ return true;
+}
+
+bool SessionFile::save(const QString &fileName)
+{
+ if (!fileName.isEmpty())
+ m_fileName = fileName;
+
+ Q_ASSERT(!m_fileName.isEmpty());
+
+ if (debug)
+ qDebug() << "SessionFile - saving " << m_fileName;
+
+ PersistentSettingsWriter writer;
+
+ // save the startup project
+ if (m_startupProject) {
+ writer.saveValue(QLatin1String("StartupProject"), m_startupProject->file()->fileName());
+ }
+
+ QStringList projectFiles;
+ foreach (Project *pro, m_projects) {
+ projectFiles << pro->file()->fileName();
+ }
+
+ writer.saveValue(QLatin1String("ProjectList"), projectFiles);
+
+ QMap<QString, QVariant> depMap;
+ QMap<QString, QStringList>::const_iterator i = m_depMap.constBegin();
+ while (i != m_depMap.constEnd()) {
+ QString key = i.key();
+ QStringList values;
+ foreach (const QString &value, i.value()) {
+ values << value;
+ }
+ depMap.insert(key, values);
+ ++i;
+ }
+ writer.saveValue(QLatin1String("ProjectDependencies"), QVariant(depMap));
+
+ writer.saveValue(QLatin1String("OpenEditors"),
+ m_core->editorManager()->openedEditors().count());
+ writer.saveValue(QLatin1String("EditorSettings"),
+ m_core->editorManager()->saveState().toBase64());
+
+ QMap<QString, QVariant>::const_iterator it, end;
+ end = m_values.constEnd();
+ QStringList keys;
+ for (it = m_values.constBegin(); it != end; ++it) {
+ writer.saveValue("value-" + it.key(), it.value());
+ keys << it.key();
+ }
+
+ writer.saveValue("valueKeys", keys);
+
+
+ if (writer.save(m_fileName, "QtCreatorSession"))
+ return true;
+
+ return false;
+}
+
+QString SessionFile::fileName() const
+{
+ return m_fileName;
+}
+
+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;
+}
+
+void SessionFile::modified(Core::IFile::ReloadBehavior *)
+{
+}
+
+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->name();
+
+ return tr("Untitled", "default file name to display");
+}
+
+Internal::SessionNodeImpl::SessionNodeImpl(SessionManager *manager)
+ : ProjectExplorer::SessionNode(manager->file()->fileName(), manager)
+{
+ setFileName("session");
+}
+
+void Internal::SessionNodeImpl::addProjectNode(ProjectNode *projectNode)
+{
+ addProjectNodes(QList<ProjectNode*>() << projectNode);
+}
+
+void Internal::SessionNodeImpl::removeProjectNode(ProjectNode *projectNode)
+{
+ removeProjectNodes(QList<ProjectNode*>() << projectNode);
+}
+
+void Internal::SessionNodeImpl::setFileName(const QString &fileName)
+{
+ setPath(fileName);
+ setFolderName(fileName);
+}
+
+/* --------------------------------- */
+
+SessionManager::SessionManager(Core::ICore *core, QObject *parent)
+ : QObject(parent),
+ m_core(core),
+ m_file(new SessionFile(core)),
+ m_sessionNode(new Internal::SessionNodeImpl(this))
+{
+ // Create qtcreator dir if it doesn't yet exist
+ QString configDir = QFileInfo(m_core->settings()->fileName()).path();
+
+ QFileInfo fi(configDir + "/qtcreator/");
+ if (!fi.exists()) {
+ QDir dir;
+ dir.mkpath(configDir + "/qtcreator");
+
+ // Move sessions to that directory
+ foreach(const QString &session, sessions()) {
+ QFile file(configDir + "/" + session + ".qws");
+ if (file.exists())
+ if(file.copy(configDir + "/qtcreator/" + session + ".qws"))
+ file.remove();
+ }
+ }
+
+ connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*)),
+ this, SLOT(saveActiveMode(Core::IMode*)));
+ connect(core->editorManager(), SIGNAL(editorCreated(Core::IEditor *, QString)),
+ this, SLOT(setEditorCodec(Core::IEditor *, QString)));
+ connect(ProjectExplorerPlugin::instance(), SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
+ this, SLOT(updateWindowTitle()));
+
+ }
+
+SessionManager::~SessionManager()
+{
+ delete m_file;
+ emit sessionUnloaded();
+}
+
+
+bool SessionManager::isDefaultVirgin() const
+{
+ return (isDefaultSession(m_sessionName)
+ && projects().isEmpty()
+ && m_core->editorManager()->openedEditors().isEmpty());
+}
+
+
+bool SessionManager::isDefaultSession(const QString &session) const
+{
+ return (session == QLatin1String("default"));
+}
+
+
+void SessionManager::saveActiveMode(Core::IMode *mode)
+{
+ setValue(QLatin1String("ActiveMode"), mode->uniqueModeName());
+}
+
+void SessionManager::clearProjectFileCache()
+{
+ // If triggered by the fileListChanged signal of one project
+ // only invalidate cache for this project
+ Project *pro = qobject_cast<Project*>(sender());
+ if (pro)
+ m_projectFileCache.remove(pro);
+ else
+ m_projectFileCache.clear();
+}
+
+bool SessionManager::recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const
+{
+ if (newDep == checkDep)
+ return false;
+
+ foreach (const QString &dependency, m_file->m_depMap.value(checkDep)) {
+ if (!recursiveDependencyCheck(newDep, dependency))
+ return false;
+ }
+
+ return true;
+}
+
+bool SessionManager::hasDependency(Project *project, Project *depProject) const
+{
+ const QString &proName = project->file()->fileName();
+ const QString &depName = depProject->file()->fileName();
+
+ const QStringList &proDeps = m_file->m_depMap.value(proName);
+ return proDeps.contains(depName);
+}
+
+bool SessionManager::canAddDependency(Project *project, Project *depProject) const
+{
+ const QString &newDep = project->file()->fileName();
+ const QString &checkDep = depProject->file()->fileName();
+
+ return recursiveDependencyCheck(newDep, checkDep);
+}
+
+bool SessionManager::addDependency(Project *project, Project *depProject)
+{
+ const QString &proName = project->file()->fileName();
+ const QString &depName = depProject->file()->fileName();
+
+ // check if this dependency is valid
+ if (!recursiveDependencyCheck(proName, depName))
+ return false;
+
+ QStringList proDeps = m_file->m_depMap.value(proName);
+ if (!proDeps.contains(depName)) {
+ proDeps.append(depName);
+ m_file->m_depMap[proName] = proDeps;
+ }
+
+ return true;
+}
+
+void SessionManager::setStartupProject(Project *startupProject)
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << (startupProject ? startupProject->name() : "0");
+
+ if (startupProject) {
+ Q_ASSERT(m_file->m_projects.contains(startupProject));
+ }
+
+ m_file->m_startupProject = startupProject;
+ emit startupProjectChanged(startupProject);
+}
+
+Project *SessionManager::startupProject() const
+{
+ return m_file->m_startupProject;
+}
+
+void SessionManager::removeDependency(Project *project,
+ Project *depProject)
+{
+ const QString &proName = project->file()->fileName();
+ const QString &depName = depProject->file()->fileName();
+
+ QStringList proDeps = m_file->m_depMap.value(proName);
+ proDeps.removeAll(depName);
+ if (proDeps.isEmpty()) {
+ m_file->m_depMap.remove(proName);
+ } else {
+ m_file->m_depMap[proName] = proDeps;
+ }
+}
+
+void SessionManager::addProject(Project *project)
+{
+ addProjects(QList<Project*>() << project);
+}
+
+void SessionManager::addProjects(const QList<Project*> &projects)
+{
+ QList<Project*> clearedList;
+ foreach (Project *pro, projects) {
+ if (!m_file->m_projects.contains(pro)) {
+ clearedList.append(pro);
+ m_file->m_projects.append(pro);
+ m_sessionNode->addProjectNode(pro->rootProjectNode());
+
+ connect(pro, SIGNAL(fileListChanged()),
+ this, SLOT(clearProjectFileCache()));
+
+ if (debug)
+ qDebug() << "SessionManager - adding project " << pro->name();
+ }
+ }
+
+ foreach (Project *pro, clearedList) {
+ emit projectAdded(pro);
+ }
+
+ if (clearedList.count() == 1)
+ emit singleProjectAdded(clearedList.first());
+
+ // maybe we have a new startup project?
+ if (!startupProject())
+ if (Project *newStartupProject = defaultStartupProject())
+ setStartupProject(newStartupProject);
+}
+
+void SessionManager::removeProject(Project *project)
+{
+ if (project == 0) {
+ qDebug() << "SessionManager::removeProject(0) ... THIS SHOULD NOT HAPPEN";
+ return;
+ }
+ removeProjects(QList<Project*>() << project);
+}
+
+bool SessionManager::createImpl(const QString &fileName)
+{
+ Q_ASSERT(!fileName.isEmpty());
+
+ if (debug)
+ qDebug() << "SessionManager - creating new session " << fileName << " ...";
+
+ bool success = true;
+
+ if (!m_file->fileName().isEmpty()) {
+ if (!save() || !clear()) {
+ success = false;
+ }
+ }
+
+ if (success) {
+ delete m_file;
+ emit sessionUnloaded();
+ m_file = new SessionFile(m_core);
+ m_file->setFileName(fileName);
+ setStartupProject(defaultStartupProject());
+ }
+
+ if (debug)
+ qDebug() << "SessionManager - creating new session returns " << success;
+
+ if (success)
+ emit sessionLoaded();
+
+ return success;
+}
+
+bool SessionManager::loadImpl(const QString &fileName)
+{
+ Q_ASSERT(!fileName.isEmpty());
+
+ if (debug)
+ qDebug() << "SessionManager - loading session " << fileName << " ...";
+
+ bool success = true;
+
+ if (!m_file->fileName().isEmpty()) {
+
+ if (isDefaultVirgin()) {
+ // do not save initial and virgin default session
+ } else if (!save() || !clear()) {
+ success = false;
+ }
+ }
+
+ if (success) {
+ delete m_file;
+ emit sessionUnloaded();
+ m_file = new SessionFile(m_core);
+ if (!m_file->load(fileName)) {
+ QMessageBox::warning(0, tr("Error while loading session"), \
+ tr("Could not load session %1").arg(fileName));
+ success = false;
+ }
+ setStartupProject(m_file->m_startupProject);
+ }
+
+ if (success) {
+ // restore the active mode
+ const QString &modeIdentifier = value(QLatin1String("ActiveMode")).toString();
+ if (!modeIdentifier.isEmpty())
+ m_core->modeManager()->activateMode(modeIdentifier);
+ }
+
+ if (debug)
+ qDebug() << "SessionManager - loading session returned " << success;
+
+ if (success)
+ emit sessionLoaded();
+
+ return success;
+}
+
+bool SessionManager::save()
+{
+ if (debug)
+ qDebug() << "SessionManager - saving session" << m_sessionName;
+
+ emit aboutToSaveSession();
+
+ bool result = m_file->save();
+
+ if (!result) {
+ QMessageBox::warning(0, tr("Error while saving session"),
+ tr("Could not save session to file %1").arg(m_file->fileName()));
+ }
+
+ if (debug)
+ qDebug() << "SessionManager - saving session returned " << result;
+
+ return result;
+}
+
+
+/*!
+ \fn bool SessionManager::clear()
+
+ Returns whether the clear operation has been not cancelled & all projects could be closed.
+ */
+bool SessionManager::clear()
+{
+ if (debug)
+ qDebug() << "SessionManager - clearing session ...";
+
+ bool cancelled;
+ QList<Project *> notClosed = requestCloseOfAllFiles(&cancelled);
+
+ bool success = !cancelled;
+
+ if (success) {
+ if (debug)
+ qDebug() << "SessionManager - Removing projects ...";
+
+ QList<Project *> toClose;
+ foreach (Project *pro, projects()) {
+ if (!notClosed.contains(pro))
+ toClose << pro;
+ }
+
+ setStartupProject(0);
+ removeProjects(toClose);
+ }
+
+ if (!notClosed.isEmpty())
+ success = false;
+
+ if (debug)
+ qDebug() << "SessionManager - clearing session result is " << success;
+
+ return success;
+}
+
+void SessionManager::editDependencies()
+{
+ DependenciesDialog dlg(0, this);
+ dlg.exec();
+}
+
+QList<Project *> SessionManager::projects() const
+{
+ return m_file->m_projects;
+}
+
+QStringList SessionManager::dependencies(const QString &proName) const
+{
+ QStringList result;
+ foreach (const QString &dep, m_file->m_depMap.value(proName))
+ result += dependencies(dep);
+
+ result << proName;
+ return result;
+}
+
+QStringList SessionManager::dependenciesOrder() const
+{
+ QList<QPair<QString, QStringList> > unordered;
+ QStringList ordered;
+
+ // copy the map to a temporary list
+ foreach (Project *pro, projects()) {
+ const QString &proName = pro->file()->fileName();
+ unordered << QPair<QString, QStringList>
+ (proName, m_file->m_depMap.value(proName));
+ }
+
+ while (!unordered.isEmpty()) {
+ for (int i=(unordered.count()-1); i>=0; --i) {
+ if (unordered.at(i).second.isEmpty()) {
+ ordered << unordered.at(i).first;
+ unordered.removeAt(i);
+ }
+ }
+
+ // remove the handled projects from the dependency lists
+ // of the remaining unordered projects
+ for (int i = 0; i < unordered.count(); ++i) {
+ foreach (const QString &pro, ordered) {
+ QStringList depList = unordered.at(i).second;
+ depList.removeAll(pro);
+ unordered[i].second = depList;
+ }
+ }
+ }
+
+ return ordered;
+}
+
+Project *SessionManager::defaultStartupProject() const
+{
+ // Just take first one
+ foreach (Project *p, m_file->m_projects) {
+ if (p->isApplication())
+ return p;
+ }
+ return 0;
+}
+
+QList<Project *> SessionManager::projectOrder(Project *project) const
+{
+ QList<Project *> result;
+
+ QStringList pros;
+ if (project) {
+ pros = dependencies(project->file()->fileName());
+ } else {
+ pros = dependenciesOrder();
+ }
+
+ foreach (const QString &proFile, pros) {
+ foreach (Project *pro, projects()) {
+ if (pro->file()->fileName() == proFile) {
+ result << pro;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+Project *SessionManager::projectForNode(Node *node) const
+{
+ if (!node)
+ return 0;
+
+ Project *project = 0;
+
+ FolderNode *rootProjectNode = qobject_cast<FolderNode*>(node);
+ if (!rootProjectNode)
+ rootProjectNode = node->parentFolderNode();
+ while (rootProjectNode && rootProjectNode->parentFolderNode() != m_sessionNode)
+ rootProjectNode = rootProjectNode->parentFolderNode();
+
+ Q_ASSERT(rootProjectNode);
+
+ QList<Project *> projectList = projects();
+ foreach (Project *p, projectList) {
+ if (p->rootProjectNode() == rootProjectNode) {
+ project = p;
+ break;
+ }
+ }
+
+ return project;
+}
+
+Node *SessionManager::nodeForFile(const QString &fileName) const
+{
+ Node *node = 0;
+ if (Project *project = projectForFile(fileName)) {
+ FindNodesForFileVisitor findNodes(fileName);
+ project->rootProjectNode()->accept(&findNodes);
+
+ foreach (Node *n, findNodes.nodes()) {
+ // prefer file nodes
+ if (!node || (node->nodeType() != FileNodeType && n->nodeType() == FileNodeType))
+ node = n;
+ }
+ }
+
+ return node;
+}
+
+Project *SessionManager::projectForFile(const QString &fileName) const
+{
+ if (debug)
+ qDebug() << "SessionManager::projectForFile(" << fileName << ")";
+
+ Project *project = 0;
+
+ QList<Project *> projectList = projects();
+
+ // Always check current project first
+ if (Project *currentProject = ProjectExplorerPlugin::instance()->currentProject()) {
+ projectList.removeOne(currentProject);
+ projectList.insert(0, currentProject);
+ }
+
+ foreach (Project *p, projectList) {
+ if (!m_projectFileCache.contains(p)) {
+ m_projectFileCache.insert(p, p->files(Project::AllFiles));
+ }
+ if (m_projectFileCache.value(p).contains(fileName)) {
+ project = p;
+ break;
+ }
+ }
+ return project;
+}
+
+void SessionManager::setEditorCodec(Core::IEditor *editor, const QString &fileName)
+{
+ if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor))
+ if (Project *project = projectForFile(fileName))
+ textEditor->setTextCodec(project->editorConfiguration()->defaultTextCodec());
+}
+
+
+QList<Project *> SessionManager::requestCloseOfAllFiles(bool *cancelled)
+{
+ *cancelled = false;
+ QList<Core::IFile*> filesToClose;
+ foreach (Project *pro, projects())
+ filesToClose << pro->file();
+ foreach (Core::IEditor *editor, m_core->editorManager()->openedEditors())
+ filesToClose << editor->file();
+ QList<Core::IFile*> notClosed;
+ if (!filesToClose.isEmpty())
+ notClosed = m_core->fileManager()->saveModifiedFiles(filesToClose, cancelled);
+ // close editors here by hand
+ if (!*cancelled) {
+ QList<Core::IEditor*> editorsToClose;
+ foreach (Core::IEditor *editor, m_core->editorManager()->openedEditors())
+ if (!notClosed.contains(editor->file()))
+ editorsToClose << editor;
+ m_core->editorManager()->closeEditors(editorsToClose, false);
+ // project files are closed/removed later (in this::clear)
+ }
+ return Core::Utils::qwConvertList<Project*>(notClosed);
+}
+
+Core::IFile *SessionManager::file() const
+{
+ return m_file;
+}
+
+void SessionManager::updateWindowTitle()
+{
+ QString windowTitle = tr("Qt Creator");
+ if (!isDefaultSession(m_sessionName)) {
+ QString sessionName = m_sessionName;
+ if (sessionName.isEmpty())
+ sessionName = tr("Untitled");
+ windowTitle.prepend(sessionName + " - ");
+ } else {
+ if (Project *currentProject = ProjectExplorerPlugin::instance()->currentProject())
+ windowTitle.prepend(currentProject->name() + " - ");
+ }
+ m_core->mainWindow()->setWindowTitle(windowTitle);
+}
+
+void SessionManager::updateName(const QString &session)
+{
+ m_sessionName = session;
+ QString sessionName = m_sessionName;
+
+ if (sessionName.isEmpty())
+ sessionName = tr("Untitled");
+
+ m_displayName = tr("Session (\'%1\')").arg(sessionName);
+ updateWindowTitle();
+}
+
+
+void SessionManager::removeProjects(QList<Project *> remove)
+{
+ QMap<QString, QStringList> resMap;
+
+ foreach (Project *pro, remove) {
+ if (debug)
+ qDebug() << "SessionManager - emitting aboutToRemoveProject(" << pro->name() << ")";
+ emit aboutToRemoveProject(pro);
+ }
+
+ // TODO: Clear m_modelProjectHash
+
+ // Delete projects
+ foreach (Project *pro, remove) {
+ m_file->m_projects.removeOne(pro);
+
+ if (pro == m_file->m_startupProject)
+ setStartupProject(0);
+
+ disconnect(pro, SIGNAL(fileListChanged()),
+ this, SLOT(clearProjectFileCache()));
+ m_projectFileCache.remove(pro);
+
+ if (debug)
+ qDebug() << "SessionManager - emitting projectRemoved(" << pro->name() << ")";
+ m_sessionNode->removeProjectNode(pro->rootProjectNode());
+ emit projectRemoved(pro);
+ delete pro;
+ }
+
+ // Refresh dependencies
+ QSet<QString> projectFiles;
+ foreach (Project *pro, projects()) {
+ if (!remove.contains(pro))
+ projectFiles.insert(pro->file()->fileName());
+ }
+
+ QSet<QString>::const_iterator i = projectFiles.begin();
+ while (i != projectFiles.end()) {
+ QStringList dependencies;
+ foreach (const QString &dependency, m_file->m_depMap.value(*i)) {
+ if (projectFiles.contains(dependency))
+ dependencies << dependency;
+ }
+ if (!dependencies.isEmpty())
+ resMap.insert(*i, dependencies);
+ ++i;
+ }
+
+ m_file->m_depMap = resMap;
+
+ if (startupProject() == 0)
+ if (Project *newStartupProject = defaultStartupProject())
+ setStartupProject(newStartupProject);
+}
+
+void SessionManager::setValue(const QString &name, const QVariant &value)
+{
+ m_file->m_values.insert(name, value);
+}
+
+QVariant SessionManager::value(const QString &name)
+{
+ QMap<QString, QVariant>::const_iterator it = m_file->m_values.find(name);
+ if (it != m_file->m_values.constEnd())
+ return *it;
+ else
+ return QVariant();
+}
+
+QString SessionManager::activeSession() const
+{
+ return m_sessionName;
+}
+
+QStringList SessionManager::sessions() const
+{
+ QStringList result = m_core->settings()->value("Sessions").toStringList();
+
+ if (!result.contains("default"))
+ result.prepend("default");
+
+ return result;
+}
+
+QString SessionManager::sessionNameToFileName(const QString &session)
+{
+ QString sn = session;
+ return QFileInfo(m_core->settings()->fileName()).path() + "/qtcreator/" + sn + ".qws";
+}
+
+void SessionManager::createAndLoadNewDefaultSession()
+{
+ updateName("default");
+ createImpl(sessionNameToFileName(m_sessionName));
+}
+
+bool SessionManager::createSession(const QString &session)
+{
+ if (sessions().contains(session))
+ return false;
+ QStringList list = m_core->settings()->value("Sessions").toStringList();
+ list.append(session);
+ m_core->settings()->setValue("Sessions", list);
+ return true;
+}
+
+bool SessionManager::deleteSession(const QString &session)
+{
+ QStringList list = m_core->settings()->value("Sessions").toStringList();
+ if (!list.contains(session))
+ return false;
+ list.removeOne(session);
+ m_core->settings()->setValue("Sessions", list);
+ QFile fi(sessionNameToFileName(session));
+ if (fi.exists())
+ return fi.remove();
+ return false;
+}
+
+bool SessionManager::cloneSession(const QString &original, const QString &clone)
+{
+ QStringList list = m_core->settings()->value("Sessions").toStringList();
+ list.append(clone);
+
+ if (!sessions().contains(original))
+ return false;
+
+ QFile fi(sessionNameToFileName(original));
+
+ // If the file does not exist, we can still clone
+ if (!fi.exists() || fi.copy(sessionNameToFileName(clone))) {
+ m_core->settings()->setValue("Sessions", list);
+ return true;
+ }
+ return false;
+}
+
+bool SessionManager::loadSession(const QString &session)
+{
+ // Do nothing if we have that session already loaded,
+ // exception if the session is the default virgin session
+ // we still want to be able to load the default session
+ if (session == m_sessionName && !isDefaultVirgin())
+ return true;
+
+ if (!sessions().contains(session))
+ return false;
+ QString fileName = sessionNameToFileName(session);
+ if (QFileInfo(fileName).exists()) {
+ if (loadImpl(fileName)) {
+ updateName(session);
+ return true;
+ }
+ } else {
+ // Create a new session with that name
+ if(!createImpl(sessionNameToFileName(session)))
+ return false;
+ updateName(session);
+ return true;
+ }
+ return false;
+}
+
+QString SessionManager::lastSession() const
+{
+ QSettings *settings = m_core->settings();
+ QString fileName = settings->value("ProjectExplorer/StartupSession").toString();
+ return QFileInfo(fileName).baseName();
+}
+
+SessionNode *SessionManager::sessionNode() const
+{
+ return m_sessionNode;
+}
+
+void SessionManager::reportProjectLoadingProgress()
+{
+ m_file->sessionLoadingProgress();
+}
+
+
+#include "session.moc"
diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h
new file mode 100644
index 0000000000..95cd21c937
--- /dev/null
+++ b/src/plugins/projectexplorer/session.h
@@ -0,0 +1,207 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SESSION_H
+#define SESSION_H
+
+#include "projectexplorer_export.h"
+#include "projectnodes.h"
+
+#include <coreplugin/ifile.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+namespace Core {
+class ICore;
+class IMode;
+class IEditor;
+}
+
+namespace ProjectExplorer {
+
+class Project;
+class Node;
+class SessionNode;
+class SessionManager;
+
+namespace Internal {
+
+class SessionFile;
+
+// Must be in header as otherwise moc has issues
+// with ProjectExplorer::SessionNode on msvc2005
+class SessionNodeImpl
+ : public ProjectExplorer::SessionNode
+{
+ Q_OBJECT
+public:
+ SessionNodeImpl(SessionManager *manager);
+
+ void addProjectNode(ProjectNode *projectNode);
+ void removeProjectNode(ProjectNode *projectNode);
+
+ void setFileName(const QString &fileName);
+};
+
+} // namespace Internal
+
+// TODO the interface of this class is not really great
+
+// The implementation suffers that all the functions from the
+// public interface just wrap around functions which do the actual work
+
+// This could be improved.
+class PROJECTEXPLORER_EXPORT SessionManager
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ SessionManager(Core::ICore *core, QObject *parent = 0);
+ ~SessionManager();
+
+ // higher level session management
+ QString activeSession() const;
+ QString lastSession() const;
+ QStringList sessions() const;
+
+ // creates a new default session and switches to it
+ void createAndLoadNewDefaultSession();
+
+ // Just creates a new session (Does not actually create the file)
+ bool createSession(const QString &session);
+
+ // delete session name from session list
+ // delete file from disk
+ bool deleteSession(const QString &session);
+
+ bool cloneSession(const QString &original, const QString &clone);
+
+ // loads a session, takes a session name (not filename)
+ bool loadSession(const QString &session);
+
+ bool save();
+ bool clear();
+
+ void addProject(Project *project);
+ void addProjects(const QList<Project*> &projects);
+ void removeProject(Project *project);
+ void removeProjects(QList<Project *> remove);
+
+ void editDependencies();
+ void setStartupProject(Project *startupProject);
+
+ // NBS think about dependency management again.
+ // Probably kill these here
+ bool canAddDependency(Project *project, Project *depProject) const;
+ bool hasDependency(Project *project, Project *depProject) const;
+ // adds the 'requiredProject' as a dependency to 'project'
+ bool addDependency(Project *project, Project *depProject);
+ void removeDependency(Project *project, Project *depProject);
+
+ Core::IFile *file() const;
+ Project *startupProject() const;
+
+ QList<Project *> projects() const;
+
+ bool isDefaultVirgin() const;
+ bool isDefaultSession(const QString &session) const;
+
+ // Let other plugins store persistent values within the session file
+ void setValue(const QString &name, const QVariant &value);
+ QVariant value(const QString &name);
+
+ // NBS rewrite projectOrder (dependency management)
+ QList<Project *> projectOrder(Project *project = 0) const;
+ QAbstractItemModel *model(const QString &modelId) const;
+
+ SessionNode *sessionNode() const;
+
+ Project *projectForNode(ProjectExplorer::Node *node) const;
+ Node *nodeForFile(const QString &fileName) const;
+ Project *projectForFile(const QString &fileName) const;
+
+
+ void reportProjectLoadingProgress();
+
+signals:
+ void projectAdded(ProjectExplorer::Project *project);
+ void singleProjectAdded(ProjectExplorer::Project *project);
+ void aboutToRemoveProject(ProjectExplorer::Project *project);
+
+ void projectRemoved(ProjectExplorer::Project *project);
+
+ void startupProjectChanged(ProjectExplorer::Project *project);
+
+ void sessionUnloaded();
+ void sessionLoaded();
+ void aboutToSaveSession();
+
+private slots:
+ void saveActiveMode(Core::IMode *mode);
+ void clearProjectFileCache();
+ void setEditorCodec(Core::IEditor *editor, const QString &fileName);
+ void updateWindowTitle();
+
+private:
+ bool loadImpl(const QString &fileName);
+ bool createImpl(const QString &fileName);
+ QString sessionNameToFileName(const QString &session);
+
+ bool recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const;
+ QStringList dependencies(const QString &proName) const;
+ QStringList dependenciesOrder() const;
+ Project *defaultStartupProject() const;
+
+ QList<Project *> requestCloseOfAllFiles(bool *cancelled);
+
+ void updateName(const QString &session);
+
+ Core::ICore *m_core;
+
+ Internal::SessionFile *m_file;
+ Internal::SessionNodeImpl *m_sessionNode;
+ QString m_displayName;
+ QString m_sessionName;
+
+ mutable
+ QHash<Project *, QStringList> m_projectFileCache;
+};
+
+} // namespace ProjectExplorer
+
+#endif // SESSION_H
diff --git a/src/plugins/projectexplorer/sessiondialog.cpp b/src/plugins/projectexplorer/sessiondialog.cpp
new file mode 100644
index 0000000000..d674c047d7
--- /dev/null
+++ b/src/plugins/projectexplorer/sessiondialog.cpp
@@ -0,0 +1,194 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "sessiondialog.h"
+#include "session.h"
+
+#include <QtGui/QInputDialog>
+
+#include <QtGui/QValidator>
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class SessionValidator : public QValidator
+{
+public:
+ SessionValidator(QObject *parent, QStringList sessions);
+ void fixup(QString & input) const;
+ QValidator::State validate(QString & input, int & pos) const;
+private:
+ QStringList m_sessions;
+};
+
+SessionValidator::SessionValidator(QObject *parent, QStringList sessions)
+ : QValidator(parent), m_sessions(sessions)
+{
+}
+
+QValidator::State SessionValidator::validate(QString &input, int &pos) const
+{
+ Q_UNUSED(pos);
+ if (m_sessions.contains(input))
+ return QValidator::Intermediate;
+ else
+ return QValidator::Acceptable;
+}
+
+void SessionValidator::fixup(QString &input) const
+{
+ int i = 2;
+ QString copy;
+ do {
+ copy = input + QString(" (%1)").arg(i);
+ ++i;
+ } while (m_sessions.contains(copy));
+ input = copy;
+}
+
+class NewSessionInputDialog : public QDialog
+{
+public:
+ NewSessionInputDialog(QStringList sessions);
+ QString value();
+private:
+ QLineEdit *m_newSessionLineEdit;
+};
+
+NewSessionInputDialog::NewSessionInputDialog(QStringList sessions)
+{
+ setWindowTitle("New session name");
+ QVBoxLayout *hlayout = new QVBoxLayout(this);
+ QLabel *label = new QLabel("Enter the name of the new session:", this);
+ hlayout->addWidget(label);
+ m_newSessionLineEdit = new QLineEdit(this);
+ m_newSessionLineEdit->setValidator(new SessionValidator(this, sessions));
+ hlayout->addWidget(m_newSessionLineEdit);
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
+ connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
+ hlayout->addWidget(buttons);
+ setLayout(hlayout);
+}
+
+QString NewSessionInputDialog::value()
+{
+ return m_newSessionLineEdit->text();
+}
+
+SessionDialog::SessionDialog(SessionManager *sessionManager, const QString &lastSession, bool startup)
+ : m_sessionManager(sessionManager), m_startup(startup)
+{
+ m_ui.setupUi(this);
+
+ connect(m_ui.btCreateNew, SIGNAL(clicked()),
+ this, SLOT(createNew()));
+
+ connect(m_ui.btClone, SIGNAL(clicked()),
+ this, SLOT(clone()));
+ connect(m_ui.btDelete, SIGNAL(clicked()),
+ this, SLOT(remove()));
+
+ connect(m_ui.sessionList, SIGNAL(itemDoubleClicked ( QListWidgetItem *)),
+ this, SLOT(accept()));
+
+ connect(m_ui.sessionList, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this, SLOT(updateActions()));
+
+ QStringList sessions = sessionManager->sessions();
+ foreach(const QString &session, sessions) {
+ m_ui.sessionList->addItem(session);
+ if (session == lastSession)
+ m_ui.sessionList->setCurrentRow(m_ui.sessionList->count() - 1);
+ }
+}
+
+void SessionDialog::updateActions()
+{
+ bool enableDelete = false;
+
+ if (m_ui.sessionList->currentItem())
+ enableDelete = (m_ui.sessionList->currentItem()->text() != m_sessionManager->activeSession()
+ && m_ui.sessionList->currentItem()->text() != "default");
+ m_ui.btDelete->setEnabled(enableDelete);
+}
+
+void SessionDialog::accept()
+{
+ if (m_ui.sessionList->currentItem()) {
+ m_sessionManager->loadSession(m_ui.sessionList->currentItem()->text());
+ }
+ QDialog::accept();
+}
+
+void SessionDialog::reject()
+{
+ // clear list
+ QDialog::reject();
+}
+
+void SessionDialog::createNew()
+{
+ NewSessionInputDialog newSessionInputDialog(m_sessionManager->sessions());
+ if (newSessionInputDialog.exec() == QDialog::Accepted) {
+ QString newSession = newSessionInputDialog.value();
+ if (newSession.isEmpty() || m_sessionManager->sessions().contains(newSession))
+ return;
+
+ m_sessionManager->createSession(newSession);
+ m_ui.sessionList->addItem(newSession);
+ m_ui.sessionList->setCurrentRow(m_ui.sessionList->count() - 1);
+ }
+}
+
+void SessionDialog::clone()
+{
+ NewSessionInputDialog newSessionInputDialog(m_sessionManager->sessions());
+ if (newSessionInputDialog.exec() == QDialog::Accepted) {
+ QString newSession = newSessionInputDialog.value();
+ if (m_sessionManager->cloneSession(m_ui.sessionList->currentItem()->text(), newSession))
+ m_ui.sessionList->addItem(newSession);
+ }
+}
+
+void SessionDialog::remove()
+{
+ m_sessionManager->deleteSession(m_ui.sessionList->currentItem()->text());
+ m_ui.sessionList->clear();
+ m_ui.sessionList->addItems(m_sessionManager->sessions());
+}
+
+}
+}
diff --git a/src/plugins/projectexplorer/sessiondialog.h b/src/plugins/projectexplorer/sessiondialog.h
new file mode 100644
index 0000000000..cae3e22028
--- /dev/null
+++ b/src/plugins/projectexplorer/sessiondialog.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SESSIONDIALOG_H
+#define SESSIONDIALOG_H
+
+#include <QtCore/QString>
+#include <QtGui/QDialog>
+
+#include "ui_sessiondialog.h"
+
+namespace ProjectExplorer {
+
+class SessionManager;
+
+namespace Internal {
+
+class SessionDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ SessionDialog(SessionManager *sessionManager, const QString &lastSession, bool startup);
+
+ void accept();
+ void reject();
+
+private slots:
+ void createNew();
+ void clone();
+ void remove();
+
+ void updateActions();
+
+private:
+ Ui::SessionDialog m_ui;
+ SessionManager *m_sessionManager;
+ bool m_startup;
+};
+
+}
+}
+
+
+#endif // SESSIONDIALOG_H
diff --git a/src/plugins/projectexplorer/sessiondialog.ui b/src/plugins/projectexplorer/sessiondialog.ui
new file mode 100644
index 0000000000..942116e35e
--- /dev/null
+++ b/src/plugins/projectexplorer/sessiondialog.ui
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectExplorer::Internal::SessionDialog</class>
+ <widget class="QDialog" name="ProjectExplorer::Internal::SessionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>370</width>
+ <height>260</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Session Manager</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Choose your session</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QListWidget" name="sessionList"/>
+ </item>
+ <item row="1" column="2">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="btCreateNew">
+ <property name="text">
+ <string>Create New Session</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btClone">
+ <property name="text">
+ <string>Clone Session</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btDelete">
+ <property name="text">
+ <string>Delete Session</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProjectExplorer::Internal::SessionDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>246</x>
+ <y>237</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>78</x>
+ <y>216</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProjectExplorer::Internal::SessionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>191</x>
+ <y>244</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>114</x>
+ <y>237</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp
new file mode 100644
index 0000000000..ae3f42a7da
--- /dev/null
+++ b/src/plugins/projectexplorer/taskwindow.cpp
@@ -0,0 +1,534 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "taskwindow.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+#include <projectexplorerconstants.h>
+
+#include <QtCore/QDir>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QHeaderView>
+#include <QtGui/QListView>
+#include <QtGui/QPainter>
+#include <QtCore/QAbstractItemModel>
+#include <QtGui/QFont>
+#include <QtGui/QFontMetrics>
+#include <QtGui/QTextLayout>
+
+using namespace ProjectExplorer::Internal;
+
+// Internal Struct for TaskModel
+struct TaskItem
+{
+ QString description;
+ QString file;
+ int line;
+ bool fileNotFound;
+ ProjectExplorer::BuildParserInterface::PatternType type;
+};
+
+class ProjectExplorer::Internal::TaskModel : public QAbstractItemModel
+{
+public:
+ // Model stuff
+ TaskModel();
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ void clear();
+ void addTask(ProjectExplorer::BuildParserInterface::PatternType type,
+ const QString &description, const QString &file, int line);
+ int sizeOfFile();
+ int sizeOfLineNumber();
+ QModelIndex firstError() const;
+ void setFileNotFound(const QModelIndex &index, bool b);
+
+ enum Roles { File = Qt::UserRole, Line, Description, FileNotFound };
+private:
+ QList<TaskItem> m_items;
+ int m_maxSizeOfFileName;
+};
+
+////
+// TaskView
+////
+
+TaskView::TaskView(QWidget *parent)
+ : QListView(parent)
+{
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+TaskView::~TaskView()
+{
+
+}
+
+void TaskView::resizeEvent(QResizeEvent *e)
+{
+ Q_UNUSED(e);
+ static_cast<TaskDelegate *>(itemDelegate())->emitSizeHintChanged(selectionModel()->currentIndex());
+}
+
+void TaskView::keyPressEvent(QKeyEvent *e)
+{
+ if (!e->modifiers() && e->key() == Qt::Key_Return) {
+ emit activated(currentIndex());
+ e->accept();
+ return;
+ }
+ QListView::keyPressEvent(e);
+}
+
+/////
+// TaskModel
+/////
+
+TaskModel::TaskModel()
+{
+ m_maxSizeOfFileName = 0;
+}
+
+void TaskModel::addTask(ProjectExplorer::BuildParserInterface::PatternType type, const QString &description, const QString &file, int line)
+{
+ TaskItem task;
+ task.description = description;
+ task.file = file;
+ task.line = line;
+ task.type = type;
+ task.fileNotFound = false;
+
+ beginInsertRows(QModelIndex(), m_items.size(), m_items.size());
+ m_items.append(task);
+ endInsertRows();
+
+ QFont font;
+ QFontMetrics fm(font);
+ QString filename = task.file;
+ int pos = filename.lastIndexOf("/");
+ if (pos != -1)
+ filename = file.mid(pos +1);
+ m_maxSizeOfFileName = qMax(m_maxSizeOfFileName, fm.width(filename));
+}
+
+void TaskModel::clear()
+{
+ if (m_items.isEmpty())
+ return;
+ beginRemoveRows(QModelIndex(), 0, m_items.size() -1);
+ m_items.clear();
+ endRemoveRows();
+ m_maxSizeOfFileName = 0;
+}
+
+
+QModelIndex TaskModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return QModelIndex();
+ return createIndex(row, column, 0);
+}
+
+QModelIndex TaskModel::parent(const QModelIndex &child) const
+{
+ Q_UNUSED(child);
+ return QModelIndex();
+}
+
+int TaskModel::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : m_items.count();
+}
+
+int TaskModel::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : 1;
+}
+
+QVariant TaskModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= m_items.size() || index.column() != 0)
+ return QVariant();
+
+ if (role == TaskModel::File)
+ return m_items.at(index.row()).file;
+ else if (role == TaskModel::Line)
+ return m_items.at(index.row()).line;
+ else if (role == TaskModel::Description)
+ return m_items.at(index.row()).description;
+ else if (role == TaskModel::FileNotFound)
+ return m_items.at(index.row()).fileNotFound;
+ else if (role == Qt::DecorationRole) {
+ if (m_items.at(index.row()).type == ProjectExplorer::BuildParserInterface::Error) {
+ return QIcon(":/projectexplorer/images/compile_error.png");
+ } else if (m_items.at(index.row()).type == ProjectExplorer::BuildParserInterface::Warning) {
+ return QIcon(":/projectexplorer/images/compile_warning.png");
+ } else {
+ return QIcon(":/projectexplorer/images/compile_unspecified.png");
+ }
+ }
+ return QVariant();
+}
+
+int TaskModel::sizeOfFile()
+{
+ return m_maxSizeOfFileName;
+}
+
+int TaskModel::sizeOfLineNumber()
+{
+ QFont font;
+ QFontMetrics fm(font);
+ return fm.width("8888");
+}
+
+QModelIndex TaskModel::firstError() const
+{
+ int size = m_items.size();
+ for (int i=0; i<size; ++i) {
+ if (m_items.at(i).type == ProjectExplorer::BuildParserInterface::Error) {
+ return index(i, 0);
+ }
+ }
+ return QModelIndex();
+}
+
+void TaskModel::setFileNotFound(const QModelIndex &idx, bool b)
+{
+ if (idx.isValid() && idx.row() < m_items.size()) {
+ m_items[idx.row()].fileNotFound = b;
+ emit dataChanged(idx, idx);
+ }
+}
+
+/////
+// TaskWindow
+/////
+
+TaskWindow::TaskWindow()
+{
+ m_coreIFace = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ m_model = new TaskModel;
+ m_listview = new TaskView;
+
+ m_listview->setModel(m_model);
+ m_listview->setFrameStyle(QFrame::NoFrame);
+ m_listview->setWindowTitle(tr("Problems"));
+ m_listview->setSelectionMode(QAbstractItemView::SingleSelection);
+ TaskDelegate *tld = new TaskDelegate(this);
+ m_listview->setItemDelegate(tld);
+ m_listview->setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
+
+ connect(m_listview->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ tld, SLOT(currentChanged(const QModelIndex &, const QModelIndex &)));
+
+ connect(m_listview, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(showTaskInFile(const QModelIndex &)));
+ connect(m_listview, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(showTaskInFile(const QModelIndex &)));
+
+ m_errorCount = 0;
+ m_currentTask = -1;
+}
+
+TaskWindow::~TaskWindow()
+{
+ delete m_listview;
+ delete m_model;
+}
+
+QList<QWidget*> TaskWindow::toolBarWidgets() const
+{
+ return QList<QWidget*>();
+}
+
+QWidget *TaskWindow::outputWidget(QWidget *)
+{
+ return m_listview;
+}
+
+void TaskWindow::clearContents()
+{
+ m_errorCount = 0;
+ m_currentTask = -1;
+ m_model->clear();
+ emit tasksChanged();
+}
+
+void TaskWindow::visibilityChanged(bool /* b */)
+{
+
+}
+
+void TaskWindow::addItem(ProjectExplorer::BuildParserInterface::PatternType type,
+ const QString &description, const QString &file, int line)
+{
+ m_model->addTask(type, description, file, line);
+ if (type == ProjectExplorer::BuildParserInterface::Error)
+ ++m_errorCount;
+ emit tasksChanged();
+}
+
+void TaskWindow::showTaskInFile(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return;
+ QString file = index.data(TaskModel::File).toString();
+ int line = index.data(TaskModel::Line).toInt();
+ if (file.isEmpty() || line == -1)
+ return;
+
+ if (QFileInfo(file).exists())
+ TextEditor::BaseTextEditor::openEditorAt(file, line);
+ else
+ m_model->setFileNotFound(index, true);
+ m_listview->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
+ m_listview->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
+}
+
+int TaskWindow::numberOfTasks() const
+{
+ return m_model->rowCount(QModelIndex());
+}
+
+int TaskWindow::numberOfErrors() const
+{
+ return m_errorCount;
+}
+
+int TaskWindow::priorityInStatusBar() const
+{
+ return 90;
+}
+
+void TaskWindow::gotoFirstError()
+{
+ QModelIndex idx = m_model->firstError();
+ if (idx.isValid())
+ showTaskInFile(idx);
+}
+
+bool TaskWindow::hasFocus()
+{
+ return m_listview->hasFocus();
+}
+
+bool TaskWindow::canFocus()
+{
+ return m_model->rowCount();
+}
+
+#include <QDebug>
+
+void TaskWindow::setFocus()
+{
+ if (m_model->rowCount()) {
+ m_listview->setFocus();
+ if (m_listview->currentIndex() == QModelIndex()) {
+ m_listview->setCurrentIndex(m_model->index(0,0, QModelIndex()));
+ }
+ }
+}
+
+/////
+// Delegate
+/////
+
+TaskDelegate::TaskDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+
+TaskDelegate::~TaskDelegate()
+{
+}
+
+QSize TaskDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption(&opt, index);
+
+
+ QFontMetrics fm(option.font);
+ QSize s;
+ s.setWidth(option.rect.width());
+ const QAbstractItemView * view = qobject_cast<const QAbstractItemView *>(opt.widget);
+ TaskModel *model = static_cast<TaskModel *>(view->model());
+ int width = opt.rect.width() - model->sizeOfFile() - model->sizeOfLineNumber() - 12 - 22;
+ if (view->selectionModel()->currentIndex() == index) {
+ QString description = index.data(TaskModel::Description).toString();
+ // Layout the description
+ int leading = fm.leading();
+ int height = 0;
+ QTextLayout tl(description);
+ tl.beginLayout();
+ while(true) {
+ QTextLine line = tl.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(width);
+ height += leading;
+ line.setPosition(QPoint(0, height));
+ height += static_cast<int>(line.height());
+ }
+ tl.endLayout();
+
+ s.setHeight(height + leading + fm.height() + 3);
+ } else {
+ s.setHeight(fm.height() + 3);
+ }
+ return s;
+}
+
+void TaskDelegate::emitSizeHintChanged(const QModelIndex &index)
+{
+ emit sizeHintChanged(index);
+}
+
+void TaskDelegate::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ emit sizeHintChanged(current);
+ emit sizeHintChanged(previous);
+}
+
+void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption(&opt, index);
+ painter->save();
+
+ QFontMetrics fm(opt.font);
+ QColor backgroundColor;
+ QColor textColor;
+
+ const QAbstractItemView * view = qobject_cast<const QAbstractItemView *>(opt.widget);
+ bool selected = view->selectionModel()->currentIndex() == index;
+
+ if (selected) {
+ painter->setBrush(opt.palette.highlight().color());
+ backgroundColor = opt.palette.highlight().color();
+ } else {
+ painter->setBrush(opt.palette.background().color());
+ backgroundColor = opt.palette.background().color();
+ }
+ painter->setPen(Qt::NoPen);
+ painter->drawRect(opt.rect);
+
+ // Set Text Color
+ if (selected)
+ textColor = opt.palette.highlightedText().color();
+ else
+ textColor = opt.palette.text().color();
+
+ painter->setPen(textColor);
+
+ QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
+ painter->drawPixmap(2, opt.rect.top() + 2, icon.pixmap(16, 16));
+
+ TaskModel *model = static_cast<TaskModel *>(view->model());
+ int width = opt.rect.width() - model->sizeOfFile() - model->sizeOfLineNumber() - 12 - 22;
+ if (!selected) {
+ // in small mode we lay out differently
+ QString bottom = index.data(TaskModel::Description).toString();
+ painter->drawText(22, 2 + opt.rect.top() + fm.ascent(), bottom);
+ if (fm.width(bottom) > width) {
+ // draw a gradient to mask the text
+ int gwidth = opt.rect.right() - width;
+ QLinearGradient lg(QPoint(width, 0), QPoint(width+gwidth, 0));
+ QColor c = backgroundColor;
+ c.setAlpha(0);
+ lg.setColorAt(0, c);
+ lg.setColorAt(20.0/gwidth, backgroundColor);
+ painter->fillRect(width, 2 + opt.rect.top(), gwidth, fm.height() + 1, lg);
+ }
+ } else {
+ // Descritption
+ QString description = index.data(TaskModel::Description).toString();
+ // Layout the description
+ int leading = fm.leading();
+ int height = 0;
+ QTextLayout tl(description);
+ tl.beginLayout();
+ while(true) {
+ QTextLine line = tl.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(width);
+ height += leading;
+ line.setPosition(QPoint(0, height));
+ height += static_cast<int>(line.height());
+ }
+ tl.endLayout();
+ tl.draw(painter, QPoint(22, 2 + opt.rect.top()));
+ //painter->drawText(22, 2 + opt.rect.top() + fm.ascent(), description);
+
+ QColor mix;
+ mix.setRgb( static_cast<int>(0.7 * textColor.red() + 0.3 * backgroundColor.red()),
+ static_cast<int>(0.7 * textColor.green() + 0.3 * backgroundColor.green()),
+ static_cast<int>(0.7 * textColor.blue() + 0.3 * backgroundColor.blue()));
+ painter->setPen(mix);
+
+ QString directory = index.data(TaskModel::File).toString();
+ int secondBaseLine = 2 + fm.ascent() + opt.rect.top() + height + leading; //opt.rect.top() + fm.ascent() + fm.height() + 6;
+ if (index.data(TaskModel::FileNotFound).toBool()) {
+ QString fileNotFound = tr("File not found: %1").arg(directory);
+ painter->setPen(Qt::red);
+ painter->drawText(22, secondBaseLine, fileNotFound);
+ } else {
+ painter->drawText(22, secondBaseLine, directory);
+ }
+ }
+
+ painter->setPen(textColor);
+ // Assemble string for the right side
+ // just filename + linenumer
+ QString file = index.data(TaskModel::File).toString();
+ int pos = file.lastIndexOf("/");
+ if (pos != -1)
+ file = file.mid(pos +1);
+ painter->drawText(width + 22 + 4, 2 + opt.rect.top() + fm.ascent(), file);
+
+ QString topRight = index.data(TaskModel::Line).toString();
+ painter->drawText(opt.rect.right() - fm.width(topRight) - 6 , 2 + opt.rect.top() + fm.ascent(), topRight);
+ // Separator lines
+ painter->setPen(QColor::fromRgb(150,150,150));
+ painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
+ painter->restore();
+}
diff --git a/src/plugins/projectexplorer/taskwindow.h b/src/plugins/projectexplorer/taskwindow.h
new file mode 100644
index 0000000000..68ae3481a1
--- /dev/null
+++ b/src/plugins/projectexplorer/taskwindow.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TASKWINDOW_H
+#define TASKWINDOW_H
+
+#include "buildparserinterface.h"
+
+#include <coreplugin/ioutputpane.h>
+#include <coreplugin/icore.h>
+
+#include <QtGui/QTreeWidget>
+#include <QtGui/QStyledItemDelegate>
+#include <QtGui/QListView>
+#include <QtGui/QToolButton>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class TaskModel;
+class TaskView;
+
+class TaskWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ TaskWindow();
+ ~TaskWindow();
+
+ QWidget *outputWidget(QWidget *);
+ QList<QWidget*> toolBarWidgets(void) const;
+
+ QString name() const { return tr("Problems"); }
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool visible);
+
+ void addItem(BuildParserInterface::PatternType type,
+ const QString &description, const QString &file, int line);
+
+ int numberOfTasks() const;
+ int numberOfErrors() const;
+
+ void gotoFirstError();
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+signals:
+ void tasksChanged();
+
+private slots:
+ void showTaskInFile(const QModelIndex &index);
+
+private:
+ int sizeHintForColumn(int column) const;
+
+ Core::ICore *m_coreIFace;
+ int m_errorCount;
+ int m_currentTask;
+
+ TaskModel *m_model;
+ TaskView *m_listview;
+};
+
+class TaskView : public QListView
+{
+public:
+ TaskView(QWidget *parent = 0);
+ ~TaskView();
+ void resizeEvent(QResizeEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+};
+
+class TaskDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ TaskDelegate(QObject * parent = 0);
+ ~TaskDelegate();
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+ // TaskView uses this method if the size of the taskview changes
+ void emitSizeHintChanged(const QModelIndex &index);
+
+public slots:
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+
+private:
+ void generateGradientPixmap(int width, int height, QColor color, bool selected) const;
+};
+
+} //namespace Internal
+} //namespace ProjectExplorer
+
+#endif
diff --git a/src/plugins/projectexplorer/winguiprocess.cpp b/src/plugins/projectexplorer/winguiprocess.cpp
new file mode 100644
index 0000000000..5179ea01cf
--- /dev/null
+++ b/src/plugins/projectexplorer/winguiprocess.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDir>
+
+#include "winguiprocess.h"
+#include "consoleprocess.h"
+
+using namespace ProjectExplorer::Internal;
+
+WinGuiProcess::WinGuiProcess(QObject *parent)
+ : QThread(parent)
+{
+ m_pid = 0;
+ m_exitCode = 0;
+}
+
+WinGuiProcess::~WinGuiProcess()
+{
+ stop();
+}
+
+bool WinGuiProcess::start(const QString &program, const QStringList &args)
+{
+ m_program = program;
+ m_args = args;
+
+ if (!isRunning()) {
+ QThread::start(QThread::NormalPriority);
+ return true;
+ }
+ return false;
+}
+
+void WinGuiProcess::stop()
+{
+ if (m_pid)
+ TerminateProcess(m_pid->hProcess, 1);
+ wait();
+}
+
+bool WinGuiProcess::isRunning() const
+{
+ return QThread::isRunning();
+}
+
+bool WinGuiProcess::setupDebugInterface(HANDLE &bufferReadyEvent, HANDLE &dataReadyEvent, HANDLE &sharedFile, LPVOID &sharedMem)
+{
+
+ bufferReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_BUFFER_READY");
+ if (!bufferReadyEvent || GetLastError() == ERROR_ALREADY_EXISTS)
+ return false;
+ dataReadyEvent = CreateEvent(NULL, FALSE, FALSE, L"DBWIN_DATA_READY");
+ if (!dataReadyEvent || GetLastError() == ERROR_ALREADY_EXISTS)
+ return false;
+ sharedFile = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, L"DBWIN_BUFFER");
+ if (!sharedFile || GetLastError() == ERROR_ALREADY_EXISTS)
+ return false;
+ sharedMem = MapViewOfFile(sharedFile, FILE_MAP_READ, 0, 0, 512);
+ if (!sharedMem)
+ return false;
+ return true;
+}
+
+void WinGuiProcess::run()
+{
+ if (m_pid)
+ return;
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ m_pid = new PROCESS_INFORMATION;
+ ZeroMemory(m_pid, sizeof(PROCESS_INFORMATION));
+
+ m_exitCode = 0;
+
+ HANDLE bufferReadyEvent = NULL;
+ HANDLE dataReadyEvent = NULL;
+ HANDLE sharedFile = NULL;
+ LPVOID sharedMem = NULL;
+
+ bool dbgInterface = setupDebugInterface(bufferReadyEvent, dataReadyEvent, sharedFile, sharedMem);
+
+ QString cmdLine = ConsoleProcess::createCommandline(m_program, m_args);
+ bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
+ 0, 0, TRUE, CREATE_UNICODE_ENVIRONMENT,
+ environment().isEmpty() ? 0
+ : ConsoleProcess::createEnvironment(environment()).data(),
+ workingDirectory().isEmpty() ? 0
+ : (WCHAR*)QDir::convertSeparators(workingDirectory()).utf16(),
+ &si, m_pid);
+
+ if (!success) {
+ emit processError(tr("The process could not be started!"));
+ delete m_pid;
+ m_pid = 0;
+ return;
+ }
+
+ if (!dbgInterface) {
+ emit receivedDebugOutput(tr("Cannot retrieve debugging output!"));
+ WaitForSingleObject(m_pid->hProcess, INFINITE);
+ } else {
+ LPSTR message;
+ LPDWORD processId;
+ HANDLE toWaitFor[2];
+
+ message = reinterpret_cast<LPSTR>(sharedMem) + sizeof(DWORD);
+ processId = reinterpret_cast<LPDWORD>(sharedMem);
+
+ SetEvent(bufferReadyEvent);
+
+ toWaitFor[0] = dataReadyEvent;
+ toWaitFor[1] = m_pid->hProcess;
+
+ for (bool stop = false; !stop;) {
+ DWORD ret = WaitForMultipleObjects(2, toWaitFor, FALSE, INFINITE);
+
+ switch (ret) {
+ case WAIT_OBJECT_0 + 0:
+ if (*processId == m_pid->dwProcessId)
+ emit receivedDebugOutput(QString::fromAscii(message));
+ SetEvent(bufferReadyEvent);
+ break;
+ case WAIT_OBJECT_0 + 1:
+ stop = true;
+ break;
+ }
+ }
+ }
+
+ GetExitCodeProcess(m_pid->hProcess, &m_exitCode);
+ emit processFinished(static_cast<int>(m_exitCode));
+
+ UnmapViewOfFile(sharedMem);
+ CloseHandle(sharedFile);
+ CloseHandle(bufferReadyEvent);
+ CloseHandle(dataReadyEvent);
+ CloseHandle(m_pid->hProcess);
+ CloseHandle(m_pid->hThread);
+
+ delete m_pid;
+ m_pid = 0;
+}
+
+qint64 WinGuiProcess::applicationPID() const
+{
+ if (m_pid)
+ return m_pid->dwProcessId;
+ return 0;
+}
+
+int WinGuiProcess::exitCode() const
+{
+ return static_cast<int>(m_exitCode);
+}
diff --git a/src/plugins/projectexplorer/winguiprocess.h b/src/plugins/projectexplorer/winguiprocess.h
new file mode 100644
index 0000000000..b6e9b488ea
--- /dev/null
+++ b/src/plugins/projectexplorer/winguiprocess.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef WINGUIPROCESS_H
+#define WINGUIPROCESS_H
+
+#include <QtCore/QThread>
+#include <QtCore/QStringList>
+#include <windows.h>
+
+#include "abstractprocess.h"
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class WinGuiProcess : public QThread, public AbstractProcess
+{
+ Q_OBJECT
+
+public:
+ WinGuiProcess(QObject *parent);
+ ~WinGuiProcess();
+
+ bool start(const QString &program, const QStringList &args);
+ void stop();
+
+ bool isRunning() const;
+ qint64 applicationPID() const;
+ int exitCode() const;
+
+signals:
+ void processError(const QString &error);
+ void receivedDebugOutput(const QString &output);
+ void processFinished(int exitCode);
+
+private:
+ bool setupDebugInterface(HANDLE &bufferReadyEvent, HANDLE &dataReadyEvent, HANDLE &sharedFile, LPVOID &sharedMem);
+ void run();
+
+ PROCESS_INFORMATION *m_pid;
+ QString m_program;
+ QStringList m_args;
+ unsigned long m_exitCode;
+};
+
+} //namespace Internal
+} //namespace ProjectExplorer
+
+#endif
diff --git a/src/plugins/qhelpproject/qhelpproject.cpp b/src/plugins/qhelpproject/qhelpproject.cpp
new file mode 100644
index 0000000000..ddd2fa8f35
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpproject.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+
+#include <qhelpsystem.h>
+
+#include "qhelpproject.h"
+#include "qhelpprojectmanager.h"
+#include "qhelpprojectitems.h"
+
+using namespace ProjectExplorer;
+using namespace QHelpProjectPlugin::Internal;
+
+QHelpProject::QHelpProject(QHelpProjectManager *manager)
+{
+ m_manager = manager;
+
+ ProjectExplorerInterface *projectExplorer = m_manager->projectExplorer();
+ projectExplorer->addProjectItem(this);
+
+ m_filesFolder = new QHelpProjectFolder();
+ m_filesFolder->setName(QObject::tr("Files"));
+ projectExplorer->addProjectItem(m_filesFolder, this);
+}
+
+QHelpProject::~QHelpProject()
+{
+
+}
+
+bool QHelpProject::open(const QString &fileName)
+{
+ m_projectFile = fileName;
+
+ QHelpProjectParser parser;
+ if (!parser.parse(m_projectFile))
+ return false;
+
+ m_name = parser.namespaceURI();
+ m_files = parser.files();
+
+ QFileInfo fi(fileName);
+ QString dir = fi.absolutePath() + QDir::separator();
+
+ ProjectExplorerInterface *projectExplorer = m_manager->projectExplorer();
+ QHelpProjectFile *file;
+ foreach (QString f, m_files) {
+ file = new QHelpProjectFile(dir + f);
+ projectExplorer->addProjectItem(file, m_filesFolder);
+ }
+
+ m_manager->projectExplorer()->updateItem(this);
+
+ return true;
+}
+
+bool QHelpProject::save(const QString &fileName)
+{
+ return true;
+}
+
+QString QHelpProject::fileName() const
+{
+ return m_projectFile;
+}
+
+QString QHelpProject::defaultPath() const
+{
+ return QString();
+}
+
+QString QHelpProject::suggestedFileName() const
+{
+ return QString();
+}
+
+QString QHelpProject::fileFilter() const
+{
+ return QString();
+}
+
+QString QHelpProject::fileExtension() const
+{
+ return QString();
+}
+
+bool QHelpProject::isModified() const
+{
+ return false;
+}
+
+bool QHelpProject::isReadOnly() const
+{
+ return false;
+}
+
+bool QHelpProject::isSaveAsAllowed() const
+{
+ return true;
+}
+
+void QHelpProject::modified(QWorkbench::FileInterface::ReloadBehavior *behavior)
+{
+
+}
+
+IProjectManager *QHelpProject::projectManager() const
+{
+ return m_manager;
+}
+
+QVariant QHelpProject::projectProperty(const QString &key) const
+{
+ return QVariant();
+}
+
+void QHelpProject::setProjectProperty(const QString &key, const QVariant &value) const
+{
+
+}
+
+void QHelpProject::executeProjectCommand(int cmd)
+{
+
+}
+
+bool QHelpProject::supportsProjectCommand(int cmd)
+{
+ return false;
+}
+
+bool QHelpProject::hasProjectProperty(ProjectProperty property) const
+{
+ return false;
+}
+
+QList<QWorkbench::FileInterface*> QHelpProject::dependencies()
+{
+ return QList<QWorkbench::FileInterface*>();
+}
+
+void QHelpProject::setExtraApplicationRunArguments(const QStringList &args)
+{
+
+}
+
+void QHelpProject::setCustomApplicationOutputHandler(QObject *handler)
+{
+
+}
+
+QStringList QHelpProject::files(const QList<QRegExp> &fileMatcher)
+{
+ return m_files;
+}
+
+ProjectItemInterface::ProjectItemKind QHelpProject::kind() const
+{
+ return ProjectItemInterface::Project;
+}
+
+QString QHelpProject::name() const
+{
+ return m_name;
+}
+
+QIcon QHelpProject::icon() const
+{
+ return QIcon();
+}
diff --git a/src/plugins/qhelpproject/qhelpproject.h b/src/plugins/qhelpproject/qhelpproject.h
new file mode 100644
index 0000000000..fb89568256
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpproject.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QHELPPROJECT_H
+#define QHELPPROJECT_H
+
+#include <QtCore/QObject>
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+namespace QHelpProjectPlugin {
+namespace Internal {
+
+class QHelpProjectManager;
+class QHelpProjectFolder;
+
+class QHelpProject : public QObject,
+ public ProjectExplorer::ProjectInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ProjectExplorer::ProjectInterface
+ ProjectExplorer::ProjectItemInterface
+ QWorkbench::FileInterface)
+
+public:
+ QHelpProject(QHelpProjectManager *manager);
+ ~QHelpProject();
+
+ bool open(const QString &fileName);
+
+ //QWorkbench::FileInterface
+ bool save(const QString &fileName = QString());
+ QString fileName() const;
+
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+ QString fileFilter() const;
+ QString fileExtension() const;
+
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+
+ void modified(QWorkbench::FileInterface::ReloadBehavior *behavior);
+
+ //ProjectExplorer::ProjectInterface
+ ProjectExplorer::IProjectManager *projectManager() const;
+
+ QVariant projectProperty(const QString &key) const;
+ void setProjectProperty(const QString &key, const QVariant &value) const;
+
+ void executeProjectCommand(int cmd);
+ bool supportsProjectCommand(int cmd);
+
+ bool hasProjectProperty(ProjectProperty property) const;
+ QList<QWorkbench::FileInterface *> dependencies();
+
+ void setExtraApplicationRunArguments(const QStringList &args);
+ void setCustomApplicationOutputHandler(QObject *handler);
+
+ QStringList files(const QList<QRegExp> &fileMatcher);
+
+
+ //ProjectExplorer::ProjectItemInterface
+ ProjectItemKind kind() const;
+
+ QString name() const;
+ QIcon icon() const;
+
+signals:
+ void buildFinished(const QString &error);
+ void changed();
+
+private:
+ QHelpProjectManager *m_manager;
+ QHelpProjectFolder *m_filesFolder;
+ QString m_projectFile;
+ QString m_name;
+ QStringList m_files;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/plugins/qhelpproject/qhelpproject.pro b/src/plugins/qhelpproject/qhelpproject.pro
new file mode 100644
index 0000000000..667da0009b
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpproject.pro
@@ -0,0 +1,16 @@
+TEMPLATE = lib
+TARGET = QHelpProject
+
+include(../../qworkbenchplugin.pri)
+include(../../../../helpsystem/qhelpsystem.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+
+SOURCES += qhelpprojectmanager.cpp \
+ qhelpproject.cpp \
+ qhelpprojectitems.cpp
+
+
+HEADERS += qhelpprojectmanager.h \
+ qhelpproject.h \
+ qhelpprojectitems.h
+
diff --git a/src/plugins/qhelpproject/qhelpprojectitems.cpp b/src/plugins/qhelpproject/qhelpprojectitems.cpp
new file mode 100644
index 0000000000..9c0d98c2ef
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpprojectitems.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QFileIconProvider>
+
+#include "qhelpprojectitems.h"
+
+using namespace ProjectExplorer;
+using namespace QHelpProjectPlugin::Internal;
+
+QIcon QHelpProjectFile::m_icon = QIcon();
+QIcon QHelpProjectFolder::m_icon = QIcon();
+
+QHelpProjectFile::QHelpProjectFile(const QString &fileName)
+{
+ m_file = fileName;
+
+ if (m_icon.isNull()) {
+ QFileIconProvider iconProvider;
+ m_icon = iconProvider.icon(QFileIconProvider::File);
+ }
+}
+
+QString QHelpProjectFile::fullName() const
+{
+ return m_file;
+}
+
+ProjectItemInterface::ProjectItemKind QHelpProjectFile::kind() const
+{
+ return ProjectItemInterface::ProjectFile;
+}
+
+QString QHelpProjectFile::name() const
+{
+ QFileInfo fi(m_file);
+ return fi.fileName();
+}
+
+QIcon QHelpProjectFile::icon() const
+{
+ return m_icon;
+}
+
+
+
+QHelpProjectFolder::QHelpProjectFolder()
+{
+ if (m_icon.isNull()) {
+ QFileIconProvider iconProvider;
+ m_icon = iconProvider.icon(QFileIconProvider::Folder);
+ }
+}
+
+QHelpProjectFolder::~QHelpProjectFolder()
+{
+}
+
+void QHelpProjectFolder::setName(const QString &name)
+{
+ m_name = name;
+}
+
+ProjectItemInterface::ProjectItemKind QHelpProjectFolder::kind() const
+{
+ return ProjectItemInterface::ProjectFolder;
+}
+
+QString QHelpProjectFolder::name() const
+{
+ return m_name;
+}
+
+QIcon QHelpProjectFolder::icon() const
+{
+ return m_icon;
+}
diff --git a/src/plugins/qhelpproject/qhelpprojectitems.h b/src/plugins/qhelpproject/qhelpprojectitems.h
new file mode 100644
index 0000000000..dc32c990ae
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpprojectitems.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QHELPPROJECTITEMS_H
+#define QHELPPROJECTITEMS_H
+
+#include <QtGui/QIcon>
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+namespace QHelpProjectPlugin {
+namespace Internal {
+
+class QHelpProjectFile : public QObject,
+ public ProjectExplorer::ProjectFileInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ProjectExplorer::ProjectFileInterface ProjectExplorer::ProjectItemInterface)
+
+public:
+ QHelpProjectFile(const QString &fileName);
+ QString fullName() const;
+
+ //ProjectExplorer::ProjectItemInterface
+ ProjectItemKind kind() const;
+
+ QString name() const;
+ QIcon icon() const;
+
+private:
+ QString m_file;
+ static QIcon m_icon;
+};
+
+class QHelpProjectFolder : public QObject,
+ public ProjectExplorer::ProjectFolderInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ProjectExplorer::ProjectFolderInterface ProjectExplorer::ProjectItemInterface)
+
+public:
+ QHelpProjectFolder();
+ ~QHelpProjectFolder();
+
+ void setName(const QString &name);
+
+ //ProjectExplorer::ProjectItemInterface
+ ProjectItemKind kind() const;
+
+ QString name() const;
+ QIcon icon() const;
+
+private:
+ QString m_name;
+ static QIcon m_icon;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/plugins/qhelpproject/qhelpprojectmanager.cpp b/src/plugins/qhelpproject/qhelpprojectmanager.cpp
new file mode 100644
index 0000000000..4878c7cdda
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpprojectmanager.cpp
@@ -0,0 +1,121 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qhelpprojectmanager.h"
+#include "qhelpproject.h"
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+using namespace QHelpProjectPlugin::Internal;
+
+QHelpProjectManager::QHelpProjectManager()
+{
+}
+
+QHelpProjectManager::~QHelpProjectManager()
+{
+}
+
+bool QHelpProjectManager::init(ExtensionSystem::PluginManager *pm, QString *error_message)
+{
+ m_pm = pm;
+ m_core = m_pm->interface<QWorkbench::ICore>();
+ QWorkbench::ActionManagerInterface *am = m_core->actionManager();
+
+ m_projectContext = m_core->uniqueIDManager()->
+ uniqueIdentifier(QLatin1String("QHelpProject"));
+
+ m_languageId = m_core->uniqueIDManager()->
+ uniqueIdentifier(QLatin1String("QHelpLanguage"));
+
+ m_projectExplorer = m_pm->interface<ProjectExplorer::ProjectExplorerInterface>();
+
+ return true;
+}
+
+void QHelpProjectManager::extensionsInitialized()
+{
+}
+
+void QHelpProjectManager::cleanup()
+{
+}
+
+int QHelpProjectManager::projectContext() const
+{
+ return m_projectContext;
+}
+
+int QHelpProjectManager::projectLanguage() const
+{
+ return m_languageId;
+}
+
+bool QHelpProjectManager::canOpen(const QString &fileName)
+{
+ qDebug() << "can open " << fileName;
+ QFileInfo fi(fileName);
+ if (fi.suffix() == QLatin1String("qthp"))
+ return true;
+ return false;
+}
+
+QList<ProjectExplorer::Project*> QHelpProjectManager::open(const QString &fileName)
+{
+ QList<ProjectExplorer::Project*> lst;
+ QHelpProject *pro = new QHelpProject(this);
+ if (pro->open(fileName)) {
+ lst.append(pro);
+ } else {
+ delete pro;
+ }
+ return lst;
+}
+
+QString QHelpProjectManager::fileFilter() const
+{
+ return tr("Qt Help Project File (*.qthp)");
+}
+
+QVariant QHelpProjectManager::editorProperty(const QString &key) const
+{
+ return QVariant();
+}
+
+ProjectExplorer::ProjectExplorerInterface *QHelpProjectManager::projectExplorer() const
+{
+ return m_projectExplorer;
+}
+
+Q_EXPORT_PLUGIN(QHelpProjectManager)
diff --git a/src/plugins/qhelpproject/qhelpprojectmanager.h b/src/plugins/qhelpproject/qhelpprojectmanager.h
new file mode 100644
index 0000000000..b3eed263dc
--- /dev/null
+++ b/src/plugins/qhelpproject/qhelpprojectmanager.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QHELPPROJECTMANAGER_H
+#define QHELPPROJECTMANAGER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+
+#include <extensionsystem/plugininterface.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+namespace Core {
+class ICore;
+}
+
+namespace QHelpProjectPlugin {
+namespace Internal {
+
+class QHelpProjectManager : public QObject,
+ public ExtensionSystem::PluginInterface,
+ public ProjectExplorer::IProjectManager
+{
+ Q_OBJECT
+ Q_CLASSINFO("RequiredPlugin", "ProjectExplorer")
+ Q_INTERFACES(ExtensionSystem::PluginInterface
+ ProjectExplorer::IProjectManager)
+
+public:
+ QHelpProjectManager();
+ ~QHelpProjectManager();
+
+ bool init(ExtensionSystem::PluginManager *pm, QString *error_message = 0);
+ void extensionsInitialized();
+ void cleanup();
+
+ int projectContext() const;
+ int projectLanguage() const;
+
+ bool canOpen(const QString &fileName);
+ QList<ProjectExplorer::ProjectInterface*> open(const QString &fileName);
+ QString fileFilter() const;
+
+ QVariant editorProperty(const QString &key) const;
+
+ ProjectExplorer::ProjectExplorerInterface *projectExplorer() const;
+
+private:
+ ExtensionSystem::PluginManager *m_pm;
+ QWorkbench::ICore *m_core;
+ ProjectExplorer::ProjectExplorerInterface *m_projectExplorer;
+
+ int m_projectContext;
+ int m_languageId;
+};
+
+} // namespace Internal
+} // namespace QHelpProjectPlugin
+
+#endif // QHELPPROJECTMANAGER_H
diff --git a/src/plugins/qt4projectmanager/Qt4ProjectManager.mimetypes.xml b/src/plugins/qt4projectmanager/Qt4ProjectManager.mimetypes.xml
new file mode 100644
index 0000000000..7fa148c881
--- /dev/null
+++ b/src/plugins/qt4projectmanager/Qt4ProjectManager.mimetypes.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/vnd.nokia.qt.qmakeprofile">
+ <sub-class-of type="text/plain"/>
+ <comment>Qt Project file</comment>
+ <glob pattern="*.pro"/>
+ </mime-type>
+ <mime-type type="application/vnd.nokia.qt.qmakeproincludefile">
+ <sub-class-of type="text/plain"/>
+ <comment>Qt Project include file</comment>
+ <glob pattern="*.pri"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/qt4projectmanager/Qt4ProjectManager.pluginspec b/src/plugins/qt4projectmanager/Qt4ProjectManager.pluginspec
new file mode 100644
index 0000000000..8e16623886
--- /dev/null
+++ b/src/plugins/qt4projectmanager/Qt4ProjectManager.pluginspec
@@ -0,0 +1,14 @@
+<plugin name="Qt4ProjectManager" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Provides project type for Qt 4 pro files and tools.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="CppTools" version="0.9.1"/>
+ <dependency name="CppEditor" version="0.9.1"/>
+ <dependency name="Help" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/qt4projectmanager/applicationlauncher.h b/src/plugins/qt4projectmanager/applicationlauncher.h
new file mode 100644
index 0000000000..e48bcb99a7
--- /dev/null
+++ b/src/plugins/qt4projectmanager/applicationlauncher.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef APPLICATIONLAUNCHER_H
+#define APPLICATIONLAUNCHER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QProcess>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ConsoleProcess;
+class WinGuiProcess;
+
+class ApplicationLauncher : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Mode {Console, Gui};
+ ApplicationLauncher(QObject *parent);
+ void setWorkingDirectory(const QString &dir);
+ void setEnvironment(const QStringList &env);
+
+ void start(Mode mode, const QString &program,
+ const QStringList &args = QStringList());
+ bool isRunning() const;
+ qint64 applicationPID() const;
+
+signals:
+ void applicationError(const QString &error);
+ void appendOutput(const QString &error);
+ void processExited(int exitCode);
+
+private slots:
+ void processStopped();
+#ifdef Q_OS_WIN
+ void readWinDebugOutput(const QString &output);
+ void processFinished(int exitCode);
+#else
+ void guiProcessError();
+ void readStandardOutput();
+ void processDone(int, QProcess::ExitStatus);
+#endif
+
+private:
+ QProcess *m_guiProcess;
+ ConsoleProcess *m_consoleProcess;
+ Mode m_currentMode;
+
+ WinGuiProcess *m_winGuiProcess;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif // APPLICATIONLAUNCHER_H
diff --git a/src/plugins/qt4projectmanager/buildoptionspage.cpp b/src/plugins/qt4projectmanager/buildoptionspage.cpp
new file mode 100644
index 0000000000..1dcc096151
--- /dev/null
+++ b/src/plugins/qt4projectmanager/buildoptionspage.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QSettings>
+#include <QtGui/QLineEdit>
+
+#include "buildoptionspage.h"
+
+BuildOptionsPage::BuildOptionsPage(QWorkbench::PluginManager *app)
+{
+ core = app;
+ QWorkbench::ICore *coreIFace = core->interface<QWorkbench::ICore>();
+ if (coreIFace && coreIFace->settings()) {
+ QSettings *s = coreIFace->settings();
+ s->beginGroup("BuildOptions");
+ m_qmakeCmd = s->value("QMake", "qmake").toString();
+ m_makeCmd = s->value("Make", "make").toString();
+ m_makeCleanCmd = s->value("MakeClean", "make clean").toString();
+ s->endGroup();
+ }
+}
+
+QString BuildOptionsPage::name() const
+{
+ return tr("Commands");
+}
+
+QString BuildOptionsPage::category() const
+{
+ return "Qt4|Build";
+}
+
+QString BuildOptionsPage::trCategory() const
+{
+ return tr("Qt4|Build");
+}
+
+QWidget *BuildOptionsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+ m_ui.qmakeLineEdit->setText(m_qmakeCmd);
+ m_ui.makeLineEdit->setText(m_makeCmd);
+ m_ui.makeCleanLineEdit->setText(m_makeCleanCmd);
+
+ return w;
+}
+
+void BuildOptionsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_qmakeCmd = m_ui.qmakeLineEdit->text();
+ m_makeCmd = m_ui.makeLineEdit->text();
+ m_makeCleanCmd = m_ui.makeCleanLineEdit->text();
+ QWorkbench::ICore *coreIFace = core->interface<QWorkbench::ICore>();
+ if (coreIFace && coreIFace->settings()) {
+ QSettings *s = coreIFace->settings();
+ s->beginGroup("BuildOptions");
+ s->setValue("QMake", m_qmakeCmd);
+ s->setValue("Make", m_makeCmd);
+ s->setValue("MakeClean", m_makeCleanCmd);
+ s->endGroup();
+ }
+}
+
+QWorkbench::Plugin *BuildOptionsPage::plugin()
+{
+ return 0;
+}
+
+QObject *BuildOptionsPage::qObject()
+{
+ return this;
+}
diff --git a/src/plugins/qt4projectmanager/buildparserfactory.cpp b/src/plugins/qt4projectmanager/buildparserfactory.cpp
new file mode 100644
index 0000000000..7b839b6606
--- /dev/null
+++ b/src/plugins/qt4projectmanager/buildparserfactory.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "buildparserfactory.h"
+#include "qt4projectmanagerconstants.h"
+#include "gccparser.h"
+#include "msvcparser.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+GccParserFactory::~GccParserFactory()
+{
+
+}
+
+bool GccParserFactory::canCreate(const QString & name) const
+{
+ return (name == Constants::BUILD_PARSER_GCC);
+}
+
+ProjectExplorer::BuildParserInterface * GccParserFactory::create(const QString & name) const
+{
+ Q_UNUSED(name);
+ return new GccParser();
+}
+
+MsvcParserFactory::~MsvcParserFactory()
+{
+
+}
+
+bool MsvcParserFactory::canCreate(const QString & name) const
+{
+ return (name == Constants::BUILD_PARSER_MSVC);
+}
+
+ProjectExplorer::BuildParserInterface * MsvcParserFactory::create(const QString & name) const
+{
+ Q_UNUSED(name);
+ return new MsvcParser();
+}
diff --git a/src/plugins/qt4projectmanager/buildparserfactory.h b/src/plugins/qt4projectmanager/buildparserfactory.h
new file mode 100644
index 0000000000..685e86fbab
--- /dev/null
+++ b/src/plugins/qt4projectmanager/buildparserfactory.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BUILDPARSERFACTORY_H
+#define BUILDPARSERFACTORY_H
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+
+namespace ProjectExplorer {
+class BuildParserInterface;
+}
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class GccParserFactory : public ProjectExplorer::IBuildParserFactory
+{
+ Q_OBJECT
+public:
+ GccParserFactory() {};
+ virtual ~GccParserFactory();
+ virtual bool canCreate(const QString & name) const;
+ virtual ProjectExplorer::BuildParserInterface * create(const QString & name) const;
+};
+
+class MsvcParserFactory : public ProjectExplorer::IBuildParserFactory
+{
+ Q_OBJECT
+public:
+ MsvcParserFactory() {};
+ virtual ~MsvcParserFactory();
+ virtual bool canCreate(const QString & name) const;
+ virtual ProjectExplorer::BuildParserInterface * create(const QString & name) const;
+};
+
+}
+}
+
+#endif
diff --git a/src/plugins/qt4projectmanager/cesdkhandler.cpp b/src/plugins/qt4projectmanager/cesdkhandler.cpp
new file mode 100644
index 0000000000..de42c5d2f0
--- /dev/null
+++ b/src/plugins/qt4projectmanager/cesdkhandler.cpp
@@ -0,0 +1,153 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cesdkhandler.h"
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+#include <QtCore/QXmlStreamReader>
+
+using namespace Qt4ProjectManager::Internal;
+using ProjectExplorer::Environment;
+
+CeSdkInfo::CeSdkInfo() : m_major(0) , m_minor(0)
+{
+}
+
+Environment CeSdkInfo::addToEnvironment(const Environment &env)
+{
+ qDebug()<<"adding "<<name()<< "to Environment";
+ Environment e(env);
+ e.set("INCLUDE", m_include);
+ e.set("LIB", m_lib);
+ e.prependOrSetPath(m_bin);
+ qDebug()<<e.toStringList();
+ return e;
+}
+
+CeSdkHandler::CeSdkHandler()
+{
+}
+
+QString CeSdkHandler::platformName(const QString &qtpath)
+{
+ QString platformName;
+ QString CE_SDK;
+ QString CE_ARCH;
+ QFile f(qtpath);
+ if(f.exists() && f.open(QIODevice::ReadOnly)) {
+ while(!f.atEnd()) {
+ QByteArray line = f.readLine();
+ if(line.startsWith("CE_SDK")) {
+ int index = line.indexOf('=');
+ if(index >= 0) {
+ CE_SDK = line.mid(index + 1).trimmed();
+ }
+ } else if(line.startsWith("CE_ARCH")) {
+ int index = line.indexOf('=');
+ if(index >= 0) {
+ CE_ARCH = line.mid(index + 1).trimmed();
+ }
+ }
+ if(!CE_SDK.isEmpty() && !CE_ARCH.isEmpty()) {
+ platformName = CE_SDK + " (" + CE_ARCH + ")";
+ break;
+ }
+ }
+ }
+ return platformName;
+}
+
+bool CeSdkHandler::parse(const QString &vsdir)
+{
+ // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config
+ // and scan through all installed sdks...
+ m_list.clear();
+
+ VCInstallDir = vsdir + "/VC/";
+ VSInstallDir = vsdir;
+
+ QDir vStudioDir(VCInstallDir);
+ if (!vStudioDir.cd("vcpackages"))
+ return false;
+
+ QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config")));
+ qDebug()<<"##";
+ if (!configFile.exists() || !configFile.open(QIODevice::ReadOnly))
+ return false;
+
+ qDebug()<<"parsing";
+
+ QString currentElement;
+ CeSdkInfo currentItem;
+ QXmlStreamReader xml(&configFile);
+ while (!xml.atEnd()) {
+ xml.readNext();
+ if (xml.isStartElement()) {
+ currentElement = xml.name().toString();
+ if (currentElement == QLatin1String("Platform"))
+ currentItem = CeSdkInfo();
+ else if (currentElement == QLatin1String("Directories")) {
+ QXmlStreamAttributes attr = xml.attributes();
+ currentItem.m_include = fixPaths(attr.value(QLatin1String("Include")).toString());
+ currentItem.m_lib = fixPaths(attr.value(QLatin1String("Library")).toString());
+ currentItem.m_bin = fixPaths(attr.value(QLatin1String("Path")).toString());
+ }
+ } else if (xml.isEndElement()) {
+ if (xml.name().toString() == QLatin1String("Platform"))
+ m_list.append(currentItem);
+ } else if (xml.isCharacters() && !xml.isWhitespace()) {
+ if (currentElement == QLatin1String("PlatformName"))
+ currentItem.m_name = xml.text().toString();
+ else if (currentElement == QLatin1String("OSMajorVersion"))
+ currentItem.m_major = xml.text().toString().toInt();
+ else if (currentElement == QLatin1String("OSMinorVersion"))
+ currentItem.m_minor = xml.text().toString().toInt();
+ }
+ }
+
+ if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
+ qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
+ return false;
+ }
+ return m_list.size() > 0 ? true : false;
+}
+
+CeSdkInfo CeSdkHandler::find(const QString &name)
+{
+ qDebug()<<"looking for platform "<<name;
+ for (QList<CeSdkInfo>::iterator it = m_list.begin(); it != m_list.end(); ++it) {
+ qDebug()<<"...."<<it->name();
+ if (it->name() == name)
+ return *it;
+ }
+ return CeSdkInfo();
+}
diff --git a/src/plugins/qt4projectmanager/cesdkhandler.h b/src/plugins/qt4projectmanager/cesdkhandler.h
new file mode 100644
index 0000000000..88d3bdb470
--- /dev/null
+++ b/src/plugins/qt4projectmanager/cesdkhandler.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CE_SDK_HANDLER_INCL
+#define CE_SDK_HANDLER_INCL
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+#include <QStringList>
+#include <QDir>
+
+#define VCINSTALL_MACRO "$(VCInstallDir)"
+#define VSINSTALL_MACRO "$(VSInstallDir)"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class CeSdkInfo
+{
+public:
+ CeSdkInfo();
+ inline QString name();
+ inline QString binPath();
+ inline QString includePath();
+ inline QString libPath();
+ ProjectExplorer::Environment addToEnvironment(const ProjectExplorer::Environment &env);
+ inline bool isValid();
+ inline int majorVersion();
+ inline int minorVersion();
+ inline bool isSupported();
+private:
+ friend class CeSdkHandler;
+ QString m_name;
+ QString m_bin;
+ QString m_include;
+ QString m_lib;
+ int m_major;
+ int m_minor;
+};
+
+inline QString CeSdkInfo::name(){ return m_name; }
+inline QString CeSdkInfo::binPath(){ return m_bin; }
+inline QString CeSdkInfo::includePath(){ return m_include; }
+inline QString CeSdkInfo::libPath(){ return m_lib; }
+inline bool CeSdkInfo::isValid(){ return !m_name.isEmpty() && !m_bin.isEmpty() && !m_include.isEmpty() && !m_lib.isEmpty(); }
+inline int CeSdkInfo::majorVersion(){ return m_major; }
+inline int CeSdkInfo::minorVersion(){ return m_minor; }
+inline bool CeSdkInfo::isSupported() { return m_major >= 5; }
+
+class CeSdkHandler
+{
+public:
+ CeSdkHandler();
+ bool parse(const QString &path);
+ inline QList<CeSdkInfo> listAll() const;
+ CeSdkInfo find(const QString &name);
+ static QString platformName(const QString &qtpath);
+private:
+ inline QString fixPaths(QString path) const;
+ QList<CeSdkInfo> m_list;
+ QString VCInstallDir;
+ QString VSInstallDir;
+};
+
+inline QList<CeSdkInfo> CeSdkHandler::listAll() const
+{
+ return m_list;
+}
+
+inline QString CeSdkHandler::fixPaths(QString path) const
+{
+ return QDir::toNativeSeparators(QDir::cleanPath(path.replace(VCINSTALL_MACRO, VCInstallDir).replace(VSINSTALL_MACRO, VSInstallDir).replace(QLatin1String(";$(PATH)"), QLatin1String(""))));
+}
+
+}
+}
+
+#endif
diff --git a/src/plugins/qt4projectmanager/deployhelper.cpp b/src/plugins/qt4projectmanager/deployhelper.cpp
new file mode 100644
index 0000000000..bf1fdf271d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/deployhelper.cpp
@@ -0,0 +1,196 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "deployhelper.h"
+#include "qt4project.h"
+
+#include <QDebug>
+#include <QDir>
+#include <QEventLoop>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+DeployHelperRunStep::DeployHelperRunStep(Qt4Project *pro)
+ : BuildStep(pro), m_started(false), m_pro(pro)
+{
+ QDir workbenchDir = QCoreApplication::applicationDirPath();
+ workbenchDir.cdUp();
+ m_binary = QDir::convertSeparators( workbenchDir.absolutePath() + QLatin1String("/qtembeddedtools/qemudeployer"));
+ m_id = "id";
+
+};
+
+bool DeployHelperRunStep::init(const QString &configuration)
+{
+ Q_UNUSED(configuration);
+ m_qtdir = m_pro->qtDir(configuration);
+ QFileInfo fi(m_pro->file()->fileName());
+ m_appdir = fi.absolutePath();
+ //find target
+ m_exec = "";
+ QStringList targets = QStringList(); //TODO fix m_pro->qmakeTarget();
+ foreach(const QString& target, targets) {
+ QFileInfo fi(m_appdir + QLatin1Char('/') + target);
+ if(fi.exists())
+ m_exec = target;
+ break;
+ }
+ m_skin = m_pro->value("VNCSkin").toString();
+ return true;
+}
+
+void DeployHelperRunStep::run(QFutureInterface<bool> & fi)
+{
+ if (m_id.isNull() || m_binary.isNull()) {
+ fi.reportResult(false);
+ return;
+ }
+ if (m_started)
+ stop();
+
+ QStringList args;
+ args << "start" << "-id"<<m_id<<"-qtdir"<<m_qtdir<<"-appdir"<<m_appdir<<"-exec"<<m_exec;
+ if (!m_skin.isEmpty())
+ args<<"-skin"<<m_skin;
+
+ for (int i=0; i<m_extraargs.count(); ++i)
+ args.append(m_extraargs.at(i));
+
+ QProcess proc;
+ connect(&proc, SIGNAL(finished (int,QProcess::ExitStatus)),
+ this, SLOT(processFinished()), Qt::DirectConnection);
+ connect(&proc, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
+
+ QStringList env = QProcess::systemEnvironment();
+ env.replaceInStrings(QRegExp("^PATH=(.*)", Qt::CaseInsensitive), "PATH="+QApplication::applicationDirPath()+";\\1");
+ proc.setEnvironment(env);
+ proc.setProcessChannelMode(QProcess::MergedChannels);
+ proc.start(m_binary, args);
+ proc.waitForStarted();
+ m_started = true;
+
+ m_eventLoop = new QEventLoop;
+ m_eventLoop->exec();
+ delete m_eventLoop;
+ m_eventLoop = 0;
+ fi.reportResult(true);
+ return;
+}
+
+DeployHelperRunStep::~DeployHelperRunStep()
+{
+ cleanup();
+}
+
+QString DeployHelperRunStep::binary()
+{
+ return m_binary;
+}
+
+QString DeployHelperRunStep::id()
+{
+ return m_id;
+}
+
+bool DeployHelperRunStep::started()
+{
+ return m_started;
+}
+
+void DeployHelperRunStep::processFinished()
+{
+ m_eventLoop->exit(0);
+}
+
+void DeployHelperRunStep::stop()
+{
+ if (m_id.isNull() || m_binary.isNull() || !m_started)
+ return;
+
+ QStringList env = QProcess::systemEnvironment();
+ env.replaceInStrings(QRegExp("^PATH=(.*)", Qt::CaseInsensitive), "PATH="+QApplication::applicationDirPath()+";\\1");
+
+ QStringList args;
+ args<<"stop"<<"-id"<<m_id;
+ QProcess proc;
+ proc.setEnvironment(env);
+ proc.start(m_binary, args);
+ proc.waitForFinished();
+ m_started = false;
+}
+
+void DeployHelperRunStep::cleanup()
+{
+ if (m_id.isNull() || m_binary.isNull() || !m_started)
+ return;
+
+ QStringList env = QProcess::systemEnvironment();
+ env.replaceInStrings(QRegExp("^PATH=(.*)", Qt::CaseInsensitive), "PATH="+QApplication::applicationDirPath()+";\\1");
+
+ QStringList args;
+ args<<"cleanup"<<"-id"<<m_id;
+ QProcess proc;
+ proc.setEnvironment(env);
+ proc.start(m_binary, args);
+ proc.waitForFinished();
+ m_started = false;
+}
+
+void DeployHelperRunStep::readyRead()
+{
+ // TODO Unbreak the application output (this whole thing should be moved to a IRunConfigurationRunner)
+ QProcess * proc = qobject_cast<QProcess *>(sender());
+ while (proc->canReadLine()) {
+ QString line = proc->readLine().trimmed();
+ if (line.startsWith("L:") || line.startsWith("A:")) {
+ //emit addToApplicationOutputWindow(line.mid(2));
+ } else {
+ //emit addToApplicationOutputWindow(line);
+ }
+ }
+}
+
+QString DeployHelperRunStep::name()
+{
+ return "trolltech.qt4projectmanager.deployhelperrunstep";
+}
+
+QString DeployHelperRunStep::displayName()
+{
+ return "Linux emulator";
+}
+
+ProjectExplorer::BuildStepConfigWidget * DeployHelperRunStep::configWidget()
+{
+ return 0;
+}
diff --git a/src/plugins/qt4projectmanager/deployhelper.h b/src/plugins/qt4projectmanager/deployhelper.h
new file mode 100644
index 0000000000..a132ba3486
--- /dev/null
+++ b/src/plugins/qt4projectmanager/deployhelper.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DEPLOYHELPER_H
+#define DEPLOYHELPER_H
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QEventLoop;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+
+class Qt4Project;
+
+namespace Internal {
+
+class DeployHelperRunStep : public ProjectExplorer::BuildStep
+{
+ Q_OBJECT
+public:
+ DeployHelperRunStep(Qt4Project * pro);
+ ~DeployHelperRunStep();
+
+ virtual bool init(const QString &configuration);
+ virtual void run(QFutureInterface<bool> &);
+
+ virtual QString name();
+ virtual QString displayName();
+
+ virtual QString binary();
+ virtual QString id();
+
+ virtual ProjectExplorer::BuildStepConfigWidget *configWidget();
+
+private:
+ bool started();
+
+ void stop();
+ void cleanup();
+
+private slots:
+ void readyRead();
+ void processFinished();
+
+private:
+ QString m_qtdir;
+ QString m_appdir;
+ QString m_exec;
+ QString m_skin;
+ QString m_binary;
+ QStringList m_extraargs;
+ QString m_id;
+ bool m_started;
+ Qt4Project *m_pro;
+ QEventLoop *m_eventLoop;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // DEPLOYHELPER_H
diff --git a/src/plugins/qt4projectmanager/directorywatcher.cpp b/src/plugins/qt4projectmanager/directorywatcher.cpp
new file mode 100644
index 0000000000..61860856a3
--- /dev/null
+++ b/src/plugins/qt4projectmanager/directorywatcher.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "directorywatcher.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QFileSystemWatcher>
+#include <QtCore/QTimer>
+
+enum { debugWatcher = 0 };
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+int DirectoryWatcher::m_objectCount = 0;
+QHash<QString,int> DirectoryWatcher::m_directoryCount;
+QFileSystemWatcher *DirectoryWatcher::m_watcher = 0;
+
+/*
+ \class DirectoryWatcher
+
+ A wrapper for QFileSystemWatcher that collects
+ consecutive changes to a registered directory and emits directoryChanged() and fileChanged().
+
+ Note that files added are only monitored if the parent directory is added, too.
+
+ All instances of DirectoryWatcher share one QFileSystemWatcher object.
+ That's because every QFileSystemWatcher object consumes a file descriptor,
+ even if no files are watched.
+*/
+DirectoryWatcher::DirectoryWatcher(QObject *parent) :
+ QObject(parent),
+ m_timer(0)
+{
+ if (!m_watcher)
+ m_watcher = new QFileSystemWatcher();
+ ++m_objectCount;
+ connect(m_watcher, SIGNAL(directoryChanged(QString)),
+ this, SLOT(slotDirectoryChanged(QString)));
+}
+
+DirectoryWatcher::~DirectoryWatcher()
+{
+ foreach (const QString &dir, m_directories)
+ removeDirectory(dir);
+ if (--m_objectCount == 0) {
+ delete m_watcher;
+ m_watcher = 0;
+ }
+}
+
+QStringList DirectoryWatcher::directories() const
+{
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << m_directories;
+ return m_directories;
+}
+
+void DirectoryWatcher::addDirectory(const QString &dir)
+{
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << dir;
+ if (m_directories.contains(dir))
+ return;
+ m_directories += dir;
+ if (m_directoryCount[dir] == 0)
+ m_watcher->addPath(dir);
+ m_directoryCount[dir] += 1;
+}
+
+void DirectoryWatcher::removeDirectory(const QString &dir)
+{
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << dir;
+ m_directories.removeOne(dir);
+ m_directoryCount[dir] -= 1;
+ if (m_directoryCount[dir] == 0)
+ m_watcher->removePath(dir);
+}
+
+QStringList DirectoryWatcher::files() const
+{
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << m_files.keys();
+ return m_files.keys();
+}
+
+void DirectoryWatcher::addFile(const QString &filePath)
+{
+ addFiles(QStringList() << filePath);
+}
+
+void DirectoryWatcher::addFiles(const QStringList &filePaths)
+{
+ foreach (const QString filePath, filePaths) {
+ QFileInfo file(filePath);
+ m_files.insert(file.absoluteFilePath(),file.lastModified());
+ }
+}
+
+void DirectoryWatcher::removeFile(const QString &filePath)
+{
+ m_files.remove(filePath);
+}
+
+void DirectoryWatcher::slotDirectoryChanged(const QString &path)
+{
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << path;
+ if (!m_directories.contains(path)
+ || m_pendingDirectories.contains(path))
+ return;
+
+ if (!m_timer) {
+ m_timer = new QTimer(this);
+ m_timer->setSingleShot(true);
+ m_timer->setInterval(500); // delay for 0.5 sec
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(slotDelayedDirectoriesChanged()));
+ }
+ if (!m_timer->isActive())
+ m_timer->start();
+ m_pendingDirectories.push_back(path);
+}
+
+void DirectoryWatcher::slotDelayedDirectoriesChanged()
+{
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << " emitting " << m_pendingDirectories;
+ const QStringList::const_iterator cend = m_pendingDirectories.constEnd();
+ for (QStringList::const_iterator it = m_pendingDirectories.constBegin(); it != cend; ++it) {
+ const QString dir = *it;
+ if (!QFileInfo(dir).exists())
+ removeDirectory(*it);
+ emit directoryChanged(*it);
+ updateFileList(*it);
+ }
+ m_pendingDirectories.clear();
+}
+
+void DirectoryWatcher::updateFileList(const QString &dir)
+{
+ const QStringList monitoredFiles = m_files.keys();
+ QStringList removedFiles = monitoredFiles;
+ if (QFileInfo(dir).exists()) {
+ // Compare directory contents and emit signals
+ QFileInfoList entryInfoList
+ = QDir(dir).entryInfoList(QDir::Files|QDir::CaseSensitive);
+ // Loop over directory creating the new map of file->time, removing
+ // the existing entries from the old map
+ const QFileInfoList::const_iterator cend = entryInfoList.constEnd();
+ for (QFileInfoList::const_iterator filIt = entryInfoList.constBegin();
+ filIt != cend; ++filIt) {
+ const QString path = filIt->absoluteFilePath();
+ FileModificationTimeMap::iterator mapIt = m_files.find(path);
+ if (mapIt != m_files.end()) {
+ const QDateTime lastModified = filIt->lastModified();
+ if (lastModified > mapIt.value()) {
+ if (debugWatcher)
+ qDebug() << Q_FUNC_INFO << "emitting file changed" << path;
+ emit fileChanged(path);
+ m_files[path] = lastModified;
+ }
+ removedFiles.removeOne(path);
+ }
+ }
+ }
+
+ if (!removedFiles.isEmpty()) {
+ foreach (const QString &file, removedFiles)
+ removeFile(file);
+ }
+}
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/directorywatcher.h b/src/plugins/qt4projectmanager/directorywatcher.h
new file mode 100644
index 0000000000..bde27794fe
--- /dev/null
+++ b/src/plugins/qt4projectmanager/directorywatcher.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DIRECTORYWATCHER
+#define DIRECTORYWATCHER
+
+#include <QtCore/QDateTime>
+#include <QtCore/QHash>
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+class QFileSystemWatcher;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class DirectoryWatcher : public QObject
+{
+ Q_DISABLE_COPY(DirectoryWatcher)
+ Q_OBJECT
+public:
+ explicit DirectoryWatcher(QObject *parent = 0);
+ virtual ~DirectoryWatcher();
+
+ QStringList directories() const;
+ void addDirectory(const QString &dir);
+ void removeDirectory(const QString &dir);
+
+ QStringList files() const;
+ void addFile(const QString &filePath);
+ void addFiles(const QStringList &filePaths);
+ void removeFile(const QString &filePath);
+
+signals:
+ void directoryChanged(const QString &path);
+ void fileChanged(const QString &path);
+
+private slots:
+ void slotDirectoryChanged(const QString &);
+ void slotDelayedDirectoriesChanged();
+
+private:
+ void updateFileList(const QString &dir);
+
+ static int m_objectCount;
+ static QHash<QString,int> m_directoryCount;
+ static QFileSystemWatcher *m_watcher;
+
+ QTimer *m_timer;
+ QStringList m_directories;
+ QStringList m_pendingDirectories;
+
+ typedef QHash<QString, QDateTime> FileModificationTimeMap;
+ FileModificationTimeMap m_files;
+};
+
+}
+} //namespace Qt4ProjectManager
+
+#endif
diff --git a/src/plugins/qt4projectmanager/embeddedpropertiespage.cpp b/src/plugins/qt4projectmanager/embeddedpropertiespage.cpp
new file mode 100644
index 0000000000..9a0d16264a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/embeddedpropertiespage.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "embeddedpropertiespage.h"
+#include "qt4project.h"
+
+#include <QFileInfo>
+#include <QDir>
+
+using namespace ProjectExplorer;
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+///
+/// EmbeddedPropertiesPanelFactory
+///
+
+bool EmbeddedPropertiesPanelFactory::supports(Project *project)
+{
+#ifdef Q_OS_WIN
+ Qt4Project *pro = qobject_cast<Qt4Project *>(project);
+ if (pro) {
+ return true;
+ }
+#else
+ Q_UNUSED(project);
+#endif
+ return false;
+}
+
+ProjectExplorer::PropertiesPanel *EmbeddedPropertiesPanelFactory::createPanel(
+ ProjectExplorer::Project *project)
+{
+ return new EmbeddedPropertiesPanel(project);
+}
+
+///
+/// EmbeddedPropertiesPanel
+///
+
+EmbeddedPropertiesPanel::EmbeddedPropertiesPanel(ProjectExplorer::Project *project)
+ : PropertiesPanel(),
+ m_widget(new EmbeddedPropertiesWidget(project))
+{
+}
+
+EmbeddedPropertiesPanel::~EmbeddedPropertiesPanel()
+{
+ delete m_widget;
+}
+
+QString EmbeddedPropertiesPanel::name() const
+{
+ return tr("Embedded Linux");
+
+}
+
+QWidget *EmbeddedPropertiesPanel::widget()
+{
+ return m_widget;
+}
+
+///
+/// EmbeddedPropertiesWidget
+///
+
+EmbeddedPropertiesWidget::EmbeddedPropertiesWidget(ProjectExplorer::Project *project)
+ : QWidget()
+{
+ m_ui.setupUi(this);
+
+#ifdef Q_OS_WIN
+ m_ui.virtualBoxCheckbox->setChecked(project->value("useVBOX").toBool());
+
+ // Find all skins
+ QString skin = QFileInfo(project->value("VNCSkin").toString()).fileName();
+ QStringList skins;
+
+ QDir skinDir = QApplication::applicationDirPath();
+ skinDir.cdUp();
+ if (skinDir.cd("qtembeddedtools") && skinDir.cd("qsimplevnc")) {
+ skins = skinDir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
+ }
+ m_ui.skinComboBox->clear();
+ m_ui.skinComboBox->addItems(skins);
+ if (!skin.isEmpty()) {
+ int index = m_ui.skinComboBox->findText(skin);
+ if (index != -1)
+ m_ui.skinComboBox->setCurrentIndex(index);
+ }
+#else
+ Q_UNUSED(project)
+#endif
+ //TODO readd finish code
+ /*
+ project->setValue("useVBOX", m_ui.virtualBoxCheckbox->isChecked());
+
+ //Skin
+ QDir skinDir = QApplication::applicationDirPath();
+ skinDir.cdUp();
+ skinDir.cd("qtembeddedtools");
+ skinDir.cd("qsimplevnc");
+ project->setValue("VNCSkin", skinDir.absolutePath() + "/" + m_ui.skinComboBox->currentText() + "/" + m_ui.skinComboBox->currentText());
+
+ */
+}
+
+EmbeddedPropertiesWidget::~EmbeddedPropertiesWidget()
+{
+}
+
diff --git a/src/plugins/qt4projectmanager/embeddedpropertiespage.h b/src/plugins/qt4projectmanager/embeddedpropertiespage.h
new file mode 100644
index 0000000000..47b3721654
--- /dev/null
+++ b/src/plugins/qt4projectmanager/embeddedpropertiespage.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef EMBEDDEDPROPERTIESPAGE_H
+#define EMBEDDEDPROPERTIESPAGE_H
+
+#include "ui_embeddedpropertiespage.h"
+#include <projectexplorer/iprojectproperties.h>
+#include <QtCore/QModelIndex>
+
+namespace ProjectExplorer {
+class Project;
+}
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+
+class EmbeddedPropertiesWidget;
+
+class EmbeddedPropertiesPanelFactory : public ProjectExplorer::IPanelFactory
+{
+public:
+ virtual bool supports(ProjectExplorer::Project *project);
+ ProjectExplorer::PropertiesPanel *createPanel(ProjectExplorer::Project *project);
+};
+
+class EmbeddedPropertiesPanel : public ProjectExplorer::PropertiesPanel
+{
+ Q_OBJECT
+public:
+ EmbeddedPropertiesPanel(ProjectExplorer::Project *project);
+ ~EmbeddedPropertiesPanel();
+
+ QString name() const;
+ QWidget *widget();
+
+private:
+ EmbeddedPropertiesWidget *m_widget;
+};
+
+class EmbeddedPropertiesWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ EmbeddedPropertiesWidget(ProjectExplorer::Project *project);
+ virtual ~EmbeddedPropertiesWidget();
+ private:
+ Ui_EmbeddedPropertiesPage m_ui;
+ ProjectExplorer::Project *m_pro;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // EMBEDDEDPROPERTIESPAGE_H
diff --git a/src/plugins/qt4projectmanager/embeddedpropertiespage.ui b/src/plugins/qt4projectmanager/embeddedpropertiespage.ui
new file mode 100644
index 0000000000..5f521ed1a3
--- /dev/null
+++ b/src/plugins/qt4projectmanager/embeddedpropertiespage.ui
@@ -0,0 +1,49 @@
+<ui version="4.0" >
+ <class>EmbeddedPropertiesPage</class>
+ <widget class="QWidget" name="EmbeddedPropertiesPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>649</width>
+ <height>302</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <layout class="QFormLayout" name="formLayout" >
+ <property name="fieldGrowthPolicy" >
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QCheckBox" name="virtualBoxCheckbox" >
+ <property name="text" >
+ <string>Use Virtual Box&#xd;
+Note: This adds the toolchain to the build environment and runs the program inside a virtual machine.&#xd;
+It also automatically sets the correct qt version.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="skinLabel" >
+ <property name="text" >
+ <string>Skin:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="skinComboBox" />
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/enveditdialog.ui b/src/plugins/qt4projectmanager/enveditdialog.ui
new file mode 100644
index 0000000000..acda028c17
--- /dev/null
+++ b/src/plugins/qt4projectmanager/enveditdialog.ui
@@ -0,0 +1,236 @@
+<ui version="4.0" >
+ <class>Qt4ProjectManager::Internal::EnvEditDialog</class>
+ <widget class="QDialog" name="Qt4ProjectManager::Internal::EnvEditDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>298</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Build Environment</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="envNameEdit" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Make Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="makeEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Build Environment:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>mkspec:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="mkspecCombo" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="varEdit" />
+ </item>
+ <item row="1" column="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>91</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item rowspan="2" row="0" column="0" colspan="2" >
+ <widget class="QTreeWidget" name="varList" >
+ <property name="uniformRowHeights" >
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable" >
+ <bool>false</bool>
+ </property>
+ <property name="columnCount" >
+ <number>2</number>
+ </property>
+ <column>
+ <property name="text" >
+ <string>0</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="valEdit" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Values:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Variable:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QToolButton" name="addButton" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QToolButton" name="delButton" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="importButton" >
+ <property name="text" >
+ <string>Import</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>91</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>envNameEdit</tabstop>
+ <tabstop>makeEdit</tabstop>
+ <tabstop>mkspecCombo</tabstop>
+ <tabstop>varEdit</tabstop>
+ <tabstop>valEdit</tabstop>
+ <tabstop>delButton</tabstop>
+ <tabstop>addButton</tabstop>
+ <tabstop>varList</tabstop>
+ <tabstop>importButton</tabstop>
+ <tabstop>okButton</tabstop>
+ <tabstop>cancelButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>okButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Qt4ProjectManager::Internal::EnvEditDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>278</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>96</x>
+ <y>254</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Qt4ProjectManager::Internal::EnvEditDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>369</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>179</x>
+ <y>282</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/qt4projectmanager/envvariablespage.ui b/src/plugins/qt4projectmanager/envvariablespage.ui
new file mode 100644
index 0000000000..7d5262b21c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/envvariablespage.ui
@@ -0,0 +1,121 @@
+<ui version="4.0" >
+ <class>Qt4ProjectManager::Internal::EnvVariablesPage</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::EnvVariablesPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>336</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="title" >
+ <string>Build Environments</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="listView" />
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="addButton" >
+ <property name="text" >
+ <string>Add...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editButton" >
+ <property name="text" >
+ <string>Edit...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="delButton" >
+ <property name="text" >
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Default mkspec:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Default make command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="mkspecEdit" />
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="defaultCmdEdit" />
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/gccparser.cpp b/src/plugins/qt4projectmanager/gccparser.cpp
new file mode 100644
index 0000000000..d54d0daa9b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/gccparser.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gccparser.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <QDebug>
+
+using namespace Qt4ProjectManager;
+
+GccParser::GccParser()
+{
+ m_regExp.setPattern("^([^\\(\\)]+[^\\d]):(\\d+):(\\d+:)*(\\s(warning|error):)?(.+)$");
+ m_regExp.setMinimal(true);
+
+ m_regExpIncluded.setPattern("^.*from\\s([^:]+):(\\d+)(,|:)$");
+ m_regExpIncluded.setMinimal(true);
+
+ m_regExpLinker.setPattern("^(\\S+)\\(\\S+\\):(.+)$");
+ m_regExpLinker.setMinimal(true);
+
+ //make[4]: Entering directory `/home/kkoehne/dev/ide-explorer/src/plugins/qtscripteditor'
+ m_makeDir.setPattern("^make.*: (\\w+) directory .(.+).$");
+ m_makeDir.setMinimal(true);
+
+ m_linkIndent = false;
+}
+
+QString GccParser::name() const
+{
+ return QLatin1String(Qt4ProjectManager::Constants::BUILD_PARSER_GCC);
+}
+
+void GccParser::stdOutput(const QString & line)
+{
+ QString lne = line.trimmed();
+
+ if (m_makeDir.indexIn(lne) > -1) {
+ if (m_makeDir.cap(1) == "Leaving")
+ emit leaveDirectory(m_makeDir.cap(2));
+ else
+ emit enterDirectory(m_makeDir.cap(2));
+ }
+}
+
+void GccParser::stdError(const QString & line)
+{
+ QString lne = line.trimmed();
+ if (m_regExp.indexIn(lne) > -1) {
+ ProjectExplorer::BuildParserInterface::PatternType type;
+ if (m_regExp.cap(5) == "warning")
+ type = ProjectExplorer::BuildParserInterface::Warning;
+ else if (m_regExp.cap(5) == "error")
+ type = ProjectExplorer::BuildParserInterface::Error;
+ else
+ type = ProjectExplorer::BuildParserInterface::Unknown;
+
+ QString description = m_regExp.cap(6);
+ if (m_linkIndent)
+ description.prepend(QLatin1String("-> "));
+
+ //qDebug()<<m_regExp.cap(1)<<m_regExp.cap(2)<<m_regExp.cap(3)<<m_regExp.cap(4);
+
+ emit addToTaskWindow(
+ m_regExp.cap(1), //filename
+ type,
+ m_regExp.cap(2).toInt(), //line number
+ description);
+
+ } else if (m_regExpIncluded.indexIn(lne) > -1) {
+ emit addToTaskWindow(
+ m_regExpIncluded.cap(1), //filename
+ ProjectExplorer::BuildParserInterface::Unknown,
+ m_regExpIncluded.cap(2).toInt(), //linenumber
+ lne //description
+ );
+ } else if (m_regExpLinker.indexIn(lne) > -1) {
+ ProjectExplorer::BuildParserInterface::PatternType type = ProjectExplorer::BuildParserInterface::Error;
+ QString description = m_regExpLinker.cap(2);
+ if (lne.endsWith(QLatin1Char(':'))) {
+ m_linkIndent = true;
+ } else if (m_linkIndent) {
+ description.prepend(QLatin1String("-> "));
+ type = ProjectExplorer::BuildParserInterface::Unknown;
+ }
+ emit addToTaskWindow(
+ m_regExpLinker.cap(1), //filename
+ type,
+ -1, //linenumber
+ description);
+ } else if (lne.startsWith(QLatin1String("collect2:"))) {
+ emit addToTaskWindow(
+ "",
+ ProjectExplorer::BuildParserInterface::Error,
+ -1,
+ lne //description
+ );
+ m_linkIndent = false;
+ } else {
+ m_linkIndent = false;
+ }
+}
diff --git a/src/plugins/qt4projectmanager/gccparser.h b/src/plugins/qt4projectmanager/gccparser.h
new file mode 100644
index 0000000000..fea60f7d48
--- /dev/null
+++ b/src/plugins/qt4projectmanager/gccparser.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GCCPARSER
+#define GCCPARSER
+
+#include <QtCore/QRegExp>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+namespace Qt4ProjectManager {
+
+class GccParser : public ProjectExplorer::BuildParserInterface
+{
+ Q_OBJECT
+
+public:
+ GccParser();
+ QString name() const;
+ virtual void stdOutput(const QString & line);
+ virtual void stdError(const QString & line);
+private:
+ QRegExp m_regExp;
+ QRegExp m_regExpIncluded;
+ QRegExp m_regExpLinker;
+ QRegExp m_makeDir;
+ bool m_linkIndent;
+};
+
+} //namespace ProjectExplorer
+
+#endif
diff --git a/src/plugins/qt4projectmanager/gccpreprocessor.cpp b/src/plugins/qt4projectmanager/gccpreprocessor.cpp
new file mode 100644
index 0000000000..81bc464176
--- /dev/null
+++ b/src/plugins/qt4projectmanager/gccpreprocessor.cpp
@@ -0,0 +1,127 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "gccpreprocessor.h"
+#include <QProcess>
+#include <QString>
+#include <QFile>
+#include <QtDebug>
+
+using namespace Qt4ProjectManager::Internal;
+
+GCCPreprocessor::GCCPreprocessor(const QString &gcc)
+ : m_gcc(gcc)
+{ }
+
+GCCPreprocessor::~GCCPreprocessor()
+{ }
+
+void GCCPreprocessor::setGcc(const QString &gcc)
+{
+ if (m_gcc == gcc)
+ return;
+ m_gcc = gcc;
+ m_predefinedMacros.clear();;
+ m_systemHeaderPaths.clear();;
+}
+
+QByteArray GCCPreprocessor::predefinedMacros()
+{
+ if (m_predefinedMacros.isEmpty()) {
+ QStringList arguments;
+ arguments << QLatin1String("-xc++")
+ << QLatin1String("-E")
+ << QLatin1String("-dM")
+ << QLatin1String("-");
+
+ QProcess cpp;
+ cpp.start(m_gcc, arguments);
+ cpp.closeWriteChannel();
+ cpp.waitForFinished();
+ m_predefinedMacros = cpp.readAllStandardOutput();
+ }
+ return m_predefinedMacros;
+}
+
+QList<HeaderPath> GCCPreprocessor::systemHeaderPaths()
+{
+ if (m_systemHeaderPaths.isEmpty()) {
+ QStringList arguments;
+ arguments << QLatin1String("-xc++")
+ << QLatin1String("-E")
+ << QLatin1String("-v")
+ << QLatin1String("-");
+
+ QProcess cpp;
+ cpp.setReadChannelMode(QProcess::MergedChannels);
+ cpp.start(m_gcc, arguments);
+ cpp.closeWriteChannel();
+ cpp.waitForFinished();
+
+ QByteArray line;
+ while (cpp.canReadLine()) {
+ line = cpp.readLine();
+ if (line.startsWith("#include"))
+ break;
+ }
+
+ if (! line.isEmpty() && line.startsWith("#include")) {
+ HeaderPath::Kind kind = HeaderPath::UserHeaderPath;
+ while (cpp.canReadLine()) {
+ line = cpp.readLine();
+ if (line.startsWith("#include")) {
+ kind = HeaderPath::GlobalHeaderPath;
+ } else if (! line.isEmpty() && QChar(line.at(0)).isSpace()) {
+ HeaderPath::Kind thisHeaderKind = kind;
+
+ line = line.trimmed();
+ if (line.endsWith('\n'))
+ line.chop(1);
+
+ int index = line.indexOf(" (framework directory)");
+ if (index != -1) {
+ line = line.left(index);
+ thisHeaderKind = HeaderPath::FrameworkHeaderPath;
+ }
+
+ m_systemHeaderPaths.append(HeaderPath(QFile::decodeName(line), thisHeaderKind));
+ } else if (line.startsWith("End of search list.")) {
+ break;
+ } else {
+ qWarning() << "ignore line:" << line;
+ }
+ }
+ }
+ }
+ return m_systemHeaderPaths;
+}
diff --git a/src/plugins/qt4projectmanager/gccpreprocessor.h b/src/plugins/qt4projectmanager/gccpreprocessor.h
new file mode 100644
index 0000000000..7a2bfb0921
--- /dev/null
+++ b/src/plugins/qt4projectmanager/gccpreprocessor.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GCCPREPROCESSOR_H
+#define GCCPREPROCESSOR_H
+
+#include "headerpath.h"
+#include <QByteArray>
+#include <QList>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class GCCPreprocessor
+{
+public:
+ GCCPreprocessor(const QString &gcc = QLatin1String("g++"));
+ ~GCCPreprocessor();
+
+ void setGcc(const QString &gcc);
+ QByteArray predefinedMacros();
+ QList<HeaderPath> systemHeaderPaths();
+
+private:
+ QString m_gcc;
+ QByteArray m_predefinedMacros;
+ QList<HeaderPath> m_systemHeaderPaths;
+};
+
+} // end of namespace Internal
+} // end of namespace Qt4ProjectManager
+
+#endif // GCCPREPROCESSOR_H
diff --git a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp
new file mode 100644
index 0000000000..ab5dcaeb9a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gdbmacrosbuildstep.h"
+#include "qt4projectmanagerconstants.h"
+#include "qt4project.h"
+#include "qmakestep.h"
+#include "makestep.h"
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+GdbMacrosBuildStep::GdbMacrosBuildStep(Qt4Project *project)
+ : BuildStep(project), m_project(project), m_configWidget(new GdbMacrosBuildStepConfigWidget)
+{
+
+}
+
+GdbMacrosBuildStep::~GdbMacrosBuildStep()
+{
+}
+
+bool GdbMacrosBuildStep::init(const QString &buildConfiguration)
+{
+ m_buildDirectory = m_project->buildDirectory(buildConfiguration);
+ m_qmake = m_project->qtVersion(buildConfiguration)->qmakeCommand();
+ m_buildConfiguration = buildConfiguration;
+ qDebug()<<"m_buildDirectory "<<m_buildDirectory;
+ qDebug()<<"m_qmake "<<m_qmake;
+ return true;
+}
+
+void GdbMacrosBuildStep::run(QFutureInterface<bool> & fi)
+{
+ // TODO CONFIG handling
+
+ QString dumperPath = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()
+ ->resourcePath() + "/gdbmacros/";
+ QStringList files;
+ files << "gdbmacros.cpp"
+ << "gdbmacros.pro";
+
+
+ QString destDir = m_buildDirectory + "/qtc-gdbmacros/";
+ QDir dir;
+ dir.mkpath(destDir);
+ foreach(const QString &file, files) {
+ QFile destination(destDir + file);
+ if (destination.exists())
+ destination.remove();
+ QFile::copy(dumperPath + file, destDir + file);
+ qDebug()<<"copying"<<(dumperPath + file)<<" to "<< (destDir + file);
+ }
+
+ Qt4Project *qt4Project = static_cast<Qt4Project *>(project());
+
+ QProcess qmake;
+ qmake.setEnvironment(qt4Project->environment(m_buildConfiguration).toStringList());
+ qmake.setWorkingDirectory(destDir);
+ QStringList configarguments;
+ QStringList makeArguments;
+
+ // Find qmake step...
+ QMakeStep *qmakeStep = qt4Project->qmakeStep();
+ // Find out which configuration is used in this build configuration
+ // and what kind of CONFIG we need to pass to qmake for that
+ if (qmakeStep->value(m_buildConfiguration, "buildConfiguration").isValid()) {
+ QtVersion::QmakeBuildConfig defaultBuildConfiguration = qt4Project->qtVersion(m_buildConfiguration)->defaultBuildConfig();
+ QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(qmakeStep->value(m_buildConfiguration, "buildConfiguration").toInt());
+ if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll))
+ configarguments << "CONFIG-=debug_and_release";
+ if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll))
+ configarguments << "CONFIG+=debug_and_release";
+ if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild))
+ configarguments << "CONFIG+=release";
+ if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild))
+ configarguments << "CONFIG+=debug";
+ if (projectBuildConfiguration & QtVersion::BuildAll)
+ makeArguments << (projectBuildConfiguration & QtVersion::DebugBuild ? "debug" : "release");
+
+ } else {
+ // Old style with CONFIG+=debug_and_release
+ qDebug() << "OLD STYLE CONF";
+ configarguments << "CONFIG+=debug_and_release";
+ const MakeStep *ms = qt4Project->makeStep();
+ QStringList makeargs = ms->value(m_buildConfiguration, "makeargs").toStringList();
+ if (makeargs.contains("debug")) {
+ makeArguments << "debug";
+ } else if(makeargs.contains("release")) {
+ makeArguments << "release";
+ }
+ }
+
+ QString mkspec = qt4Project->qtVersion(m_buildConfiguration)->mkspec();
+ qmake.start(m_qmake, QStringList()<<"-spec"<<mkspec<<configarguments<<"gdbmacros.pro");
+ qmake.waitForFinished();
+ qDebug()<<qmake.readAllStandardError()<<qmake.readAllStandardOutput();
+
+ qmake.start(qt4Project->qtVersion(m_buildConfiguration)->makeCommand(), makeArguments);
+ qmake.waitForFinished();
+ qDebug()<<qmake.readAllStandardError()<<qmake.readAllStandardOutput();
+
+ fi.reportResult(true);
+}
+
+QString GdbMacrosBuildStep::name()
+{
+ return Constants::GDBMACROSBUILDSTEP;
+}
+
+QString GdbMacrosBuildStep::displayName()
+{
+ return "Gdb Macros Build";
+}
+
+ProjectExplorer::BuildStepConfigWidget *GdbMacrosBuildStep::createConfigWidget()
+{
+ return new GdbMacrosBuildStepConfigWidget;
+}
+
+bool GdbMacrosBuildStep::immutable() const
+{
+ return false;
+}
+
+bool GdbMacrosBuildStepFactory::canCreate(const QString &name) const
+{
+ return name == Constants::GDBMACROSBUILDSTEP;
+}
+
+ProjectExplorer::BuildStep *GdbMacrosBuildStepFactory::create(ProjectExplorer::Project *pro, const QString &name) const
+{
+ Q_ASSERT(name == Constants::GDBMACROSBUILDSTEP);
+ Qt4Project *qt4project = qobject_cast<Qt4Project *>(pro);
+ Q_ASSERT(qt4project);
+ return new GdbMacrosBuildStep(qt4project);
+}
+
+QStringList GdbMacrosBuildStepFactory::canCreateForProject(ProjectExplorer::Project *pro) const
+{
+ QStringList results;
+ if (qobject_cast<QObject *>(pro))
+ results << Constants::GDBMACROSBUILDSTEP;
+ return results;
+}
+
+QString GdbMacrosBuildStepFactory::displayNameForName(const QString &name) const
+{
+ if (name == Constants::GDBMACROSBUILDSTEP)
+ return "Gdb Macros Build";
+ else
+ return QString::null;
+}
+
+QString GdbMacrosBuildStepConfigWidget::displayName() const
+{
+ return "Gdb Macros Build";
+}
+
+void GdbMacrosBuildStepConfigWidget::init(const QString & /*buildConfiguration*/)
+{
+ // TODO
+}
diff --git a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.h b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.h
new file mode 100644
index 0000000000..d08f0c395b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GDBMACROSBUILDSTEP_H
+#define GDBMACROSBUILDSTEP_H
+
+#include <projectexplorer/buildstep.h>
+
+namespace Qt4ProjectManager {
+class Qt4Project;
+namespace Internal {
+class GdbMacrosBuildStepConfigWidget;
+
+class GdbMacrosBuildStep : public ProjectExplorer::BuildStep
+{
+ Q_OBJECT
+public:
+ GdbMacrosBuildStep(Qt4Project * project);
+ virtual ~GdbMacrosBuildStep();
+ virtual bool init(const QString &buildConfiguration);
+ virtual void run(QFutureInterface<bool> &);
+ virtual QString name();
+ virtual QString displayName();
+ virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
+ virtual bool immutable() const;
+private:
+ Qt4Project *m_project;
+ GdbMacrosBuildStepConfigWidget* m_configWidget;
+ QString m_buildDirectory;
+ QString m_qmake;
+ QString m_buildConfiguration;
+};
+
+class GdbMacrosBuildStepFactory : public ProjectExplorer::IBuildStepFactory
+{
+ Q_OBJECT
+public:
+ virtual bool canCreate(const QString &name) const;
+ virtual ProjectExplorer::BuildStep *create(ProjectExplorer::Project *pro, const QString &name) const;
+ virtual QStringList canCreateForProject(ProjectExplorer::Project *pro) const;
+ virtual QString displayNameForName(const QString &name) const;
+
+};
+
+class GdbMacrosBuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+ virtual QString displayName() const;
+ virtual void init(const QString &buildConfiguration);
+};
+}
+}
+
+#endif // GDBMACROSBUILDSTEP_H
diff --git a/src/plugins/qt4projectmanager/headerpath.h b/src/plugins/qt4projectmanager/headerpath.h
new file mode 100644
index 0000000000..e85f89f157
--- /dev/null
+++ b/src/plugins/qt4projectmanager/headerpath.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HEADERPATH_H
+#define HEADERPATH_H
+
+#include <QString>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class HeaderPath
+{
+public:
+ enum Kind {
+ GlobalHeaderPath,
+ UserHeaderPath,
+ FrameworkHeaderPath
+ };
+
+ HeaderPath()
+ : _kind(GlobalHeaderPath)
+ { }
+
+ HeaderPath(const QString &path, Kind kind)
+ : _path(path), _kind(kind)
+ { }
+
+ QString path() const { return _path; }
+ Kind kind() const { return _kind; }
+
+private:
+ QString _path;
+ Kind _kind;
+};
+
+} // end of namespace Internal
+} // end of namespace Qt4ProjectManager
+
+#endif // HEADERPATH_H
diff --git a/src/plugins/qt4projectmanager/images/qt_project.png b/src/plugins/qt4projectmanager/images/qt_project.png
new file mode 100644
index 0000000000..25133f5f47
--- /dev/null
+++ b/src/plugins/qt4projectmanager/images/qt_project.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/images/run_qmake.png b/src/plugins/qt4projectmanager/images/run_qmake.png
new file mode 100644
index 0000000000..b5aa4345c3
--- /dev/null
+++ b/src/plugins/qt4projectmanager/images/run_qmake.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/images/run_qmake_small.png b/src/plugins/qt4projectmanager/images/run_qmake_small.png
new file mode 100644
index 0000000000..3d732520b1
--- /dev/null
+++ b/src/plugins/qt4projectmanager/images/run_qmake_small.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/images/window.png b/src/plugins/qt4projectmanager/images/window.png
new file mode 100644
index 0000000000..9493e3b1ce
--- /dev/null
+++ b/src/plugins/qt4projectmanager/images/window.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/makestep.cpp b/src/plugins/qt4projectmanager/makestep.cpp
new file mode 100644
index 0000000000..e347a59106
--- /dev/null
+++ b/src/plugins/qt4projectmanager/makestep.cpp
@@ -0,0 +1,315 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "makestep.h"
+#include "qt4project.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <QFileInfo>
+#include <QDir>
+#include <extensionsystem/ExtensionSystemInterfaces>
+
+using ProjectExplorer::IBuildParserFactory;
+using ProjectExplorer::BuildParserInterface;
+using ProjectExplorer::Environment;
+using ExtensionSystem::PluginManager;
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+namespace {
+bool debug = false;
+}
+
+MakeStep::MakeStep(Qt4Project * project)
+ : AbstractProcessStep(project),
+ m_project(project),
+ m_buildParser(0)
+{
+}
+
+MakeStep::~MakeStep()
+{
+ delete m_buildParser;
+ m_buildParser = 0;
+}
+
+ProjectExplorer::BuildParserInterface *MakeStep::buildParser(const QtVersion * const version)
+{
+ QString buildParser;
+ QtVersion::ToolchainType type = version->toolchainType();
+ if( type == QtVersion::MSVC || type == QtVersion::WINCE)
+ buildParser = Constants::BUILD_PARSER_MSVC;
+ else
+ buildParser = Constants::BUILD_PARSER_GCC;
+
+ QList<IBuildParserFactory *> buildParserFactories =
+ ExtensionSystem::PluginManager::instance()->getObjects<ProjectExplorer::IBuildParserFactory>();
+
+ foreach (IBuildParserFactory * factory, buildParserFactories)
+ if (factory->canCreate(buildParser))
+ return factory->create(buildParser);
+ return 0;
+}
+
+bool MakeStep::init(const QString &name)
+{
+ m_buildConfiguration = name;
+ Environment environment = project()->environment(name);
+ setEnvironment(name, environment);
+
+ QString workingDirectory;
+ if (project()->value(name, "useShadowBuild").toBool())
+ workingDirectory = project()->value(name, "buildDirectory").toString();
+ if(workingDirectory.isEmpty())
+ workingDirectory = QFileInfo(project()->file()->fileName()).absolutePath();
+ setWorkingDirectory(name, workingDirectory);
+
+ //NBS only dependency on Qt4Project, we probably simply need a MakeProject from which Qt4Project derives
+ QString makeCmd = qobject_cast<Qt4Project *>(project())->qtVersion(name)->makeCommand();
+ if(!value(name, "makeCmd").toString().isEmpty())
+ makeCmd = value(name, "makeCmd").toString();
+ if (!QFileInfo(makeCmd).isAbsolute()) {
+ // Try to detect command in environment
+ QString tmp = environment.searchInPath(makeCmd);
+ if(tmp == QString::null) {
+ emit addToOutputWindow(tr("<font color=\"#ff0000\">Could not find make command: %1 "\
+ "in the build environment</font>").arg(makeCmd));
+ return false;
+ }
+ makeCmd = tmp;
+ }
+ setCommand(name, makeCmd);
+
+ bool skipMakeClean = false;
+ QStringList args;
+ if (value("clean").isValid() && value("clean").toBool()) {
+ args = QStringList() << "clean";
+ if (!QDir(workingDirectory).exists(QLatin1String("Makefile"))) {
+ skipMakeClean = true;
+ }
+ } else {
+ args = value(name, "makeargs").toStringList();
+ }
+
+ // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
+ // absolute file path
+ // FIXME doing this without the user having a way to override this is rather bad
+ // so we only do it for unix and if the user didn't override the make command
+ // but for now this is the least invasive change
+ QtVersion::ToolchainType t = qobject_cast<Qt4Project *>(project())->qtVersion(name)->toolchainType();
+ if (t != QtVersion::MSVC && t != QtVersion::WINCE) {
+ if (value(name, "makeCmd").toString().isEmpty())
+ args << "-w";
+ }
+
+ setEnabled(name, !skipMakeClean);
+ setArguments(name, args);
+
+ m_openDirectories.clear();
+ addDirectory(workingDirectory);
+
+ delete m_buildParser;
+ m_buildParser = 0;
+
+ m_buildParser = buildParser(qobject_cast<Qt4Project *>(project())->qtVersion(name));
+ if (m_buildParser) {
+ connect(m_buildParser, SIGNAL(addToOutputWindow(const QString &)),
+ this, SIGNAL(addToOutputWindow(const QString &)),
+ Qt::DirectConnection);
+ connect(m_buildParser, SIGNAL(addToTaskWindow(const QString &, int, int, const QString &)),
+ this, SLOT(slotAddToTaskWindow(const QString &, int, int, const QString &)),
+ Qt::DirectConnection);
+ connect(m_buildParser, SIGNAL(enterDirectory(const QString &)),
+ this, SLOT(addDirectory(const QString &)),
+ Qt::DirectConnection);
+ connect(m_buildParser, SIGNAL(leaveDirectory(const QString &)),
+ this, SLOT(removeDirectory(const QString &)),
+ Qt::DirectConnection);
+ }
+
+ return AbstractProcessStep::init(name);
+}
+
+void MakeStep::slotAddToTaskWindow(const QString & fn, int type, int linenumber, const QString & description)
+{
+ QString filePath = fn;
+ if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
+ // We have no save way to decide which file in which subfolder
+ // is meant. Therefore we apply following heuristics:
+ // 1. Search for unique file in directories currently indicated as open by GNU make
+ // (Enter directory xxx, Leave directory xxx...) + current directory
+ // 3. Check if file is unique in whole project
+ // 4. Otherwise give up
+
+ filePath = filePath.trimmed();
+
+ QList<QFileInfo> possibleFiles;
+ foreach (const QString &dir, m_openDirectories) {
+ QFileInfo candidate(dir + QLatin1Char('/') + filePath);
+ if (debug)
+ qDebug() << "Checking path " << candidate.filePath();
+ if (candidate.exists()
+ && !possibleFiles.contains(candidate)) {
+ if (debug)
+ qDebug() << candidate.filePath() << "exists!";
+ possibleFiles << candidate;
+ }
+ }
+ if (possibleFiles.count() == 0) {
+ if (debug)
+ qDebug() << "No success. Trying all files in project ...";
+ QString fileName = QFileInfo(filePath).fileName();
+ foreach (const QString &file, m_project->files(ProjectExplorer::Project::AllFiles)) {
+ QFileInfo candidate(file);
+ if (candidate.fileName() == fileName) {
+ if (debug)
+ qDebug() << "Found " << file;
+ possibleFiles << candidate;
+ }
+ }
+ }
+ if (possibleFiles.count() == 1)
+ filePath = possibleFiles.first().filePath();
+ else
+ qWarning() << "Could not find absolute location of file " << filePath;
+ }
+ emit addToTaskWindow(filePath, type, linenumber, description);
+}
+
+void MakeStep::addDirectory(const QString &dir)
+{
+ if (!m_openDirectories.contains(dir))
+ m_openDirectories.insert(dir);
+}
+
+void MakeStep::removeDirectory(const QString &dir)
+{
+ if (m_openDirectories.contains(dir))
+ m_openDirectories.remove(dir);
+}
+
+void MakeStep::run(QFutureInterface<bool> & fi)
+{
+ if (qobject_cast<Qt4Project *>(project())->rootProjectNode()->projectType() == ScriptTemplate) {
+ fi.reportResult(true);
+ return;
+ }
+
+ if (!enabled(m_buildConfiguration)) {
+ emit addToOutputWindow(tr("<font color=\"#0000ff\"><b>No Makefile found, assuming project is clean.</b></font>"));
+ fi.reportResult(true);
+ return;
+ }
+
+ AbstractProcessStep::run(fi);
+}
+
+void MakeStep::stdOut(const QString &line)
+{
+ if (m_buildParser)
+ m_buildParser->stdOutput(line);
+ AbstractProcessStep::stdOut(line);
+}
+
+void MakeStep::stdError(const QString &line)
+{
+ if (m_buildParser)
+ m_buildParser->stdError(line);
+ AbstractProcessStep::stdError(line);
+}
+
+QString MakeStep::name()
+{
+ return Constants::MAKESTEP;
+}
+
+QString MakeStep::displayName()
+{
+ return "Make";
+}
+
+bool MakeStep::immutable() const
+{
+ return true;
+}
+
+ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
+{
+ return new MakeStepConfigWidget(this);
+}
+
+MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
+ : BuildStepConfigWidget(), m_makeStep(makeStep)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.makeLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(makeLineEditTextEdited()));
+ connect(m_ui.makeArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(makeArgumentsLineEditTextEdited()));
+}
+
+QString MakeStepConfigWidget::displayName() const
+{
+ return m_makeStep->displayName();
+}
+
+void MakeStepConfigWidget::init(const QString &buildConfiguration)
+{
+ m_buildConfiguration = buildConfiguration;
+ bool showPage0 = buildConfiguration.isNull();
+ m_ui.stackedWidget->setCurrentIndex(showPage0? 0 : 1);
+
+ if(!showPage0) {
+ Qt4Project *pro = qobject_cast<Qt4Project *>(m_makeStep->project());
+ m_ui.makeLabel->setText(tr("Override %1:").arg(pro->qtVersion(buildConfiguration)->makeCommand()));
+
+ const QString &makeCmd = m_makeStep->value(buildConfiguration, "makeCmd").toString();
+ m_ui.makeLineEdit->setText(makeCmd);
+
+ const QStringList &makeArguments =
+ m_makeStep->value(buildConfiguration, "makeargs").toStringList();
+ m_ui.makeArgumentsLineEdit->setText(ProjectExplorer::Environment::joinArgumentList(makeArguments));
+ }
+
+}
+
+void MakeStepConfigWidget::makeLineEditTextEdited()
+{
+ Q_ASSERT(!m_buildConfiguration.isNull());
+ m_makeStep->setValue(m_buildConfiguration, "makeCmd", m_ui.makeLineEdit->text());
+}
+
+void MakeStepConfigWidget::makeArgumentsLineEditTextEdited()
+{
+ Q_ASSERT(!m_buildConfiguration.isNull());
+ m_makeStep->setValue(m_buildConfiguration, "makeargs", ProjectExplorer::Environment::parseCombinedArgString(m_ui.makeArgumentsLineEdit->text()));
+}
diff --git a/src/plugins/qt4projectmanager/makestep.h b/src/plugins/qt4projectmanager/makestep.h
new file mode 100644
index 0000000000..966e0f2a4b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/makestep.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MAKESTEP_H
+#define MAKESTEP_H
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <QDebug>
+
+#include "qtversionmanager.h"
+
+#include "ui_makestep.h"
+
+namespace Qt4ProjectManager {
+
+class Qt4Project;
+
+
+// NBS move this class to an own plugin? So that there can be a make project at a future time
+class MakeStep : public ProjectExplorer::AbstractProcessStep
+{
+ Q_OBJECT
+public:
+ MakeStep(Qt4Project * project);
+ ~MakeStep();
+ virtual bool init(const QString & name);
+ virtual void run(QFutureInterface<bool> &);
+ virtual QString name();
+ virtual QString displayName();
+ virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
+ virtual bool immutable() const;
+protected:
+ virtual void stdOut(const QString &line);
+ virtual void stdError(const QString &line);
+private slots:
+ void slotAddToTaskWindow(const QString & fn, int type, int linenumber, const QString & description);
+ void addDirectory(const QString &dir);
+ void removeDirectory(const QString &dir);
+private:
+ ProjectExplorer::BuildParserInterface *buildParser(const Internal::QtVersion * const version);
+ Qt4Project *m_project;
+ ProjectExplorer::BuildParserInterface *m_buildParser;
+ bool m_skipMakeClean;
+ QString m_buildConfiguration;
+ QSet<QString> m_openDirectories;
+};
+
+class MakeStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+ Q_OBJECT
+public:
+ MakeStepConfigWidget(MakeStep *makeStep);
+ QString displayName() const;
+ void init(const QString &buildConfiguration);
+private slots:
+ void makeLineEditTextEdited();
+ void makeArgumentsLineEditTextEdited();
+private:
+ QString m_buildConfiguration;
+ Ui::MakeStep m_ui;
+ MakeStep *m_makeStep;
+};
+
+} // Qt4ProjectManager
+
+#endif // MAKESTEP_H
diff --git a/src/plugins/qt4projectmanager/makestep.ui b/src/plugins/qt4projectmanager/makestep.ui
new file mode 100644
index 0000000000..7ce4a4034b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/makestep.ui
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MakeStep</class>
+ <widget class="QWidget" name="MakeStep">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>428</width>
+ <height>384</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="page_1">
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_2">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="makeLabel">
+ <property name="text">
+ <string>Override %1:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="makeLineEdit"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="makeArgumentsLabel">
+ <property name="text">
+ <string>Make arguments:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="makeArgumentsLineEdit"/>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>255</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>makeLineEdit</tabstop>
+ <tabstop>makeArgumentsLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/msvcenvironment.cpp b/src/plugins/qt4projectmanager/msvcenvironment.cpp
new file mode 100644
index 0000000000..9405ed7dec
--- /dev/null
+++ b/src/plugins/qt4projectmanager/msvcenvironment.cpp
@@ -0,0 +1,156 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "msvcenvironment.h"
+
+#include <QSettings>
+#include <QFile>
+#include <QDebug>
+#include <QStringList>
+#include <QRegExp>
+#include <QTemporaryFile>
+
+using namespace Qt4ProjectManager::Internal;
+using ProjectExplorer::Environment;
+
+MSVCEnvironment::MSVCEnvironment(const QString &name, const QString &path)
+ : m_name(name), m_path(path), m_valuesSet(false)
+{
+
+}
+
+QString MSVCEnvironment::name() const
+{
+ return m_name;
+}
+
+QString MSVCEnvironment::path() const
+{
+ return m_path;
+}
+
+QList<MSVCEnvironment> MSVCEnvironment::availableVersions()
+{
+ QList<MSVCEnvironment> result;
+
+ QSettings registry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7",
+ QSettings::NativeFormat);
+ QStringList versions = registry.allKeys();
+ foreach(const QString &version, versions) {
+ QString dir = registry.value(version).toString();
+ result << MSVCEnvironment(version, dir);
+ }
+ return result;
+}
+
+QString MSVCEnvironment::description() const
+{
+ QString desc;
+ desc = "Microsoft Visual Studio " + m_name + " from " + m_path;
+ return desc;
+}
+
+// This method is ugly as hell, but that is to be expected
+// It crates a temporary batch file which first runs vsvars32.bat from MSVC
+// and then runs *set* to get the environment
+// We cache that information.
+Environment MSVCEnvironment::addToEnvironment(const Environment &env) const
+{
+ Environment e(env);
+ if (!m_valuesSet) {
+ QString desc;
+ QString varsbat = m_path + "Common7\\Tools\\vsvars32.bat";
+ if (QFileInfo(varsbat).exists()) {
+ QTemporaryFile tf(QDir::tempPath() + "\\XXXXXX.bat");
+ if(!tf.open())
+ return e;
+ QString filename = tf.fileName();
+ tf.write("call \"" + varsbat.toLocal8Bit()+"\"\r\n");
+ tf.write(("set > \"" + QDir::tempPath() + "\\qtcreator-msvc-environment.txt\"\r\n").toLocal8Bit());
+ tf.flush();
+ tf.waitForBytesWritten(30000);
+
+ QProcess run;
+ QString cmdPath = e.searchInPath("cmd");
+ run.start(cmdPath, QStringList()<<"/c"<<filename);
+ run.waitForFinished();
+ tf.close();
+
+ QFile vars(QDir::tempPath() + "\\qtcreator-msvc-environment.txt");
+ if(vars.exists() && vars.open(QIODevice::ReadOnly)) {
+ while(!vars.atEnd()) {
+ QByteArray line = vars.readLine();
+ QString line2 = QString::fromLocal8Bit(line);
+ line2 = line2.trimmed();
+ QRegExp regexp("(\\w*)=(.*)");
+ if(regexp.exactMatch(line2)) {
+ QString variable = regexp.cap(1);
+ QString value = regexp.cap(2);
+ value.replace('%' + variable + '%', e.value(variable));
+ m_values.append(QPair<QString, QString>(variable, value));
+
+ }
+ }
+ vars.close();
+ vars.remove();
+ }
+ }
+ m_valuesSet = true;
+ }
+
+ QList< QPair<QString, QString> >::const_iterator it, end;
+ end = m_values.constEnd();
+ for (it = m_values.constBegin(); it != end; ++it) {
+ e.set((*it).first, (*it).second);
+ qDebug()<<"variable:"<<(*it).first<<"value:"<<(*it).second;
+ }
+
+
+// QFile varsbat(m_path + "Common7\\Tools\\vsvars32.bat");
+// if(varsbat.exists() && varsbat.open(QIODevice::ReadOnly)) {
+// while(!varsbat.atEnd()) {
+// QByteArray line = varsbat.readLine();
+// QString line2 = QString::fromLocal8Bit(line);
+// line2 = line2.trimmed();
+// QRegExp regexp("\\s*@?(S|s)(E|e)(T|t)\\s*(\\w*)=(.*)");
+// if(regexp.exactMatch(line2)) {
+// QString variable = regexp.cap(4);
+// QString value = regexp.cap(5);
+// value.replace('%' + variable + '%', e.value(variable));
+// e.set(variable, value);
+// }
+// }
+// varsbat.close();
+// }
+
+ return e;
+}
diff --git a/src/plugins/qt4projectmanager/msvcenvironment.h b/src/plugins/qt4projectmanager/msvcenvironment.h
new file mode 100644
index 0000000000..eda0fcb2be
--- /dev/null
+++ b/src/plugins/qt4projectmanager/msvcenvironment.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MSVCENVIRONMENT_H
+#define MSVCENVIRONMENT_H
+
+#include <QString>
+#include <QList>
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class MSVCEnvironment
+{
+public:
+ QString name() const;
+ QString path() const;
+ ProjectExplorer::Environment addToEnvironment(const ProjectExplorer::Environment &env) const;
+ QString description() const;
+
+ static QList<MSVCEnvironment> availableVersions();
+private:
+
+ MSVCEnvironment(const QString &name, const QString &path);
+ QString m_name;
+ QString m_path;
+ mutable QList<QPair<QString, QString> > m_values;
+ mutable bool m_valuesSet;
+};
+
+}
+}
+#endif
diff --git a/src/plugins/qt4projectmanager/msvcparser.cpp b/src/plugins/qt4projectmanager/msvcparser.cpp
new file mode 100644
index 0000000000..055e7bf1d1
--- /dev/null
+++ b/src/plugins/qt4projectmanager/msvcparser.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QStringList>
+
+#include "msvcparser.h"
+#include "qt4projectmanagerconstants.h"
+
+using namespace Qt4ProjectManager;
+
+MsvcParser::MsvcParser()
+{
+ m_compileRegExp.setPattern("^([^\\(]+)\\((\\d+)\\)+\\s:[^:\\d]+(\\d+):(.*)$");
+ m_compileRegExp.setMinimal(true);
+ m_linkRegExp.setPattern("^([^\\(]+)\\s:[^:\\d]+(\\d+):(.*)$");
+ m_linkRegExp.setMinimal(true);
+}
+
+QString MsvcParser::name() const
+{
+ return QLatin1String(Qt4ProjectManager::Constants::BUILD_PARSER_MSVC);
+}
+
+void MsvcParser::stdError(const QString & line)
+{
+ Q_UNUSED(line);
+ //do nothing
+}
+
+void MsvcParser::stdOutput(const QString & line)
+{
+ QString lne = line.trimmed();
+ if (m_compileRegExp.indexIn(lne) > -1 && m_compileRegExp.numCaptures() == 4) {
+ emit addToTaskWindow(
+ m_compileRegExp.cap(1), //filename
+ toType(m_compileRegExp.cap(3).toInt()), // PatternType
+ m_compileRegExp.cap(2).toInt(), //linenumber
+ m_compileRegExp.cap(4) //description
+ );
+
+ } else if (m_linkRegExp.indexIn(lne) > -1 && m_linkRegExp.numCaptures() == 3) {
+ QString fileName = m_linkRegExp.cap(1);
+ if (fileName.contains(QLatin1String("LINK"), Qt::CaseSensitive))
+ fileName.clear();
+
+ emit addToTaskWindow(
+ fileName, //filename
+ toType(m_linkRegExp.cap(2).toInt()), // pattern type
+ -1, // line number
+ m_linkRegExp.cap(3) // description
+ );
+ }
+}
+
+ProjectExplorer::BuildParserInterface::PatternType MsvcParser::toType(int number)
+{
+ if (number == 0)
+ return ProjectExplorer::BuildParserInterface::Unknown;
+ else if (number > 4000 && number < 5000)
+ return ProjectExplorer::BuildParserInterface::Warning;
+ else
+ return ProjectExplorer::BuildParserInterface::Error;
+}
diff --git a/src/plugins/qt4projectmanager/msvcparser.h b/src/plugins/qt4projectmanager/msvcparser.h
new file mode 100644
index 0000000000..2bb9b043ca
--- /dev/null
+++ b/src/plugins/qt4projectmanager/msvcparser.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MSVCPARSER_H
+#define MSVCPARSER_H
+
+#include <QtCore/QRegExp>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+namespace Qt4ProjectManager {
+
+class MsvcParser : public ProjectExplorer::BuildParserInterface
+{
+ Q_OBJECT
+
+public:
+ MsvcParser();
+ QString name() const;
+
+ virtual void stdOutput(const QString & line);
+ virtual void stdError(const QString & line);
+private:
+ ProjectExplorer::BuildParserInterface::PatternType toType(int number);
+ QRegExp m_compileRegExp;
+ QRegExp m_linkRegExp;
+};
+
+} //namespace ProjectExplorer
+
+#endif
diff --git a/src/plugins/qt4projectmanager/proeditorcontainer.ui b/src/plugins/qt4projectmanager/proeditorcontainer.ui
new file mode 100644
index 0000000000..ba9c371e6d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/proeditorcontainer.ui
@@ -0,0 +1,72 @@
+<ui version="4.0" >
+ <class>ProEditorContainer</class>
+ <widget class="QWidget" name="ProEditorContainer" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>503</width>
+ <height>372</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTreeView" name="m_scopeList" >
+ <property name="uniformRowHeights" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Qt4ProjectManager::Internal::ProEditor" name="m_variableEdit" />
+ </item>
+ <item>
+ <widget class="QCheckBox" name="m_advancedCheckBox" >
+ <property name="text" >
+ <string>Advanced Mode</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Qt4ProjectManager::Internal::ValueEditor" native="1" name="m_valueEdit" />
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Qt4ProjectManager::Internal::ProEditor</class>
+ <extends>QFrame</extends>
+ <header>proparser/proeditor.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Qt4ProjectManager::Internal::ValueEditor</class>
+ <extends>QWidget</extends>
+ <header>valueeditor.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/profilecache.cpp b/src/plugins/qt4projectmanager/profilecache.cpp
new file mode 100644
index 0000000000..022a037f13
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilecache.cpp
@@ -0,0 +1,362 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4project.h"
+#include "qt4nodes.h"
+#include "qt4projectmanager.h"
+#include "profilecache.h"
+#include "proparser/prowriter.h"
+#include "proitems.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <coreplugin/filemanager.h>
+#include <utils/reloadpromptutils.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtGui/QMainWindow>
+#include <QtCore/QDir>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+namespace {
+bool debug = false;
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ManagedProjectFile
+ : public Core::IFile
+{
+ Q_OBJECT
+
+public:
+ ManagedProjectFile(ProFileCache *parent, ProFile *profile);
+ virtual ~ManagedProjectFile();
+
+ ProFile *profile();
+ void setProfile(ProFile *profile);
+ bool isOutOfSync() { return m_outOfSync; }
+ void setOutOfSync(bool state) { m_outOfSync = state; }
+
+ // Core::IFile
+ bool save(const QString &fileName = QString());
+ QString fileName() const;
+
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+
+ virtual QString mimeType() const;
+
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+
+ void modified(ReloadBehavior *behavior);
+
+signals:
+ void changed();
+
+private:
+ const QString m_mimeType;
+ ProFile *m_profile;
+ ProFileCache *m_cache;
+ bool m_outOfSync;
+};
+
+} // namespace Internal
+} // namespace Qt4ProFileNodemanager
+
+ManagedProjectFile::ManagedProjectFile(ProFileCache *parent, ProFile *profile) :
+ Core::IFile(parent),
+ m_mimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)),
+ m_profile(profile),
+ m_cache(parent),
+ m_outOfSync(false)
+{
+
+}
+
+ManagedProjectFile::~ManagedProjectFile()
+{
+ delete m_profile;
+}
+
+ProFile *ManagedProjectFile::profile()
+{
+ return m_profile;
+}
+
+void ManagedProjectFile::setProfile(ProFile *profile)
+{
+ m_outOfSync = false;
+ if (profile == m_profile)
+ return;
+ delete m_profile;
+ m_profile = profile;
+}
+
+bool ManagedProjectFile::save(const QString &)
+{
+ if (!m_profile)
+ return false;
+
+ ProWriter pw;
+ bool ok = pw.write(m_profile, m_profile->fileName());
+ m_profile->setModified(false);
+ m_cache->notifyModifiedChanged(m_profile);
+
+ return ok;
+}
+
+QString ManagedProjectFile::fileName() const
+{
+ return QDir::cleanPath(m_profile->fileName());
+}
+
+QString ManagedProjectFile::defaultPath() const
+{
+ QFileInfo fi(fileName());
+ return fi.absolutePath();
+}
+
+QString ManagedProjectFile::suggestedFileName() const
+{
+ QFileInfo fi(fileName());
+ return fi.fileName();
+}
+
+bool ManagedProjectFile::isModified() const
+{
+ return m_profile->isModified();
+}
+
+bool ManagedProjectFile::isReadOnly() const
+{
+ QFileInfo fi(fileName());
+ return !fi.isWritable();
+}
+
+bool ManagedProjectFile::isSaveAsAllowed() const
+{
+ return false;
+}
+
+void ManagedProjectFile::modified(ReloadBehavior *behavior)
+{
+
+ switch (*behavior) {
+ case Core::IFile::ReloadNone:
+ case Core::IFile::ReloadPermissions:
+ return;
+ case Core::IFile::ReloadAll:
+ m_cache->notifyChanged(QSet<ProFile *>() << m_profile, true);
+ return;
+ case Core::IFile::AskForReload:
+ break;
+ }
+
+ const QString prompt = tr("The project file %1 has changed outside Qt Creator. Do you want to reload it?").arg(m_profile->fileName());
+ switch (const Core::Utils::ReloadPromptAnswer answer = Core::Utils::reloadPrompt(tr("File Changed"), prompt, m_cache->manager()->core()->mainWindow())) {
+ case Core::Utils::ReloadAll:
+ case Core::Utils::ReloadCurrent:
+ m_cache->notifyChanged(QSet<ProFile *>() << m_profile, true);
+ if (answer == Core::Utils::ReloadAll)
+ *behavior = Core::IFile::ReloadAll;
+ break;
+ case Core::Utils::ReloadSkipCurrent:
+ break;
+ case Core::Utils::ReloadNone:
+ *behavior = Core::IFile::ReloadNone;
+ break;
+ }
+}
+
+QString ManagedProjectFile::mimeType() const
+{
+ return m_mimeType;
+}
+
+
+#include "profilecache.moc"
+
+ProFileCache::ProFileCache(Qt4Manager *manager)
+ : QObject(manager)
+{
+ m_manager = manager;
+}
+
+ProFileCache::~ProFileCache()
+{
+ qDeleteAll(m_profiles.values());
+ m_profiles.clear();
+ m_projects.clear();
+}
+
+void ProFileCache::notifyModifiedChanged(ProFile *profile)
+{
+ QList<Qt4ProFileNode *> pros = m_projects.values(profile->fileName());
+ for (int i=0; i<pros.count(); ++i) {
+ Qt4ProFileNode *pro = pros.at(i);
+ pro->update();
+ }
+}
+
+void ProFileCache::notifyChanged(const QSet<ProFile *> &profiles, bool external)
+{
+ QList<Qt4ProFileNode *> notifyProjects;
+
+ foreach (ProFile *profile, profiles) {
+ QList<Qt4ProFileNode *> pros = m_projects.values(profile->fileName());
+
+ if (external) {
+ ManagedProjectFile *file = m_profiles.value(profile->fileName());
+ if (file)
+ file->setOutOfSync(true);
+ }
+
+ QList<Qt4ProFileNode *>::const_iterator i = pros.constBegin();
+ for (; i != pros.constEnd(); ++i) {
+ if (!notifyProjects.contains(*i))
+ notifyProjects << *i;
+ }
+ }
+
+ QList<Qt4ProFileNode *>::const_iterator i = notifyProjects.constBegin();
+ while (i != notifyProjects.constEnd()) {
+ (*i)->update();
+ ++i;
+ }
+}
+
+void ProFileCache::updateDependencies(const QSet<ProFile *> &files, Qt4ProFileNode *project)
+{
+ // just remove and add files that have changed
+ const QSet<QString> &oldFiles = m_projects.keys(project).toSet();
+ QSet<QString> newFiles;
+
+ QList<Core::IFile *> addedFiles;
+ foreach (ProFile *file, files) {
+ newFiles << file->fileName();
+ if (!m_profiles.contains(file->fileName())) {
+ ManagedProjectFile *profile = new ManagedProjectFile(this, file);
+ m_profiles.insert(file->fileName(), profile);
+ if (debug)
+ qDebug() << "ProFileCache - inserting file " << file->fileName();
+ addedFiles << profile;
+ } else {
+ ManagedProjectFile *profile = m_profiles.value(file->fileName());
+ profile->setProfile(file);
+ }
+ }
+ m_manager->core()->fileManager()->addFiles(addedFiles);
+
+ if (oldFiles.isEmpty()) {
+ connect(project, SIGNAL(destroyed(QObject *)),
+ this, SLOT(removeProject(QObject *)));
+ }
+
+ foreach (const QString &profile, (oldFiles - newFiles).toList()) {
+ removeFile(profile, project);
+ }
+
+ foreach (const QString &profile, (newFiles - oldFiles).toList()) {
+ m_projects.insertMulti(profile, project);
+ }
+}
+
+QStringList ProFileCache::dependencies(Qt4ProFileNode *project) const
+{
+ return m_projects.keys(project);
+}
+
+ProFile *ProFileCache::proFile(const QString &file) const
+{
+ QSet<ProFile *> profiles = proFiles(QStringList(file));
+ if (profiles.isEmpty())
+ return 0;
+ return profiles.toList().first();
+}
+
+QSet<ProFile *> ProFileCache::proFiles(const QStringList &files) const
+{
+ QSet<ProFile *> results;
+ foreach (const QString &file, files) {
+ ManagedProjectFile *managedFile = m_profiles.value(file, 0);
+ if (managedFile && !managedFile->isOutOfSync()) {
+ results << managedFile->profile();
+ }
+ }
+ return results;
+}
+
+QSet<ProFile *> ProFileCache::proFiles(Qt4ProFileNode *project) const
+{
+ return proFiles(m_projects.keys(project));
+}
+
+Core::IFile *ProFileCache::fileInterface(const QString &file)
+{
+ return m_profiles.value(file);
+}
+
+void ProFileCache::removeFile(const QString &file, Qt4ProFileNode *proj)
+{
+ QList<Qt4ProFileNode*> projects = m_projects.values(file);
+ m_projects.remove(file);
+ projects.removeAll(proj);
+ if (!projects.isEmpty()) {
+ foreach (Qt4ProFileNode *p, projects) {
+ m_projects.insert(file, p);
+ }
+ } else {
+ ManagedProjectFile *mp = m_profiles.value(file, 0);
+ if (debug)
+ qDebug() << "ProFileCache - removing file " << file;
+ m_manager->core()->fileManager()->removeFile(mp);
+ m_profiles.remove(file);
+ delete mp;
+ }
+}
+
+void ProFileCache::removeProject(QObject *obj)
+{
+ // Cannot use qobject_cast here because
+ // it is triggered by destroyed signal
+ Qt4ProFileNode *proj = static_cast<Qt4ProFileNode*>(obj);
+ QStringList files = m_projects.keys(proj);
+ foreach (const QString &file, files) {
+ removeFile(file, proj);
+ }
+}
diff --git a/src/plugins/qt4projectmanager/profilecache.h b/src/plugins/qt4projectmanager/profilecache.h
new file mode 100644
index 0000000000..59e9a76eb5
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilecache.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILECACHE_H
+#define PROFILECACHE_H
+
+#include <QtCore/QObject>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+class ProFile;
+QT_END_NAMESPACE
+
+namespace Core {
+class IFile;
+}
+
+namespace Qt4ProjectManager {
+
+//class Qt4Project;
+class Qt4Manager;
+
+namespace Internal {
+
+class Qt4ProFileNode;
+class ManagedProjectFile;
+
+class ProFileCache : public QObject
+{
+ Q_OBJECT
+
+public:
+ ProFileCache(Qt4Manager *manager);
+ ~ProFileCache();
+
+ // does not result in a reparse or resolve
+ void notifyModifiedChanged(ProFile *profile);
+
+ // if external is true we need to reparse, it it's false we only resolve
+ void notifyChanged(const QSet<ProFile *> &profiles, bool external = false);
+
+ void updateDependencies(const QSet<ProFile *> &files, Qt4ProFileNode *projectNode);
+ QStringList dependencies(Qt4ProFileNode *projectNode) const;
+
+ ProFile *proFile(const QString &filename) const;
+ QSet<ProFile *> proFiles(const QStringList &files) const;
+ QSet<ProFile *> proFiles(Qt4ProFileNode *projectNode) const;
+
+ Core::IFile *fileInterface(const QString &filename);
+ inline Qt4Manager *manager() const { return m_manager; }
+
+protected slots:
+ void removeProject(QObject *obj);
+
+private:
+ void removeFile(const QString &profile, Qt4ProFileNode *projectNode);
+
+ Qt4Manager *m_manager;
+ QMultiMap<QString, Qt4ProFileNode *> m_projects;
+ QMap<QString, ManagedProjectFile *> m_profiles;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROFILECACHE_H
diff --git a/src/plugins/qt4projectmanager/profileeditor.cpp b/src/plugins/qt4projectmanager/profileeditor.cpp
new file mode 100644
index 0000000000..fc4c6d5542
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profileeditor.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "profileeditor.h"
+#include "profilehighlighter.h"
+#include "qt4projectmanager.h"
+#include "qt4projectmanagerconstants.h"
+#include "profilecache.h"
+#include "profileeditorfactory.h"
+#include "proeditormodel.h"
+#include "procommandmanager.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditoractionhandler.h>
+#include <texteditor/texteditorconstants.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <QtCore/QFileInfo>
+#include <QtGui/QTextEdit>
+#include <QtGui/QHeaderView>
+
+using namespace ExtensionSystem;
+using namespace Core;
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+using namespace ProjectExplorer;
+
+
+ProFileEditorEditable::ProFileEditorEditable(ProFileEditor *editor, Core::ICore *core)
+ :BaseTextEditorEditable(editor)
+{
+ m_context << core->uniqueIDManager()->
+ uniqueIdentifier(Qt4ProjectManager::Constants::C_PROFILEEDITOR);
+ m_context << core->uniqueIDManager()->
+ uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+// m_contexts << core->uniqueIDManager()->
+// uniqueIdentifier(Qt4ProjectManager::Constants::PROJECT_KIND);
+}
+
+TextEditor::BaseTextEditorEditable *ProFileEditor::createEditableInterface()
+{
+ return new ProFileEditorEditable(this, m_core);
+}
+
+ProFileEditor::ProFileEditor(QWidget *parent, ProFileEditorFactory *factory, TextEditor::TextEditorActionHandler *ah)
+ : BaseTextEditor(parent), m_factory(factory), m_ah(ah)
+{
+ Qt4Manager *manager = factory->qt4ProjectManager();
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ ProFileDocument *doc = new ProFileDocument(manager);
+ doc->setMimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE));
+ setBaseTextDocument(doc);
+
+ ah->setupActions(this);
+
+ baseTextDocument()->setSyntaxHighlighter(new ProFileHighlighter);
+}
+
+ProFileEditor::~ProFileEditor()
+{
+}
+
+QList<int> ProFileEditorEditable::context() const
+{
+ return m_context;
+}
+
+Core::IEditor *ProFileEditorEditable::duplicate(QWidget *parent)
+{
+ ProFileEditor *ret = new ProFileEditor(parent, qobject_cast<ProFileEditor*>(editor())->factory(),
+ qobject_cast<ProFileEditor*>(editor())->actionHandler());
+ ret->duplicateFrom(editor());
+ ret->initialize();
+ return ret->editableInterface();
+}
+
+void ProFileEditor::initialize()
+{
+ TextEditor::TextEditorSettings *settings = TextEditor::TextEditorSettings::instance();
+
+ connect(settings, SIGNAL(fontSettingsChanged(const TextEditor::FontSettings&)),
+ this, SLOT(setFontSettings(const TextEditor::FontSettings&)));
+
+ setFontSettings(settings->fontSettings());
+}
+
+const char *ProFileEditorEditable::kind() const
+{
+ return Qt4ProjectManager::Constants::PROFILE_EDITOR;
+}
+
+void ProFileEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ TextEditor::BaseTextEditor::setFontSettings(fs);
+ ProFileHighlighter *highlighter = qobject_cast<ProFileHighlighter*>(baseTextDocument()->syntaxHighlighter());
+ if (!highlighter)
+ return;
+
+ static QVector<QString> categories;
+ if (categories.isEmpty()) {
+ categories << QLatin1String(TextEditor::Constants::C_VARIABLE)
+ << QLatin1String(TextEditor::Constants::C_FUNCTION)
+ << QLatin1String(TextEditor::Constants::C_COMMENT);
+ }
+
+ const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
+ highlighter->setFormats(formats.constBegin(), formats.constEnd());
+ highlighter->rehighlight();
+}
+
+ProFileDocument::ProFileDocument(Qt4Manager *manager)
+ : TextEditor::BaseTextDocument(), m_manager(manager)
+{
+}
+
+bool ProFileDocument::save(const QString &name)
+{
+ if (BaseTextDocument::save(name)) {
+ ProFile *profile = m_manager->proFileCache()->proFile(name);
+ if (profile)
+ m_manager->proFileCache()->notifyChanged(QSet<ProFile*>() << profile, true);
+ return true;
+ }
+ return false;
+}
+
+QString ProFileDocument::defaultPath() const
+{
+ QFileInfo fi(fileName());
+ return fi.absolutePath();
+}
+
+QString ProFileDocument::suggestedFileName() const
+{
+ QFileInfo fi(fileName());
+ return fi.fileName();
+}
diff --git a/src/plugins/qt4projectmanager/profileeditor.h b/src/plugins/qt4projectmanager/profileeditor.h
new file mode 100644
index 0000000000..44710bacfb
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profileeditor.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILEEDITOR
+#define PROFILEEDITOR
+
+#include <texteditor/basetextdocument.h>
+#include <texteditor/basetexteditor.h>
+#include "ui_proeditorcontainer.h"
+
+namespace TextEditor {
+class FontSettings;
+class BaseEditorActionHandler;
+}
+
+namespace Core {
+class ICore;
+class IFile;
+}
+
+namespace Qt4ProjectManager {
+
+class Qt4Manager;
+class Qt4Project;
+
+namespace Internal {
+
+class ProFileEditorFactory;
+class ProItemInfoManager;
+class ProEditorModel;
+class ProFileHighlighter;
+
+class ProFileEditor;
+
+class ProFileEditorEditable : public TextEditor::BaseTextEditorEditable
+{
+public:
+ ProFileEditorEditable(ProFileEditor *, Core::ICore *core);
+ QList<int> context() const;
+
+ bool duplicateSupported() const { return true; }
+ Core::IEditor *duplicate(QWidget *parent);
+ const char *kind() const;
+private:
+ QList<int> m_context;
+};
+
+class ProFileEditor : public TextEditor::BaseTextEditor
+{
+ Q_OBJECT
+
+public:
+ ProFileEditor(QWidget *parent, ProFileEditorFactory *factory,
+ TextEditor::TextEditorActionHandler *ah);
+ ~ProFileEditor();
+ void initialize();
+
+ bool save(const QString &fileName = QString());
+
+
+ ProFileEditorFactory *factory() { return m_factory; }
+ TextEditor::TextEditorActionHandler *actionHandler() const { return m_ah; }
+protected:
+ TextEditor::BaseTextEditorEditable *createEditableInterface();
+
+public slots:
+ virtual void setFontSettings(const TextEditor::FontSettings &);
+
+private:
+ Core::ICore *m_core;
+ ProFileEditorFactory *m_factory;
+ TextEditor::TextEditorActionHandler *m_ah;
+};
+
+class ProFileDocument : public TextEditor::BaseTextDocument
+{
+ Q_OBJECT
+
+public:
+ ProFileDocument(Qt4Manager *manager);
+ bool save(const QString &name);
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+
+private:
+ Qt4Manager *m_manager;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROFILEEDITOR
diff --git a/src/plugins/qt4projectmanager/profileeditorfactory.cpp b/src/plugins/qt4projectmanager/profileeditorfactory.cpp
new file mode 100644
index 0000000000..6866193db8
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profileeditorfactory.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "profileeditorfactory.h"
+#include "qt4projectmanager.h"
+#include "qt4projectmanagerconstants.h"
+#include "profileeditor.h"
+#include "qt4projectmanagerenums.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/texteditoractionhandler.h>
+
+#include <QtCore/QFileInfo>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+ProFileEditorFactory::ProFileEditorFactory(Qt4Manager *manager, TextEditor::TextEditorActionHandler *handler) :
+ m_kind(QLatin1String(Qt4ProjectManager::Constants::PROFILE_EDITOR)),
+ m_mimeTypes(QStringList() << QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)
+ << QLatin1String(Qt4ProjectManager::Constants::PROINCLUDEFILE_MIMETYPE)),
+ m_manager(manager),
+ m_actionHandler(handler)
+{
+ Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
+ iconProvider->registerIconForSuffix(QIcon(":/qt4projectmanager/images/qt_project.png"),
+ QLatin1String("pro"));
+ iconProvider->registerIconForSuffix(QIcon(":/qt4projectmanager/images/qt_project.png"),
+ QLatin1String("pri"));
+}
+
+ProFileEditorFactory::~ProFileEditorFactory()
+{
+}
+
+QString ProFileEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *ProFileEditorFactory::open(const QString &fileName)
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ Core::IEditor *iface = core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *ProFileEditorFactory::createEditor(QWidget *parent)
+{
+ ProFileEditor *rc = new ProFileEditor(parent, this, m_actionHandler);
+ rc->initialize();
+ return rc->editableInterface();
+}
+
+QStringList ProFileEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
+
+void ProFileEditorFactory::initializeActions()
+{
+ m_actionHandler->initializeActions();
+}
diff --git a/src/plugins/qt4projectmanager/profileeditorfactory.h b/src/plugins/qt4projectmanager/profileeditorfactory.h
new file mode 100644
index 0000000000..fb50fa0895
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profileeditorfactory.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILEEDITORFACTORY_H
+#define PROFILEEDITORFACTORY_H
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+class TextEditorActionHandler;
+}
+
+namespace Qt4ProjectManager {
+
+class Qt4Manager;
+
+namespace Internal {
+
+class ProFileEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ ProFileEditorFactory(Qt4Manager *parent, TextEditor::TextEditorActionHandler *handler);
+ ~ProFileEditorFactory();
+
+ virtual QStringList mimeTypes() const;
+ virtual QString kind() const;
+ Core::IFile *open(const QString &fileName);
+ Core::IEditor *createEditor(QWidget *parent);
+
+ inline Qt4Manager *qt4ProjectManager() const { return m_manager; }
+
+ void initializeActions();
+
+private:
+ const QString m_kind;
+ const QStringList m_mimeTypes;
+ Qt4Manager *m_manager;
+ TextEditor::TextEditorActionHandler *m_actionHandler;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROFILEEDITORFACTORY_H
diff --git a/src/plugins/qt4projectmanager/profilehighlighter.cpp b/src/plugins/qt4projectmanager/profilehighlighter.cpp
new file mode 100644
index 0000000000..df4dbc45c9
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilehighlighter.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "profilehighlighter.h"
+
+#include <QtCore/QRegExp>
+#include <QtGui/QColor>
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextEdit>
+
+using namespace Qt4ProjectManager::Internal;
+
+#define MAX_VARIABLES 48
+const char *const variables[MAX_VARIABLES] = {
+ "CONFIG",
+ "DEFINES",
+ "DEF_FILE",
+ "DEPENDPATH",
+ "DESTDIR",
+ "DESTDIR_TARGET",
+ "DISTFILES",
+ "DLLDESTDIR",
+ "FORMS",
+ "HEADERS",
+ "INCLUDEPATH",
+ "LEXSOURCES",
+ "LIBS",
+ "MAKEFILE",
+ "MOC_DIR",
+ "OBJECTS",
+ "OBJECTS_DIR",
+ "OBJMOC",
+ "POST_TARGETDEPS",
+ "PRECOMPILED_HEADER",
+ "PRE_TARGETDEPS",
+ "QMAKE",
+ "QMAKESPEC",
+ "QT",
+ "RCC_DIR",
+ "RC_FILE",
+ "REQUIRES",
+ "RESOURCES",
+ "RES_FILE",
+ "SOURCES",
+ "SRCMOC",
+ "SUBDIRS",
+ "TARGET",
+ "TARGET_EXT",
+ "TARGET_x",
+ "TARGET_x.y.z",
+ "TEMPLATE",
+ "TRANSLATIONS",
+ "UI_DIR",
+ "UI_HEADERS_DIR",
+ "UI_SOURCES_DIR",
+ "VER_MAJ",
+ "VER_MIN",
+ "VER_PAT",
+ "VERSION",
+ "VPATH",
+ "YACCSOURCES",
+ 0
+};
+
+#define MAX_FUNCTIONS 22
+const char *const functions[MAX_FUNCTIONS] = {
+ "basename",
+ "CONFIG",
+ "contains",
+ "count",
+ "dirname",
+ "error",
+ "exists",
+ "find",
+ "for",
+ "include",
+ "infile",
+ "isEmpty",
+ "join",
+ "member",
+ "message",
+ "prompt",
+ "quote",
+ "sprintf",
+ "system",
+ "unique",
+ "warning",
+ 0
+};
+
+struct KeywordHelper
+{
+ inline KeywordHelper(const QString &word) : needle(word) {}
+ const QString needle;
+};
+
+static bool operator<(const KeywordHelper &helper, const char *kw)
+{
+ return helper.needle < QLatin1String(kw);
+}
+
+static bool operator<(const char *kw, const KeywordHelper &helper)
+{
+ return QLatin1String(kw) < helper.needle;
+}
+
+static bool isVariable(const QString &word)
+{
+ const char *const *start = &variables[0];
+ const char *const *end = &variables[MAX_VARIABLES - 1];
+ const char *const *kw = qBinaryFind(start, end, KeywordHelper(word));
+ return *kw != 0;
+}
+
+static bool isFunction(const QString &word)
+{
+ const char *const *start = &functions[0];
+ const char *const *end = &functions[MAX_FUNCTIONS - 1];
+ const char *const *kw = qBinaryFind(start, end, KeywordHelper(word));
+ return *kw != 0;
+}
+
+ProFileHighlighter::ProFileHighlighter(QTextDocument *document) :
+ QSyntaxHighlighter(document)
+{
+}
+
+void ProFileHighlighter::highlightBlock(const QString &text)
+{
+ if (text.isEmpty())
+ return;
+
+ QString buf;
+ bool inCommentMode = false;
+
+ QTextCharFormat emptyFormat;
+ int i = 0;
+ for (;;) {
+ const QChar c = text.at(i);
+ if (inCommentMode) {
+ setFormat(i, 1, m_formats[ProfileCommentFormat]);
+ } else {
+ if (c.isLetter() || c == '_' || c == '.') {
+ buf += c;
+ setFormat(i - buf.length()+1, buf.length(), emptyFormat);
+ if (!buf.isEmpty() && isFunction(buf))
+ setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileFunctionFormat]);
+ else if (!buf.isEmpty() && isVariable(buf))
+ setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileVariableFormat]);
+ } else if (c == '(') {
+ if (!buf.isEmpty() && isFunction(buf))
+ setFormat(i - buf.length(), buf.length(), m_formats[ProfileFunctionFormat]);
+ buf.clear();
+ } else if (c == '#') {
+ inCommentMode = true;
+ setFormat(i, 1, m_formats[ProfileCommentFormat]);
+ buf.clear();
+ } else {
+ if (!buf.isEmpty() && isVariable(buf))
+ setFormat(i - buf.length(), buf.length(), m_formats[ProfileVariableFormat]);
+ buf.clear();
+ }
+ }
+ i++;
+ if (i >= text.length())
+ break;
+ }
+}
+
diff --git a/src/plugins/qt4projectmanager/profilehighlighter.h b/src/plugins/qt4projectmanager/profilehighlighter.h
new file mode 100644
index 0000000000..c15d584e09
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilehighlighter.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILEHIGHLIGHTER_H
+#define PROFILEHIGHLIGHTER_H
+
+#include "qt4projectmanagerenums.h"
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCharFormat>
+#include <QtCore/QtAlgorithms>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProFileHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ ProFileHighlighter(QTextDocument *document = 0);
+ virtual void highlightBlock(const QString &text);
+
+ // Set formats from a sequence of type QTextCharFormat
+ template <class InputIterator>
+ void setFormats(InputIterator begin, InputIterator end) {
+ qCopy(begin, end, m_formats);
+ }
+
+private:
+ QTextCharFormat m_formats[NumProfileFormats];
+
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROFILEHIGHLIGHTER_H
diff --git a/src/plugins/qt4projectmanager/profilereader.cpp b/src/plugins/qt4projectmanager/profilereader.cpp
new file mode 100644
index 0000000000..bba0393a61
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilereader.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "profilereader.h"
+#include "profilecache.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+ProFileReader::ProFileReader(ProFileCache *cache)
+ : m_cache(cache)
+{
+}
+
+void ProFileReader::setQtVersion(QtVersion *qtVersion) {
+ QHash<QString, QStringList> additionalVariables;
+ additionalVariables.insert(QString("QT_BUILD_TREE"), QStringList() << qtVersion->path());
+ additionalVariables.insert(QString("QT_SOURCE_TREE"), QStringList() << qtVersion->sourcePath());
+ addVariables(additionalVariables);
+ addProperties(qtVersion->versionInfo());
+ // ### TODO override QT_VERSION property
+}
+
+bool ProFileReader::readProFile(const QString &fileName)
+{
+ //disable caching -> list of include files is not updated otherwise
+// ProFile *pro = proFileFromCache(fileName);
+// if (!pro) {
+// pro = new ProFile(fileName);
+// if (!queryProFile(pro)) {
+// delete pro;
+// return false;
+// }
+// }
+ QString fn = QFileInfo(fileName).filePath();
+ ProFile *pro = new ProFile(fn);
+ if (!queryProFile(pro)) {
+ delete pro;
+ return false;
+ }
+ m_includeFiles.insert(fn, pro);
+ return accept(pro);
+}
+
+ProFile *ProFileReader::parsedProFile(const QString &fileName)
+{
+// ProFile *pro = proFileFromCache(fileName);
+// if (pro)
+// return pro;
+ QString fn = QFileInfo(fileName).filePath();
+ ProFile *pro = ProFileEvaluator::parsedProFile(fn);
+ if (pro) {
+ m_includeFiles.insert(fn, pro);
+ }
+ return pro;
+}
+
+void ProFileReader::releaseParsedProFile(ProFile */*proFile*/)
+{
+ return;
+}
+
+ProFile *ProFileReader::proFileFromCache(const QString &fileName) const
+{
+ QString fn = QFileInfo(fileName).filePath();
+ ProFile *pro = 0;
+ if (m_includeFiles.contains(fn))
+ pro = m_includeFiles.value(fn);
+ else
+ pro = m_cache->proFile(fn); // this can expand to null
+ return pro;
+}
+
+QList<ProFile*> ProFileReader::includeFiles() const
+{
+ QString qmakeMkSpecDir = propertyValue("QMAKE_MKSPECS");
+ QList<ProFile *> list;
+ QMap<QString, ProFile *>::const_iterator it, end;
+ end = m_includeFiles.constEnd();
+ for (it = m_includeFiles.constBegin(); it != end; ++it) {
+ if (!(it.key().startsWith(qmakeMkSpecDir)))
+ list.append(it.value());
+ }
+ return list;
+}
+
+QString ProFileReader::value(const QString &variable) const
+{
+ QStringList vals = values(variable);
+ if (!vals.isEmpty())
+ return vals.first();
+
+ return QString();
+}
+
+
+// Construct QFileInfo from path value and base directory
+// Truncate trailing slashs and make absolute
+static inline QFileInfo infoFromPath(QString path,
+ const QString &baseDirectory)
+{
+ if (path.size() > 1 && path.endsWith(QLatin1Char('/')))
+ path.truncate(path.size() - 1);
+ QFileInfo info(path);
+ if (info.isAbsolute())
+ return info;
+ return QFileInfo(baseDirectory, path);
+}
+
+/*!
+ Returns a list of absolute paths
+ */
+QStringList ProFileReader::absolutePathValues(const QString &variable,
+ const QString &baseDirectory,
+ PathValuesMode mode,
+ const ProFile *pro) const
+{
+ QStringList rawList;
+ if (!pro)
+ rawList = values(variable);
+ else
+ rawList = values(variable, pro);
+
+ if (rawList.isEmpty())
+ return QStringList();
+
+ // Normalize list of paths, kill trailing slashes,
+ // remove duplicates while maintaining order
+ const QChar slash = QLatin1Char('/');
+ QStringList result;
+ const QStringList::const_iterator rcend = rawList.constEnd();
+ for (QStringList::const_iterator it = rawList.constBegin(); it != rcend; ++it) {
+ const QFileInfo info = infoFromPath(*it, baseDirectory);
+ if (mode == AllPaths || info.exists()) {
+ if (mode != ExistingFilePaths || info.isFile()) {
+ const QString absPath = info.absoluteFilePath();
+ if (!result.contains(absPath))
+ result.push_back(absPath);
+ }
+ }
+ }
+ return result;
+}
+
+void ProFileReader::fileMessage(const QString &message)
+{
+ Q_UNUSED(message);
+ // we ignore these...
+}
+
+void ProFileReader::logMessage(const QString &message)
+{
+ Q_UNUSED(message);
+ // we ignore these...
+}
+
+void ProFileReader::errorMessage(const QString &message)
+{
+ emit errorFound(message);
+}
diff --git a/src/plugins/qt4projectmanager/profilereader.h b/src/plugins/qt4projectmanager/profilereader.h
new file mode 100644
index 0000000000..682793c236
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilereader.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILEREADER_H
+#define PROFILEREADER_H
+
+#include "profileevaluator.h"
+#include "qtversionmanager.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+
+class ProFileCache;
+
+class ProFileReader : public QObject, public ProFileEvaluator
+{
+ Q_OBJECT
+
+public:
+ ProFileReader(ProFileCache *cache);
+
+ void setQtVersion(QtVersion *qtVersion);
+ bool readProFile(const QString &fileName);
+ QList<ProFile*> includeFiles() const;
+
+ QString value(const QString &variable) const;
+
+ enum PathValuesMode { AllPaths, ExistingPaths, ExistingFilePaths };
+ QStringList absolutePathValues(const QString &variable,
+ const QString &baseDirectory,
+ PathValuesMode mode,
+ const ProFile *pro = 0) const;
+
+signals:
+ void errorFound(const QString &error);
+
+private:
+ virtual ProFile *parsedProFile(const QString &fileName);
+ virtual void releaseParsedProFile(ProFile *proFile);
+ virtual void logMessage(const QString &msg);
+ virtual void fileMessage(const QString &msg);
+ virtual void errorMessage(const QString &msg);
+
+private:
+ ProFile *proFileFromCache(const QString &fileName) const;
+ ProFileCache *m_cache;
+ QMap<QString, ProFile *> m_includeFiles;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif // PROFILEREADER_H
diff --git a/src/plugins/qt4projectmanager/projectloadwizard.cpp b/src/plugins/qt4projectmanager/projectloadwizard.cpp
new file mode 100644
index 0000000000..b53575c786
--- /dev/null
+++ b/src/plugins/qt4projectmanager/projectloadwizard.cpp
@@ -0,0 +1,221 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "projectloadwizard.h"
+#include "qt4project.h"
+#include "qtversionmanager.h"
+#include "qt4projectmanager.h"
+#include "qmakestep.h"
+#include "makestep.h"
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QCheckBox>
+#include <QtGui/QComboBox>
+#include <QtGui/QFormLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QHeaderView>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QListWidget>
+#include <QtGui/QRadioButton>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QToolButton>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QWizard>
+#include <QtGui/QWizardPage>
+#include <QFileDialog>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+ProjectLoadWizard::ProjectLoadWizard(Qt4Project *project, QWidget *parent, Qt::WindowFlags flags)
+ : QWizard(parent, flags), m_project(project), m_importVersion(0), m_temporaryVersion(false)
+{
+ QtVersionManager * vm = project->qt4ProjectManager()->versionManager();
+ QString directory = QFileInfo(project->file()->fileName()).absolutePath();
+ QString importVersion = vm->findQtVersionFromMakefile(directory);
+
+ if (!importVersion.isNull()) {
+ // This also means we have a build in there
+ // First get the qt version
+ m_importVersion = vm->qtVersionForDirectory(importVersion);
+ // Okay does not yet exist, create
+ if (!m_importVersion) {
+ m_importVersion = new QtVersion(QFileInfo(importVersion).baseName(), importVersion);
+ m_temporaryVersion = true;
+ }
+
+ m_importBuildConfig = m_importVersion->defaultBuildConfig();
+ m_importBuildConfig= vm->scanMakefileForQmakeConfig(directory, m_importBuildConfig);
+ }
+
+ // So now we have the version and the configuration for that version
+ // If buildAll we create debug and release configurations,
+ // if not then just either debug or release
+ // The default buildConfiguration depends on QmakeBuildConfig::DebugBuild
+ // Also if the qt version is not yet in the Tools Options dialog we offer to add it there
+
+ if (m_importVersion)
+ setupImportPage(m_importVersion, m_importBuildConfig);
+
+ setOptions(options() | QWizard::NoCancelButton | QWizard::NoBackButtonOnLastPage);
+}
+
+// We don't want to actually show the dialog if we don't show the import page
+// We used to simply call ::exec() on the dialog
+void ProjectLoadWizard::execDialog()
+{
+ if (m_importVersion)
+ exec();
+ else
+ done(QDialog::Accepted);
+}
+
+ProjectLoadWizard::~ProjectLoadWizard()
+{
+
+}
+
+void ProjectLoadWizard::addBuildConfiguration(QString name, QtVersion *qtversion, QtVersion::QmakeBuildConfig buildConfiguration)
+{
+ QMakeStep *qmakeStep = m_project->qmakeStep();
+ MakeStep *makeStep = m_project->makeStep();
+
+ bool debug = buildConfiguration & QtVersion::DebugBuild;
+ // Check that bc.name is not already in use
+ if (m_project->buildConfigurations().contains(name)) {
+ int i =1;
+ do {
+ ++i;
+ } while (m_project->buildConfigurations().contains(name + " " + QString::number(i)));
+ name.append(" " + QString::number(i));
+ }
+
+ // Add the buildconfiguration
+ m_project->addBuildConfiguration(name);
+ // set some options for qmake and make
+ if (buildConfiguration & QtVersion::BuildAll) // debug_and_release => explicit targets
+ makeStep->setValue(name, "makeargs", QStringList() << (debug ? "debug" : "release"));
+
+ qmakeStep->setValue(name, "buildConfiguration", int(buildConfiguration));
+
+ // Finally set the qt version
+ bool defaultQtVersion = (qtversion == 0);
+ if (defaultQtVersion)
+ m_project->setQtVersion(name, 0);
+ else
+ m_project->setQtVersion(name, qtversion->uniqueId());
+
+}
+
+void ProjectLoadWizard::done(int result)
+{
+ QWizard::done(result);
+ // This normally happens on showing the final page, but since we
+ // don't show it anymore, do it here
+
+ QString directory = QFileInfo(m_project->file()->fileName()).absolutePath();
+ if (m_importVersion && importCheckbox->isChecked()) {
+ if (m_temporaryVersion)
+ m_project->qt4ProjectManager()->versionManager()->addVersion(m_importVersion);
+ // Import the existing stuff
+ // qDebug()<<"Creating m_buildconfiguration entry from imported stuff";
+ // qDebug()<<((m_importBuildConfig& QtVersion::BuildAll)? "debug_and_release" : "")<<((m_importBuildConfig & QtVersion::DebugBuild)? "debug" : "release");
+ bool debug = m_importBuildConfig & QtVersion::DebugBuild;
+ addBuildConfiguration(debug ? "Debug" : "Release", m_importVersion, m_importBuildConfig);
+
+ if (m_importBuildConfig & QtVersion::BuildAll) {
+ // Also create the other configuration
+ QtVersion::QmakeBuildConfig otherBuildConfiguration = m_importBuildConfig;
+ if (debug)
+ otherBuildConfiguration = QtVersion::QmakeBuildConfig(otherBuildConfiguration & ~ QtVersion::DebugBuild);
+ else
+ otherBuildConfiguration = QtVersion::QmakeBuildConfig(otherBuildConfiguration | QtVersion::DebugBuild);
+
+ addBuildConfiguration(debug ? "Release" : "Debug", m_importVersion, otherBuildConfiguration);
+ }
+ } else {
+ if (m_temporaryVersion)
+ delete m_importVersion;
+ // Create default
+ addBuildConfiguration("Debug", 0, QtVersion::QmakeBuildConfig(QtVersion::BuildAll | QtVersion::DebugBuild));
+ addBuildConfiguration("Release", 0, QtVersion::BuildAll);
+ }
+
+ if (!m_project->buildConfigurations().isEmpty())
+ m_project->setActiveBuildConfiguration(m_project->buildConfigurations().at(0));
+}
+
+// This function used to do the commented stuff instead of having only one page
+int ProjectLoadWizard::nextId() const
+{
+ return -1;
+}
+
+void ProjectLoadWizard::setupImportPage(QtVersion *version, QtVersion::QmakeBuildConfig buildConfig)
+{
+ resize(605, 490);
+ // Import Page
+ importPage = new QWizardPage(this);
+ importPage->setTitle("Import existing settings");
+ QVBoxLayout *importLayout = new QVBoxLayout(importPage);
+ importLabel = new QLabel(importPage);
+
+ QString versionString = version->name() + " (" + version->path() + ")";
+ QString buildConfigString = (buildConfig & QtVersion::BuildAll) ? QLatin1String("debug_and_release ") : QLatin1String("");
+ buildConfigString.append((buildConfig & QtVersion::DebugBuild) ? QLatin1String("debug") : QLatin1String("release"));
+ importLabel->setTextFormat(Qt::RichText);
+ importLabel->setText(tr("Qt Creator has found an already existing build in the source directory.<br><br>"
+ "<b>Qt Version:</b> %1<br>"
+ "<b>Build configuration:</b> %2<br>")
+ .arg(versionString)
+ .arg(buildConfigString));
+
+ importLayout->addWidget(importLabel);
+
+
+ importCheckbox = new QCheckBox(importPage);
+ importCheckbox->setText("Import existing build settings.");
+ importCheckbox->setChecked(true);
+ importLayout->addWidget(importCheckbox);
+ import2Label = new QLabel(importPage);
+ import2Label->setTextFormat(Qt::RichText);
+ if (m_temporaryVersion)
+ import2Label->setText(QString("<b>Note:</b> Importing the settings will automatically add the Qt Version from:<br><b>%1</b> to the list of qt versions.")
+ .arg(m_importVersion->path()));
+ importLayout->addWidget(import2Label);
+ addPage(importPage);
+}
+
diff --git a/src/plugins/qt4projectmanager/projectloadwizard.h b/src/plugins/qt4projectmanager/projectloadwizard.h
new file mode 100644
index 0000000000..d75d4e6954
--- /dev/null
+++ b/src/plugins/qt4projectmanager/projectloadwizard.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/********************************************************************************
+** Form generated from reading ui file 'projectloadwizard.ui'
+**
+** Created: Mon Nov 3 16:31:45 2008
+** by: Qt User Interface Compiler version 4.5.0
+**
+** WARNING! All changes made in this file will be lost when recompiling ui file!
+********************************************************************************/
+
+#ifndef PROJECTLOADWIZARD_H
+#define PROJECTLOADWIZARD_H
+
+#include "qt4project.h"
+#include <QtGui/QWizard>
+
+
+QT_BEGIN_NAMESPACE
+class QWizardPage;
+class QVBoxLayout;
+class QHBoxLayout;
+class QLabel;
+class QCheckBox;
+class QRadioButton;
+class QListWidget;
+class QLineEdit;
+class QToolButton;
+class QSpacerItem;
+class QFormLayout;
+class QComboBox;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+class Qt4Project;
+namespace Internal {
+
+class ProjectLoadWizard : public QWizard
+{
+ Q_OBJECT
+public:
+ ProjectLoadWizard(Qt4ProjectManager::Qt4Project *project, QWidget * parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~ProjectLoadWizard();
+ virtual int nextId() const;
+ virtual void done(int result);
+ void execDialog();
+private:
+ void addBuildConfiguration(QString name, QtVersion *qtversion, QtVersion::QmakeBuildConfig buildConfiguration);
+ void setupImportPage(QtVersion *version, QtVersion::QmakeBuildConfig buildConfig);
+
+ Qt4Project *m_project;
+
+ // Only used for imported stuff
+ QtVersion *m_importVersion;
+ QtVersion::QmakeBuildConfig m_importBuildConfig;
+ // Those that we might add
+ bool m_temporaryVersion;
+
+ // This was a file autogenarated by Designer, before I found out you can't actually
+ // create non linear wizards in it
+ // So those variables should all be m_*, but that one has to wait for refactoring support :)
+ QWizardPage *importPage;
+ QLabel *importLabel;
+ QLabel *import2Label;
+ QCheckBox *importCheckbox;
+
+ void setupUi();
+};
+}
+}
+
+#endif // UI_PROJECTLOADWIZARD_H
diff --git a/src/plugins/qt4projectmanager/qmakebuildstepfactory.cpp b/src/plugins/qt4projectmanager/qmakebuildstepfactory.cpp
new file mode 100644
index 0000000000..fbf1a80952
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qmakebuildstepfactory.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qmakebuildstepfactory.h"
+#include "qmakestep.h"
+#include "makestep.h"
+#include "qt4project.h"
+#include "qt4projectmanagerconstants.h"
+
+using namespace Qt4ProjectManager::Internal;
+using namespace ProjectExplorer;
+
+QMakeBuildStepFactory::QMakeBuildStepFactory()
+{
+}
+
+QMakeBuildStepFactory::~QMakeBuildStepFactory()
+{
+}
+
+bool QMakeBuildStepFactory::canCreate(const QString & name) const
+{
+ return (name == Constants::QMAKESTEP);
+}
+
+ProjectExplorer::BuildStep * QMakeBuildStepFactory::create(ProjectExplorer::Project * pro, const QString & name) const
+{
+ Q_UNUSED(name);
+ return new QMakeStep(static_cast<Qt4Project *>(pro));
+}
+
+QStringList QMakeBuildStepFactory::canCreateForProject(ProjectExplorer::Project *pro) const
+{
+ Q_UNUSED(pro)
+ return QStringList();
+}
+
+QString QMakeBuildStepFactory::displayNameForName(const QString &name) const
+{
+ Q_UNUSED(name);
+ return QString();
+}
+
+MakeBuildStepFactory::MakeBuildStepFactory()
+{
+}
+
+MakeBuildStepFactory::~MakeBuildStepFactory()
+{
+}
+
+bool MakeBuildStepFactory::canCreate(const QString & name) const
+{
+ return (name == Constants::MAKESTEP);
+}
+
+ProjectExplorer::BuildStep * MakeBuildStepFactory::create(ProjectExplorer::Project * pro, const QString & name) const
+{
+ Q_UNUSED(name);
+ return new MakeStep(static_cast<Qt4Project *>(pro));
+}
+
+QStringList MakeBuildStepFactory::canCreateForProject(ProjectExplorer::Project *pro) const
+{
+ Q_UNUSED(pro)
+ return QStringList();
+}
+
+QString MakeBuildStepFactory::displayNameForName(const QString &name) const
+{
+ Q_UNUSED(name);
+ return QString();
+}
diff --git a/src/plugins/qt4projectmanager/qmakebuildstepfactory.h b/src/plugins/qt4projectmanager/qmakebuildstepfactory.h
new file mode 100644
index 0000000000..c2292b832c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qmakebuildstepfactory.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QMAKEBUILDSTEPFACTORY_H
+#define QMAKEBUILDSTEPFACTORY_H
+
+#include <projectexplorer/buildstep.h>
+#include <QString>
+
+namespace ProjectExplorer {
+class BuildStep;
+class IBuildStepFactory;
+class Project;
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class QMakeBuildStepFactory : public ProjectExplorer::IBuildStepFactory
+{
+ Q_OBJECT
+public:
+ QMakeBuildStepFactory();
+ virtual ~QMakeBuildStepFactory();
+ bool canCreate(const QString & name) const;
+ ProjectExplorer::BuildStep * create(ProjectExplorer::Project * pro, const QString & name) const;
+ QStringList canCreateForProject(ProjectExplorer::Project *pro) const;
+ QString displayNameForName(const QString &name) const;
+};
+
+class MakeBuildStepFactory : public ProjectExplorer::IBuildStepFactory
+{
+ Q_OBJECT
+public:
+ MakeBuildStepFactory();
+ virtual ~MakeBuildStepFactory();
+ bool canCreate(const QString & name) const;
+ ProjectExplorer::BuildStep * create(ProjectExplorer::Project * pro, const QString & name) const;
+ QStringList canCreateForProject(ProjectExplorer::Project *pro) const;
+ QString displayNameForName(const QString &name) const;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // QMAKEBUILDSTEPFACTORY_H
diff --git a/src/plugins/qt4projectmanager/qmakestep.cpp b/src/plugins/qt4projectmanager/qmakestep.cpp
new file mode 100644
index 0000000000..4798690923
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qmakestep.cpp
@@ -0,0 +1,272 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qmakestep.h"
+#include "qt4project.h"
+#include "qt4projectmanagerconstants.h"
+#include "qt4projectmanager.h"
+#include "makestep.h"
+#include "qtversionmanager.h"
+
+#include <coreplugin/icore.h>
+
+#include <QFileDialog>
+#include <QDir>
+#include <QFile>
+#include <QCoreApplication>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+using namespace ProjectExplorer;
+
+QMakeStep::QMakeStep(Qt4Project *project)
+ : AbstractProcessStep(project), m_pro(project), m_forced(false)
+{
+}
+
+QMakeStep::~QMakeStep()
+{
+}
+
+QStringList QMakeStep::arguments(const QString &buildConfiguration)
+{
+ QStringList additonalArguments = value(buildConfiguration, "qmakeArgs").toStringList();
+ QStringList arguments;
+ arguments << project()->file()->fileName();
+ if (!additonalArguments.contains("-spec")) {
+ if(m_pro->value("useVBOX").toBool()) { //NBS TODO don't special case VBOX like this
+ arguments << "-spec" << "linux-i686fb-g++";
+ arguments << "-unix";
+ } else {
+ arguments << "-spec" << m_pro->qtVersion(buildConfiguration)->mkspec();
+ }
+ }
+
+ arguments << "-r";
+
+ if (value(buildConfiguration, "buildConfiguration").isValid()) {
+ QStringList configarguments;
+ QtVersion::QmakeBuildConfig defaultBuildConfiguration = m_pro->qtVersion(buildConfiguration)->defaultBuildConfig();
+ QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(value(buildConfiguration, "buildConfiguration").toInt());
+ if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll))
+ configarguments << "CONFIG-=debug_and_release";
+ if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll))
+ configarguments << "CONFIG+=debug_and_release";
+ if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild))
+ configarguments << "CONFIG+=release";
+ if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild))
+ configarguments << "CONFIG+=debug";
+ arguments << configarguments;
+ } else {
+ arguments << "CONFIG+=debug_and_release";
+ }
+
+ if (!additonalArguments.isEmpty())
+ arguments << additonalArguments;
+
+ return arguments;
+}
+
+bool QMakeStep::init(const QString &name)
+{
+ m_buildConfiguration = name;
+ const QtVersion *qtVersion = m_pro->qtVersion(name);
+
+ if (!qtVersion->isValid()) {
+#if defined(Q_OS_MAC)
+ emit addToOutputWindow(tr("\n<font color=\"#ff0000\"><b>No valid Qt version set. Set one in Preferences </b></font>\n"));
+#else
+ emit addToOutputWindow(tr("\n<font color=\"#ff0000\"><b>No valid Qt version set. Set one in Tools/Options </b></font>\n"));
+#endif
+ return false;
+ }
+
+ QStringList args = arguments(name);
+ QString workingDirectory = m_pro->buildDirectory(name);
+
+ Environment environment = m_pro->environment(name);
+ if(!environment.value("QMAKESPEC").isEmpty() && environment.value("QMAKESPEC") != qtVersion->mkspec())
+ emit addToOutputWindow(tr("QMAKESPEC set to ") + environment.value("QMAKESPEC") +
+ tr(" overrides mkspec of selected qt ")+qtVersion->mkspec());
+
+ QString program = qtVersion->qmakeCommand();
+
+ // Check wheter we need to run qmake
+ bool needToRunQMake = true;
+ if (QDir(workingDirectory).exists(QLatin1String("Makefile")))
+ needToRunQMake = false;
+
+ QStringList newEnv = environment.toStringList();
+ newEnv.sort();
+
+ if (m_lastEnv != newEnv) {
+ m_lastEnv = newEnv;
+ needToRunQMake = true;
+ }
+ if (m_lastWorkingDirectory != workingDirectory) {
+ m_lastWorkingDirectory = workingDirectory;
+ needToRunQMake = true;
+ }
+
+ if (m_lastArguments != args) {
+ m_lastArguments = args;
+ needToRunQMake = true;
+ }
+
+ if (m_lastProgram != program) {
+ m_lastProgram = program;
+ needToRunQMake = true;
+ }
+
+ if (m_forced) {
+ m_forced = false;
+ needToRunQMake = true;
+ }
+
+ setEnabled(name, needToRunQMake);
+ setWorkingDirectory(name, workingDirectory);
+ setCommand(name, program);
+ setArguments(name, args);
+ setEnvironment(name, environment);
+ setWorkingDirectory(name, workingDirectory);
+ return AbstractProcessStep::init(name);
+}
+
+void QMakeStep::run(QFutureInterface<bool> &fi)
+{
+ if (qobject_cast<Qt4Project *>(project())->rootProjectNode()->projectType() == ScriptTemplate) {
+ fi.reportResult(true);
+ return;
+ }
+
+ if (!enabled(m_buildConfiguration)) {
+ emit addToOutputWindow(tr("<font color=\"#0000ff\">Configuration unchanged, skipping QMake step.</font>"));
+ fi.reportResult(true);
+ return;
+ }
+ AbstractProcessStep::run(fi);
+}
+
+QString QMakeStep::name()
+{
+ return Constants::QMAKESTEP;
+}
+
+QString QMakeStep::displayName()
+{
+ return "QMake";
+}
+
+void QMakeStep::setForced(bool b)
+{
+ m_forced = b;
+}
+
+bool QMakeStep::forced()
+{
+ return m_forced;
+}
+
+ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
+{
+ return new QMakeStepConfigWidget(this);
+}
+
+bool QMakeStep::immutable() const
+{
+ return true;
+}
+
+
+void QMakeStep::processStartupFailed()
+{
+ m_forced = true;
+ AbstractProcessStep::processStartupFailed();
+}
+
+bool QMakeStep::processFinished(int exitCode, QProcess::ExitStatus status)
+{
+ bool result = AbstractProcessStep::processFinished(exitCode, status);
+ if (!result)
+ m_forced = true;
+ return result;
+}
+
+QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
+ : BuildStepConfigWidget(), m_step(step)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.qmakeAdditonalArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(qmakeArgumentsLineEditTextEdited()));
+ connect(m_ui.buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(buildConfigurationChanged()));
+}
+
+void QMakeStepConfigWidget::qmakeArgumentsLineEditTextEdited()
+{
+ Q_ASSERT(!m_buildConfiguration.isNull());
+ m_step->setValue(m_buildConfiguration, "qmakeArgs", ProjectExplorer::Environment::parseCombinedArgString(m_ui.qmakeAdditonalArgumentsLineEdit->text()));
+ m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(m_buildConfiguration)));
+}
+
+void QMakeStepConfigWidget::buildConfigurationChanged()
+{
+ QtVersion::QmakeBuildConfig buildConfiguration = QtVersion::QmakeBuildConfig(m_step->value(m_buildConfiguration, "buildConfiguration").toInt());
+ if (m_ui.buildConfigurationComboBox->currentIndex() == 0) {
+ // debug
+ buildConfiguration = QtVersion::QmakeBuildConfig(buildConfiguration | QtVersion::DebugBuild);
+ } else {
+ buildConfiguration = QtVersion::QmakeBuildConfig(buildConfiguration & ~QtVersion::DebugBuild);
+ }
+ m_step->setValue(m_buildConfiguration, "buildConfiguration", int(buildConfiguration));
+ m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(m_buildConfiguration)));
+}
+
+QString QMakeStepConfigWidget::displayName() const
+{
+ return m_step->displayName();
+}
+
+void QMakeStepConfigWidget::init(const QString &buildConfiguration)
+{
+ m_buildConfiguration = buildConfiguration;
+ if (buildConfiguration.isEmpty()){
+ m_ui.stackedWidget->setCurrentWidget(m_ui.page_2);
+ } else {
+ m_ui.stackedWidget->setCurrentWidget(m_ui.page_1);
+ QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->value(buildConfiguration, "qmakeArgs").toStringList());
+ m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);
+ m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(buildConfiguration)));
+ bool debug = QtVersion::QmakeBuildConfig(m_step->value(buildConfiguration, "buildConfiguration").toInt()) & QtVersion::DebugBuild;
+ m_ui.buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
+ }
+}
+
diff --git a/src/plugins/qt4projectmanager/qmakestep.h b/src/plugins/qt4projectmanager/qmakestep.h
new file mode 100644
index 0000000000..5515603362
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qmakestep.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QMAKESTEP_H
+#define QMAKESTEP_H
+
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <QStringList>
+
+#include "ui_qmakestep.h"
+
+namespace Qt4ProjectManager {
+
+class Qt4Project;
+
+class QMakeStep : public ProjectExplorer::AbstractProcessStep
+{
+ Q_OBJECT
+public:
+ QMakeStep(Qt4Project * project);
+ ~QMakeStep();
+ virtual bool init(const QString & name);
+ virtual void run(QFutureInterface<bool> &);
+ virtual QString name();
+ virtual QString displayName();
+ virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
+ virtual bool immutable() const;
+ QStringList arguments(const QString &buildConfiguration);
+ void setForced(bool b);
+ bool forced();
+protected:
+ virtual void processStartupFailed();
+ virtual bool processFinished(int exitCode, QProcess::ExitStatus status);
+
+private:
+ Qt4Project *m_pro;
+ // last values
+ QString m_buildConfiguration;
+ QStringList m_lastEnv;
+ QString m_lastWorkingDirectory;
+ QStringList m_lastArguments;
+ QString m_lastProgram;
+ bool m_forced;
+};
+
+
+class QMakeStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+ Q_OBJECT
+public:
+ QMakeStepConfigWidget(QMakeStep *step);
+ QString displayName() const;
+ void init(const QString &buildConfiguration);
+private slots:
+ void qmakeArgumentsLineEditTextEdited();
+ void buildConfigurationChanged();
+private:
+ QString m_buildConfiguration;
+ Ui::QMakeStep m_ui;
+ QMakeStep *m_step;
+};
+
+} // namespace Qt4ProjectManager
+
+#endif // QMAKESTEP_H
diff --git a/src/plugins/qt4projectmanager/qmakestep.ui b/src/plugins/qt4projectmanager/qmakestep.ui
new file mode 100644
index 0000000000..df5fb98e39
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qmakestep.ui
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QMakeStep</class>
+ <widget class="QWidget" name="QMakeStep">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>414</width>
+ <height>442</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="page_1">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>QMake Build Configuration:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QComboBox" name="buildConfigurationComboBox">
+ <item>
+ <property name="text">
+ <string>debug</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>release</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="qmakeArgsLabel">
+ <property name="text">
+ <string>Additional arguments:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="qmakeAdditonalArgumentsLineEdit"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Arguments:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="qmakeArgumentsEdit">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>393</width>
+ <height>179</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_2"/>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/qt4buildconfigwidget.cpp b/src/plugins/qt4projectmanager/qt4buildconfigwidget.cpp
new file mode 100644
index 0000000000..5efb108686
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4buildconfigwidget.cpp
@@ -0,0 +1,257 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4buildconfigwidget.h"
+#include "ui_qt4buildconfigwidget.h"
+#include "qt4project.h"
+#include "qt4projectmanager.h"
+#include "qmakestep.h"
+#include "makestep.h"
+
+#include <QtGui/QFileDialog>
+
+namespace {
+bool debug = false;
+}
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+Qt4BuildConfigWidget::Qt4BuildConfigWidget(Qt4Project *project)
+ : BuildStepConfigWidget(),
+ m_pro(project)
+{
+ m_ui = new Ui::Qt4BuildConfigWidget();
+ m_ui->setupUi(this);
+ m_ui->invalidQtWarningLabel->setVisible(false);
+
+ connect(m_ui->nameLineEdit, SIGNAL(textEdited(QString)),
+ this, SLOT(changeConfigName(QString)));
+
+ connect(m_ui->shadowBuildCheckBox, SIGNAL(clicked(bool)),
+ this, SLOT(shadowBuildCheckBoxClicked(bool)));
+
+ connect(m_ui->shadowBuildButton, SIGNAL(clicked(bool)),
+ this, SLOT(shadowBuildButtonClicked()));
+
+ connect(m_ui->shadowBuildLineEdit, SIGNAL(textEdited(QString)),
+ this, SLOT(shadowBuildLineEditTextChanged()));
+
+ connect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
+ this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));
+
+ connect(m_ui->importLabel, SIGNAL(linkActivated(QString)),
+ this, SLOT(importLabelClicked()));
+
+ connect(m_pro->qt4ProjectManager()->versionManager(), SIGNAL(qtVersionsChanged()),
+ this, SLOT(setupQtVersionsComboBox()));
+
+}
+
+Qt4BuildConfigWidget::~Qt4BuildConfigWidget()
+{
+ delete m_ui;
+}
+
+QString Qt4BuildConfigWidget::displayName() const
+{
+ return tr("General");
+}
+
+void Qt4BuildConfigWidget::init(const QString &buildConfiguration)
+{
+ if (debug)
+ qDebug() << "Qt4BuildConfigWidget::init()";
+
+ m_buildConfiguration = buildConfiguration;
+
+ m_ui->nameLineEdit->setText(m_pro->displayNameFor(m_buildConfiguration));
+
+ setupQtVersionsComboBox();
+
+ bool shadowBuild = m_pro->value(buildConfiguration, "useShadowBuild").toBool();
+ m_ui->shadowBuildCheckBox->setChecked(shadowBuild);
+ m_ui->shadowBuildLineEdit->setEnabled(shadowBuild);
+ m_ui->shadowBuildLineEdit->setText(m_pro->buildDirectory(buildConfiguration));
+ shadowBuildLineEditTextChanged(); // Update the import label
+ m_ui->shadowBuildButton->setEnabled(shadowBuild);
+}
+
+void Qt4BuildConfigWidget::changeConfigName(const QString &newName)
+{
+ m_pro->setDisplayNameFor(m_buildConfiguration, newName);
+}
+
+void Qt4BuildConfigWidget::setupQtVersionsComboBox()
+{
+ if (m_buildConfiguration.isEmpty()) // not yet initialized
+ return;
+
+ disconnect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(const QString &)),
+ this, SLOT(qtVersionComboBoxCurrentIndexChanged(const QString &)));
+
+ m_ui->qtVersionComboBox->clear();
+ m_ui->qtVersionComboBox->addItem(tr("Default Qt Version"), 0);
+
+ if(m_pro->qtVersionId(m_buildConfiguration) == 0) {
+ m_ui->qtVersionComboBox->setCurrentIndex(0);
+ m_ui->invalidQtWarningLabel->setVisible(false);
+ }
+ // Add Qt Versions to the combo box
+ QtVersionManager *vm = m_pro->qt4ProjectManager()->versionManager();
+ const QList<QtVersion *> &versions = vm->versions();
+ for(int i=0; i<versions.size(); ++i) {
+ m_ui->qtVersionComboBox->addItem(versions.at(i)->name(), versions.at(i)->uniqueId());
+
+ if(versions.at(i)->uniqueId() == m_pro->qtVersionId(m_buildConfiguration)) {
+ m_ui->qtVersionComboBox->setCurrentIndex(i+1);
+ m_ui->invalidQtWarningLabel->setVisible(!versions.at(i)->isValid());
+ }
+ }
+
+ // And connect again
+ connect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(const QString &)),
+ this, SLOT(qtVersionComboBoxCurrentIndexChanged(const QString &)));
+}
+
+void Qt4BuildConfigWidget::shadowBuildButtonClicked()
+{
+ QString initialDirectory = m_ui->shadowBuildLineEdit->text();
+ if (initialDirectory.isEmpty())
+ initialDirectory = QFileInfo(m_pro->file()->fileName()).absolutePath();
+
+ QString shadowBuildDirectory =
+ QFileDialog::getExistingDirectory(this, tr("Shadow Build Directory"), initialDirectory );
+
+ if (shadowBuildDirectory != QString::null)
+ m_ui->shadowBuildLineEdit->setText(shadowBuildDirectory);
+ shadowBuildLineEditTextChanged();
+}
+
+void Qt4BuildConfigWidget::shadowBuildCheckBoxClicked(bool checked)
+{
+ m_ui->shadowBuildLineEdit->setEnabled(checked);
+ m_ui->shadowBuildButton->setEnabled(checked);
+ bool b = m_ui->shadowBuildCheckBox->isChecked();
+ m_pro->setValue(m_buildConfiguration, "useShadowBuild", b);
+ if (b)
+ m_pro->setValue(m_buildConfiguration, "buildDirectory", m_ui->shadowBuildLineEdit->text());
+ else
+ m_pro->setValue(m_buildConfiguration, "buildDirectory", QVariant(QString::null));
+}
+
+void Qt4BuildConfigWidget::shadowBuildLineEditTextChanged()
+{
+ m_pro->setValue(m_buildConfiguration, "buildDirectory", m_ui->shadowBuildLineEdit->text());
+ // if the directory already exists
+ // check if we have a build in there and
+ // offer to import it
+ m_ui->importLabel->setVisible(false);
+ if (m_ui->shadowBuildCheckBox->isChecked()) {
+ QString qtPath = m_pro->qt4ProjectManager()->versionManager()->findQtVersionFromMakefile(m_ui->shadowBuildLineEdit->text());
+ if(!qtPath.isEmpty()) {
+ m_ui->importLabel->setVisible(true);
+ }
+ }
+
+// QFileInfo fi(m_ui->shadowBuildLineEdit->text());
+// if (fi.exists()) {
+// m_ui->shadowBuildLineEdit->setStyleSheet("");
+// m_ui->shadowBuildLineEdit->setToolTip("");
+// } else {
+// m_ui->shadowBuildLineEdit->setStyleSheet("background: red;");
+// m_ui->shadowBuildLineEdit->setToolTip(tr("Directory does not exist."));
+// }
+}
+
+void Qt4BuildConfigWidget::importLabelClicked()
+{
+ if (m_ui->shadowBuildCheckBox->isChecked()) {
+ QString directory = m_ui->shadowBuildLineEdit->text();
+ if (!directory.isEmpty()) {
+ QtVersionManager *vm = m_pro->qt4ProjectManager()->versionManager();
+ QString qtPath = vm->findQtVersionFromMakefile(directory);
+ if (!qtPath.isEmpty()) {
+ QtVersion *version = vm->qtVersionForDirectory(qtPath);
+ if (!version) {
+ version = new QtVersion(QFileInfo(qtPath).baseName(), qtPath);
+ vm->addVersion(version);
+ }
+ QtVersion::QmakeBuildConfig qmakeBuildConfig = version->defaultBuildConfig();
+ qmakeBuildConfig = vm->scanMakefileForQmakeConfig(directory, qmakeBuildConfig);
+
+ // So we got all the information now apply it...
+ m_pro->setQtVersion(m_buildConfiguration, version->uniqueId());
+ // Combo box will be updated at the end
+
+ // Find qmakestep...
+ QMakeStep *qmakeStep = m_pro->qmakeStep();
+ MakeStep *makeStep = m_pro->makeStep();
+
+ qmakeStep->setValue(m_buildConfiguration, "buildConfiguration", int(qmakeBuildConfig));
+ // Adjust command line arguments, this is ugly as hell
+ // If we are switching to BuildAll we want "release" in there and no "debug"
+ // or "debug" in there and no "release"
+ // If we are switching to not BuildAl we want neither "release" nor "debug" in there
+ QStringList makeCmdArguments = makeStep->value(m_buildConfiguration, "makeargs").toStringList();
+ bool debug = qmakeBuildConfig & QtVersion::DebugBuild;
+ if (qmakeBuildConfig & QtVersion::BuildAll) {
+ makeCmdArguments.removeAll(debug ? "release" : "debug");
+ if (!makeCmdArguments.contains(debug ? "debug" : "release"))
+ makeCmdArguments.append(debug ? "debug" : "release");
+ } else {
+ makeCmdArguments.removeAll("debug");
+ makeCmdArguments.removeAll("remove");
+ }
+ makeStep->setValue(m_buildConfiguration, "makeargs", makeCmdArguments);
+ }
+ }
+ }
+ setupQtVersionsComboBox();
+}
+
+void Qt4BuildConfigWidget::qtVersionComboBoxCurrentIndexChanged(const QString &)
+{
+ //Qt Version
+ int newQtVersion;
+ if (m_ui->qtVersionComboBox->currentIndex() == 0) {
+ newQtVersion = 0;
+ } else {
+ newQtVersion = m_ui->qtVersionComboBox->itemData(m_ui->qtVersionComboBox->currentIndex()).toInt();
+ }
+ bool isValid = m_pro->qt4ProjectManager()->versionManager()->version(newQtVersion)->isValid();
+ m_ui->invalidQtWarningLabel->setVisible(!isValid);
+ if(newQtVersion != m_pro->qtVersionId(m_buildConfiguration)) {
+ m_pro->setQtVersion(m_buildConfiguration, newQtVersion);
+ m_pro->update();
+ }
+}
diff --git a/src/plugins/qt4projectmanager/qt4buildconfigwidget.h b/src/plugins/qt4projectmanager/qt4buildconfigwidget.h
new file mode 100644
index 0000000000..725ed18bdc
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4buildconfigwidget.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4BUILDCONFIGWIDGET_H
+#define QT4BUILDCONFIGWIDGET_H
+
+#include <projectexplorer/buildstep.h>
+
+namespace Qt4ProjectManager {
+
+class Qt4Project;
+
+namespace Internal {
+
+namespace Ui {
+class Qt4BuildConfigWidget;
+}
+
+class Qt4BuildConfigWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+ Q_OBJECT
+public:
+ Qt4BuildConfigWidget(Qt4Project *project);
+ ~Qt4BuildConfigWidget();
+
+ QString displayName() const;
+ void init(const QString &buildConfiguration);
+
+private slots:
+ void changeConfigName(const QString &newName);
+ void setupQtVersionsComboBox();
+ void shadowBuildCheckBoxClicked(bool checked);
+ void shadowBuildButtonClicked();
+ void shadowBuildLineEditTextChanged();
+ void importLabelClicked();
+ void qtVersionComboBoxCurrentIndexChanged(const QString &);
+
+private:
+ Ui::Qt4BuildConfigWidget *m_ui;
+ Qt4Project *m_pro;
+ QString m_buildConfiguration;
+};
+
+} // Internal
+} // Qt4ProjectManager
+
+#endif // QT4BUILDCONFIGWIDGET_H
diff --git a/src/plugins/qt4projectmanager/qt4buildconfigwidget.ui b/src/plugins/qt4projectmanager/qt4buildconfigwidget.ui
new file mode 100644
index 0000000000..f62d4a69b5
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4buildconfigwidget.ui
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Qt4ProjectManager::Internal::Qt4BuildConfigWidget</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::Qt4BuildConfigWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>652</width>
+ <height>247</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Configuration Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameLineEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>100</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="qtVersionLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Qt Version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="qtVersionComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="invalidQtWarningLabel">
+ <property name="text">
+ <string>This Qt-Version is invalid.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Shadow Build</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="shadowBuildCheckBox">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="buildDirLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Build Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLineEdit" name="shadowBuildLineEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>100</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="shadowBuildButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="importLabel">
+ <property name="text">
+ <string>&lt;a href=&quot;import&quot;&gt;Import existing build&lt;/a&gt;</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.cpp b/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.cpp
new file mode 100644
index 0000000000..7c3a73781f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.cpp
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4buildenvironmentwidget.h"
+#include "ui_qt4buildenvironmentwidget.h"
+
+#include "qt4project.h"
+#include <projectexplorer/environmenteditmodel.h>
+
+namespace {
+bool debug = false;
+}
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+using ProjectExplorer::EnvironmentModel;
+
+Qt4BuildEnvironmentWidget::Qt4BuildEnvironmentWidget(Qt4Project *project)
+ : BuildStepConfigWidget(), m_pro(project)
+{
+ m_ui = new Ui::Qt4BuildEnvironmentWidget();
+ m_ui->setupUi(this);
+
+ m_environmentModel = new EnvironmentModel();
+ m_environmentModel->setMergedEnvironments(true);
+ m_ui->environmentTreeView->setModel(m_environmentModel);
+ m_ui->environmentTreeView->header()->resizeSection(0, 250);
+
+ connect(m_environmentModel, SIGNAL(userChangesUpdated()),
+ this, SLOT(environmentModelUserChangesUpdated()));
+
+ connect(m_environmentModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
+ this, SLOT(updateButtonsEnabled()));
+
+ connect(m_ui->editButton, SIGNAL(clicked(bool)),
+ this, SLOT(editEnvironmentButtonClicked()));
+ connect(m_ui->addButton, SIGNAL(clicked(bool)),
+ this, SLOT(addEnvironmentButtonClicked()));
+ connect(m_ui->removeButton, SIGNAL(clicked(bool)),
+ this, SLOT(removeEnvironmentButtonClicked()));
+ connect(m_ui->unsetButton, SIGNAL(clicked(bool)),
+ this, SLOT(unsetEnvironmentButtonClicked()));
+ connect(m_ui->environmentTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex &)),
+ this, SLOT(environmentCurrentIndexChanged(const QModelIndex &, const QModelIndex &)));
+ connect(m_ui->clearSystemEnvironmentCheckBox, SIGNAL(toggled(bool)),
+ this, SLOT(clearSystemEnvironmentCheckBoxClicked(bool)));
+}
+
+Qt4BuildEnvironmentWidget::~Qt4BuildEnvironmentWidget()
+{
+ delete m_ui;
+ delete m_environmentModel;
+}
+
+QString Qt4BuildEnvironmentWidget::displayName() const
+{
+ return tr("Build Environment");
+}
+
+void Qt4BuildEnvironmentWidget::init(const QString &buildConfiguration)
+{
+ if (debug)
+ qDebug() << "Qt4BuildConfigWidget::init()";
+
+ m_buildConfiguration = buildConfiguration;
+ m_ui->clearSystemEnvironmentCheckBox->setChecked(!m_pro->useSystemEnvironment(buildConfiguration));
+ m_environmentModel->setBaseEnvironment(m_pro->baseEnvironment(buildConfiguration));
+ m_environmentModel->setUserChanges(m_pro->userEnvironmentChanges(buildConfiguration));
+
+ updateButtonsEnabled();
+}
+
+
+void Qt4BuildEnvironmentWidget::editEnvironmentButtonClicked()
+{
+ m_ui->environmentTreeView->edit(m_ui->environmentTreeView->currentIndex());
+}
+
+void Qt4BuildEnvironmentWidget::addEnvironmentButtonClicked()
+{
+ QModelIndex index = m_environmentModel->addVariable();
+ m_ui->environmentTreeView->setCurrentIndex(index);
+ m_ui->environmentTreeView->edit(index);
+ updateButtonsEnabled();
+}
+
+void Qt4BuildEnvironmentWidget::removeEnvironmentButtonClicked()
+{
+ const QString &name = m_environmentModel->indexToVariable(m_ui->environmentTreeView->currentIndex());
+ m_environmentModel->removeVariable(name);
+ updateButtonsEnabled();
+}
+// unset in Merged Environment Mode means, unset if it comes from the base environment
+// or remove when it is just a change we added
+// unset in changes view, means just unset
+void Qt4BuildEnvironmentWidget::unsetEnvironmentButtonClicked()
+{
+ const QString &name = m_environmentModel->indexToVariable(m_ui->environmentTreeView->currentIndex());
+ if(!m_environmentModel->isInBaseEnvironment(name) && m_environmentModel->mergedEnvironments())
+ m_environmentModel->removeVariable(name);
+ else
+ m_environmentModel->unset(name);
+ updateButtonsEnabled();
+}
+
+void Qt4BuildEnvironmentWidget::switchEnvironmentTab(int newTab)
+{
+ bool mergedEnvironments = (newTab == 0);
+ m_environmentModel->setMergedEnvironments(mergedEnvironments);
+ if(mergedEnvironments) {
+ m_ui->removeButton->setText(tr("Reset"));
+ } else {
+ m_ui->removeButton->setText(tr("Remove"));
+ }
+}
+
+void Qt4BuildEnvironmentWidget::updateButtonsEnabled()
+{
+ environmentCurrentIndexChanged(m_ui->environmentTreeView->currentIndex(), QModelIndex());
+}
+
+void Qt4BuildEnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ Q_UNUSED(previous)
+ if(current.isValid()) {
+ if(m_environmentModel->mergedEnvironments()) {
+ const QString &name = m_environmentModel->indexToVariable(current);
+ bool modified = m_environmentModel->isInBaseEnvironment(name) && m_environmentModel->changes(name);
+ bool unset = m_environmentModel->isUnset(name);
+ m_ui->removeButton->setEnabled(modified || unset);
+ m_ui->unsetButton->setEnabled(!unset);
+ return;
+ } else {
+ m_ui->removeButton->setEnabled(true);
+ m_ui->unsetButton->setEnabled(!m_environmentModel->isUnset(m_environmentModel->indexToVariable(current)));
+ return;
+ }
+ }
+ m_ui->editButton->setEnabled(current.isValid());
+ m_ui->removeButton->setEnabled(false);
+ m_ui->unsetButton->setEnabled(false);
+}
+
+void Qt4BuildEnvironmentWidget::clearSystemEnvironmentCheckBoxClicked(bool checked)
+{
+ m_pro->setUseSystemEnvironment(m_buildConfiguration, !checked);
+ m_environmentModel->setBaseEnvironment(m_pro->baseEnvironment(m_buildConfiguration));
+}
+
+void Qt4BuildEnvironmentWidget::environmentModelUserChangesUpdated()
+{
+ m_pro->setUserEnvironmentChanges(m_buildConfiguration, m_environmentModel->userChanges());
+}
diff --git a/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.h b/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.h
new file mode 100644
index 0000000000..fe134206ec
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4BUILDENVIRONMENTWIDGET_H
+#define QT4BUILDENVIRONMENTWIDGET_H
+
+#include <projectexplorer/buildstep.h>
+
+namespace ProjectExplorer {
+class EnvironmentModel;
+}
+
+namespace Qt4ProjectManager {
+
+class Qt4Project;
+
+namespace Internal {
+
+namespace Ui {
+class Qt4BuildEnvironmentWidget;
+}
+
+class Qt4BuildEnvironmentWidget : public ProjectExplorer::BuildStepConfigWidget
+{
+ Q_OBJECT
+public:
+ Qt4BuildEnvironmentWidget(Qt4Project *project);
+ ~Qt4BuildEnvironmentWidget();
+
+ QString displayName() const;
+ void init(const QString &buildConfiguration);
+
+private slots:
+ void environmentModelUserChangesUpdated();
+ void editEnvironmentButtonClicked();
+ void addEnvironmentButtonClicked();
+ void removeEnvironmentButtonClicked();
+ void unsetEnvironmentButtonClicked();
+ void switchEnvironmentTab(int newTab);
+ void environmentCurrentIndexChanged(const QModelIndex &current, const QModelIndex &previous);
+ void clearSystemEnvironmentCheckBoxClicked(bool);
+ void updateButtonsEnabled();
+
+private:
+ Ui::Qt4BuildEnvironmentWidget *m_ui;
+ Qt4Project *m_pro;
+ ProjectExplorer::EnvironmentModel *m_environmentModel;
+ QString m_buildConfiguration;
+};
+
+} // Internal
+} // Qt4ProjectManager
+
+#endif // QT4BUILDENVIRONMENTWIDGET_H
diff --git a/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.ui b/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.ui
new file mode 100644
index 0000000000..354ac61e89
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4buildenvironmentwidget.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Qt4ProjectManager::Internal::Qt4BuildEnvironmentWidget</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::Qt4BuildEnvironmentWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="clearSystemEnvironmentCheckBox">
+ <property name="text">
+ <string>Clear system environment</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="environmentTreeView">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="headerHidden">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QPushButton" name="editButton">
+ <property name="text">
+ <string>&amp;Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Reset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="unsetButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Unset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
new file mode 100644
index 0000000000..847d6ae38f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4nodes.cpp
@@ -0,0 +1,975 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "proeditormodel.h"
+#include "profilecache.h"
+#include "profilereader.h"
+#include "qt4nodes.h"
+#include "qt4project.h"
+#include "qt4projectmanager.h"
+#include "directorywatcher.h"
+
+#include <projectexplorer/nodesvisitor.h>
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+
+#include <cpptools/cppmodelmanagerinterface.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+namespace {
+ bool debug = false;
+}
+
+namespace {
+ // sorting helper function
+ bool sortProjectFilesByPath(ProFile *f1, ProFile *f2)
+ {
+ return f1->fileName() < f2->fileName();
+ }
+}
+
+/*!
+ \class Qt4PriFileNode
+ Implements abstract ProjectNode class
+ */
+
+Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project,
+ const QString &filePath)
+ : ProjectNode(filePath),
+ m_core(project->qt4ProjectManager()->core()),
+ m_project(project),
+ m_projectFilePath(filePath),
+ m_projectDir(QFileInfo(filePath).absolutePath()),
+ m_includeFile(0),
+ m_saveTimer(new QTimer(this))
+{
+ Q_ASSERT(project);
+ setFolderName(QFileInfo(filePath).baseName());
+ setIcon(QIcon(":/qt4projectmanager/images/qt_project.png"));
+
+ // m_saveTimer is used for the delayed saving of the pro file
+ // so that multiple insert/remove calls in one event loop run
+ // trigger just one save call.
+ m_saveTimer->setSingleShot(true);
+ connect(m_saveTimer, SIGNAL(timeout()), this, SLOT(save()));
+}
+
+void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
+{
+ Q_ASSERT(includeFile);
+ Q_ASSERT(reader);
+
+ m_includeFile = includeFile;
+
+ // add project file node
+ if (m_fileNodes.isEmpty())
+ addFileNodes(QList<FileNode*>() << new FileNode(m_projectFilePath, ProjectFileType, false), this);
+
+ static QList<FileType> fileTypes =
+ (QList<FileType>() << ProjectExplorer::HeaderType
+ << ProjectExplorer::SourceType
+ << ProjectExplorer::FormType
+ << ProjectExplorer::ResourceType
+ << ProjectExplorer::UnknownFileType);
+
+ // update files
+ const QDir projectDir = QFileInfo(m_projectFilePath).dir();
+ foreach (FileType type, fileTypes) {
+ const QStringList qmakeVariables = varNames(type);
+
+ QStringList newFilePaths;
+ foreach (const QString &qmakeVariable, qmakeVariables)
+ newFilePaths += reader->absolutePathValues(qmakeVariable, projectDir.path(), ProFileReader::ExistingFilePaths, includeFile);
+
+ QList<FileNode*> existingFileNodes;
+ foreach (FileNode *fileNode, fileNodes()) {
+ if (fileNode->fileType() == type && !fileNode->isGenerated())
+ existingFileNodes << fileNode;
+ }
+
+ QList<FileNode*> toRemove;
+ QList<FileNode*> toAdd;
+
+ qSort(newFilePaths);
+ qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
+
+ QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
+ QList<QString>::const_iterator newPathIter = newFilePaths.constBegin();
+ while (existingNodeIter != existingFileNodes.constEnd()
+ && newPathIter != newFilePaths.constEnd()) {
+ if ((*existingNodeIter)->path() < *newPathIter) {
+ toRemove << *existingNodeIter;
+ ++existingNodeIter;
+ } else if ((*existingNodeIter)->path() > *newPathIter) {
+ toAdd << new FileNode(*newPathIter, type, false);
+ ++newPathIter;
+ } else { // *existingNodeIter->path() == *newPathIter
+ ++existingNodeIter;
+ ++newPathIter;
+ }
+ }
+ while (existingNodeIter != existingFileNodes.constEnd()) {
+ toRemove << *existingNodeIter;
+ ++existingNodeIter;
+ }
+ while (newPathIter != newFilePaths.constEnd()) {
+ toAdd << new FileNode(*newPathIter, type, false);
+ ++newPathIter;
+ }
+
+ if (!toRemove.isEmpty())
+ removeFileNodes(toRemove, this);
+ if (!toAdd.isEmpty())
+ addFileNodes(toAdd, this);
+ }
+}
+
+QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
+{
+ QList<ProjectAction> actions;
+ if (m_includeFile) {
+ const FolderNode *folderNode = this;
+ const Qt4ProFileNode *proFileNode;
+ while (!(proFileNode = qobject_cast<const Qt4ProFileNode*>(folderNode)))
+ folderNode = folderNode->parentFolderNode();
+ Q_ASSERT(proFileNode);
+
+ switch (proFileNode->projectType()) {
+ case ApplicationTemplate:
+ case LibraryTemplate:
+ actions << AddFile << RemoveFile;
+ break;
+ case SubDirsTemplate:
+ actions << AddSubProject << RemoveSubProject;
+ break;
+ default:
+ break;
+ }
+ }
+ return actions;
+}
+
+bool Qt4PriFileNode::addSubProjects(const QStringList &proFilePaths)
+{
+ if (!m_includeFile)
+ return false;
+ return changeIncludes(m_includeFile, proFilePaths, AddToProFile);
+}
+
+bool Qt4PriFileNode::removeSubProjects(const QStringList &proFilePaths)
+{
+ if (!m_includeFile)
+ return false;
+ return changeIncludes(m_includeFile, proFilePaths, RemoveFromProFile);
+}
+
+bool Qt4PriFileNode::addFiles(const FileType fileType, const QStringList &filePaths,
+ QStringList *notAdded)
+{
+ if (!m_includeFile)
+ return false;
+ QStringList failedFiles;
+
+ changeFiles(fileType, filePaths, &failedFiles, AddToProFile);
+ if (notAdded)
+ *notAdded = failedFiles;
+ return failedFiles.isEmpty();
+}
+
+bool Qt4PriFileNode::removeFiles(const FileType fileType, const QStringList &filePaths,
+ QStringList *notRemoved)
+{
+ if (!m_includeFile)
+ return false;
+ QStringList failedFiles;
+ changeFiles(fileType, filePaths, &failedFiles, RemoveFromProFile);
+ if (notRemoved)
+ *notRemoved = failedFiles;
+ return failedFiles.isEmpty();
+}
+
+bool Qt4PriFileNode::renameFile(const FileType fileType, const QString &filePath,
+ const QString &newFilePath)
+{
+ if (!m_includeFile || newFilePath.isEmpty())
+ return false;
+
+ if (!QFile::rename(filePath, newFilePath))
+ return false;
+
+ QStringList dummy;
+ changeFiles(fileType, QStringList() << filePath, &dummy, RemoveFromProFile);
+ if (!dummy.isEmpty())
+ return false;
+ changeFiles(fileType, QStringList() << newFilePath, &dummy, AddToProFile);
+ if (!dummy.isEmpty())
+ return false;
+ return true;
+}
+
+bool Qt4PriFileNode::changeIncludes(ProFile *includeFile, const QStringList &proFilePaths,
+ ChangeType change)
+{
+ Q_UNUSED(includeFile);
+ Q_UNUSED(proFilePaths);
+ Q_UNUSED(change);
+ // TODO
+ return false;
+}
+
+
+namespace {
+ enum ReadOnlyAction { RO_Cancel, RO_OpenSCC, RO_MakeWriteable };
+}
+
+static ReadOnlyAction promptReadOnly(const QString &fileName, bool hasSCC, QWidget *parent)
+{
+ QMessageBox msgBox(QMessageBox::Question, QObject::tr("File is Read Only"),
+ QObject::tr("The file %1 is read only.").arg(fileName),
+ QMessageBox::Cancel, parent);
+
+ QPushButton *sccButton = 0;
+ if (hasSCC)
+ sccButton = msgBox.addButton(QObject::tr("Open with SCC"), QMessageBox::AcceptRole);
+ QPushButton *makeWritableButton = msgBox.addButton(QObject::tr("Make writable"), QMessageBox::AcceptRole);
+ if (hasSCC)
+ msgBox.setDefaultButton(sccButton);
+ else
+ msgBox.setDefaultButton(makeWritableButton);
+ msgBox.exec();
+ QAbstractButton *clickedButton = msgBox.clickedButton();
+ if (clickedButton == sccButton)
+ return RO_OpenSCC;
+ if (clickedButton == makeWritableButton)
+ return RO_MakeWriteable;
+ return RO_Cancel;
+}
+
+bool Qt4PriFileNode::priFileWritable(const QString &path)
+{
+ const QString dir = QFileInfo(path).dir().path();
+ Core::IVersionControl *versionControl = m_core->vcsManager()->findVersionControlForDirectory(dir);
+ switch (promptReadOnly(path, versionControl != 0, m_core->mainWindow())) {
+ case RO_OpenSCC:
+ if (!versionControl->vcsOpen(path)) {
+ QMessageBox::warning(m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for edit with SCC."));
+ return false;
+ }
+ break;
+ case RO_MakeWriteable: {
+ const bool permsOk = QFile::setPermissions(path, QFile::permissions(path) | QFile::WriteUser);
+ if (!permsOk) {
+ QMessageBox::warning(m_core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable."));
+ return false;
+ }
+ break;
+ }
+ case RO_Cancel: {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Qt4PriFileNode::saveModifiedEditors(const QString &path)
+{
+ QList<Core::IFile*> allFileHandles;
+ QList<Core::IFile*> modifiedFileHandles;
+
+ foreach (Core::IFile *file, m_core->fileManager()->managedFiles(path)) {
+ allFileHandles << file;
+ }
+
+ foreach (Core::IEditor *editor, m_core->editorManager()->editorsForFileName(path)) {
+ if (Core::IFile *editorFile = editor->file()) {
+ if (editorFile->isModified())
+ modifiedFileHandles << editorFile;
+ }
+ }
+
+ if (!modifiedFileHandles.isEmpty()) {
+ bool cancelled;
+ m_core->fileManager()->saveModifiedFiles(modifiedFileHandles, &cancelled,
+ tr("There are unsaved changes for project file %1.").arg(path));
+ if (cancelled)
+ return false;
+ // force instant reload
+ foreach (Core::IFile *fileHandle, allFileHandles) {
+ Core::IFile::ReloadBehavior reload = Core::IFile::ReloadAll;
+ fileHandle->modified(&reload);
+ }
+ }
+ return true;
+}
+
+void Qt4PriFileNode::changeFiles(const FileType fileType,
+ const QStringList &filePaths,
+ QStringList *notChanged,
+ ChangeType change)
+{
+ if (filePaths.isEmpty())
+ return;
+
+ *notChanged = filePaths;
+
+ // Check for modified editors
+ if (!saveModifiedEditors(m_projectFilePath))
+ return;
+
+ // Check if file is readonly
+ ProFileCache *cache = m_project->qt4ProjectManager()->proFileCache();
+ if (cache->fileInterface(m_projectFilePath)->isReadOnly() && !priFileWritable(m_projectFilePath))
+ return;
+
+ ProEditorModel proModel;
+ proModel.setProFiles(QList<ProFile*>() << m_includeFile);
+
+ const QStringList vars = varNames(fileType);
+ QDir priFileDir = QDir(m_projectDir);
+
+ if (change == AddToProFile) {
+ // root item "<Global Scope>"
+ const QModelIndex root = proModel.index(0, 0);
+
+ // Check if variable item exists as child of root item
+ ProVariable *proVar = 0;
+ int row = 0;
+ for (; row < proModel.rowCount(root); ++row) {
+ if ((proVar = proModel.proVariable(root.child(row, 0)))) {
+ if (vars.contains(proVar->variable())
+ && proVar->variableOperator() != ProVariable::RemoveOperator
+ && proVar->variableOperator() != ProVariable::ReplaceOperator)
+ break;
+ else
+ proVar = 0;
+ }
+ }
+
+ if (!proVar) {
+ // Create & append new variable item
+
+ // TODO: This will always store e.g. a source file in SOURCES and not OBJECTIVE_SOURCES
+ proVar = new ProVariable(vars.first(), proModel.proBlock(root));
+ proVar->setVariableOperator(ProVariable::AddOperator);
+ proModel.insertItem(proVar, row, root);
+ }
+ const QModelIndex varIndex = root.child(row, 0);
+
+ foreach (const QString &filePath, filePaths) {
+ const QString &relativeFilePath = priFileDir.relativeFilePath(filePath);
+ proModel.insertItem(new ProValue(relativeFilePath, proVar),
+ proModel.rowCount(varIndex), varIndex);
+ notChanged->removeOne(filePath);
+ }
+ } else { // RemoveFromProFile
+ QList<QModelIndex> proVarIndexes = proModel.findVariables(vars);
+ QList<QModelIndex> toRemove;
+
+ QStringList relativeFilePaths;
+ foreach (const QString &absoluteFilePath, filePaths)
+ relativeFilePaths << priFileDir.relativeFilePath(absoluteFilePath);
+
+ foreach (const QModelIndex &proVarIndex, proVarIndexes) {
+ ProVariable *proVar = proModel.proVariable(proVarIndex);
+
+ if (proVar->variableOperator() != ProVariable::RemoveOperator
+ && proVar->variableOperator() != ProVariable::ReplaceOperator) {
+
+ for (int row = proModel.rowCount(proVarIndex) - 1; row >= 0; --row) {
+ QModelIndex itemIndex = proModel.index(row, 0, proVarIndex);
+ ProItem *item = proModel.proItem(itemIndex);
+
+ if (item->kind() == ProItem::ValueKind) {
+ ProValue *val = static_cast<ProValue *>(item);
+ int index = relativeFilePaths.indexOf(val->value());
+ if (index != -1) {
+ toRemove.append(itemIndex);
+ notChanged->removeAt(index);
+ }
+ }
+ }
+ }
+ }
+
+ foreach (const QModelIndex &index, toRemove) {
+ proModel.removeItem(index);
+ }
+ }
+
+ // save file
+ if (!m_saveTimer->isActive())
+ m_saveTimer->start();
+}
+
+void Qt4PriFileNode::save()
+{
+ // Prevent any reload questions; just reload
+ Core::FileManager *fileManager = m_core->fileManager();
+ ProFileCache *cache = m_project->qt4ProjectManager()->proFileCache();
+
+ QList<Core::IFile *> allFileHandles = fileManager->managedFiles(m_includeFile->fileName());
+ Core::IFile *modifiedFileHandle = cache->fileInterface(m_includeFile->fileName());
+
+ fileManager->blockFileChange(modifiedFileHandle);
+ modifiedFileHandle->save();
+ fileManager->unblockFileChange(modifiedFileHandle);
+
+ Core::IFile::ReloadBehavior tempBehavior =
+ Core::IFile::ReloadAll;
+ foreach (Core::IFile *file, allFileHandles) {
+ file->modified(&tempBehavior);
+ }
+}
+
+/*
+ Deletes all subprojects/files/virtual folders
+ */
+void Qt4PriFileNode::clear()
+{
+ // delete files && folders && projects
+ if (!fileNodes().isEmpty())
+ removeFileNodes(fileNodes(), this);
+ if (!subProjectNodes().isEmpty())
+ removeProjectNodes(subProjectNodes());
+ if (!subFolderNodes().isEmpty())
+ removeFolderNodes(subFolderNodes(), this);
+}
+
+QStringList Qt4PriFileNode::varNames(FileType type)
+{
+ QStringList vars;
+ switch (type) {
+ case ProjectExplorer::HeaderType:
+ vars << QLatin1String("HEADERS");
+ break;
+ case ProjectExplorer::SourceType:
+ vars << QLatin1String("SOURCES");
+ vars << QLatin1String("OBJECTIVE_SOURCES");
+ break;
+ case ProjectExplorer::ResourceType:
+ vars << QLatin1String("RESOURCES");
+ break;
+ case ProjectExplorer::FormType:
+ vars << QLatin1String("FORMS");
+ break;
+ default:
+ vars << QLatin1String("OTHER_FILES");
+ break;
+ }
+ return vars;
+}
+
+/*!
+ \class Qt4ProFileNode
+ Implements abstract ProjectNode class
+ */
+Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project,
+ const QString &filePath,
+ QObject *parent)
+ : Qt4PriFileNode(project, filePath),
+ // own stuff
+ m_projectType(InvalidProject),
+ m_isQBuildProject(false),
+ m_cache(project->qt4ProjectManager()->proFileCache()),
+ m_dirWatcher(new DirectoryWatcher(this))
+{
+ if (parent)
+ setParent(parent);
+
+ connect(m_dirWatcher, SIGNAL(directoryChanged(const QString&)),
+ this, SLOT(update()));
+ connect(m_dirWatcher, SIGNAL(fileChanged(const QString&)),
+ this, SLOT(fileChanged(const QString&)));
+ connect(m_project, SIGNAL(activeBuildConfigurationChanged()),
+ this, SLOT(update()));
+}
+
+bool Qt4ProFileNode::hasTargets() const
+{
+ return (projectType() == ApplicationTemplate) || (projectType() == LibraryTemplate);
+}
+
+Qt4ProjectType Qt4ProFileNode::projectType() const
+{
+ return m_projectType;
+}
+
+QStringList Qt4ProFileNode::variableValue(const Qt4Variable var) const
+{
+ return m_varValues.value(var);
+}
+
+void Qt4ProFileNode::update()
+{
+ ProFileReader *reader = createProFileReader();
+ if (!reader->readProFile(m_projectFilePath)) {
+ m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath));
+ delete reader;
+ invalidate();
+ return;
+ }
+
+ if (debug)
+ qDebug() << "Qt4ProFileNode - updating files for file " << m_projectFilePath;
+
+#ifdef QTEXTENDED_QBUILD_SUPPORT
+ if (m_projectFilePath.endsWith("qbuild.pro")) {
+ m_isQBuildProject = true;
+ }
+#endif
+
+ Qt4ProjectType projectType = InvalidProject;
+ switch (reader->templateType()) {
+ case ProFileEvaluator::TT_Unknown:
+ case ProFileEvaluator::TT_Application: {
+ projectType = ApplicationTemplate;
+ break;
+ }
+ case ProFileEvaluator::TT_Library: {
+ projectType = LibraryTemplate;
+ break;
+ }
+ case ProFileEvaluator::TT_Script: {
+ projectType = ScriptTemplate;
+ break;
+ }
+ case ProFileEvaluator::TT_Subdirs:
+ projectType = SubDirsTemplate;
+ break;
+ }
+ if (projectType != m_projectType) {
+ Qt4ProjectType oldType = m_projectType;
+ // probably all subfiles/projects have changed anyway ...
+ clear();
+ m_projectType = projectType;
+ foreach (NodesWatcher *watcher, watchers())
+ if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
+ emit qt4Watcher->projectTypeChanged(this, oldType, projectType);
+ }
+
+ //
+ // Add/Remove pri files, sub projects
+ //
+
+ QList<ProjectNode*> existingProjectNodes = subProjectNodes();
+
+ QList<QString> newProjectFiles;
+ QHash<QString, ProFile*> includeFiles;
+ ProFile *fileForCurrentProject = 0;
+ {
+ if (projectType == SubDirsTemplate) {
+ foreach (const QString &subDirProject, subDirsPaths(reader))
+ newProjectFiles << subDirProject;
+ }
+
+ foreach (ProFile *includeFile, reader->includeFiles()) {
+ if (includeFile->fileName() == m_projectFilePath) { // this file
+ fileForCurrentProject = includeFile;
+ } else {
+ newProjectFiles << includeFile->fileName();
+ includeFiles.insert(includeFile->fileName(), includeFile);
+ }
+ }
+ }
+
+ qSort(existingProjectNodes.begin(), existingProjectNodes.end(),
+ sortNodesByPath);
+ qSort(newProjectFiles.begin(), newProjectFiles.end());
+
+ QList<ProjectNode*> toAdd;
+ QList<ProjectNode*> toRemove;
+
+ QList<ProjectNode*>::const_iterator existingNodeIter = existingProjectNodes.constBegin();
+ QList<QString>::const_iterator newProjectFileIter = newProjectFiles.constBegin();
+ while (existingNodeIter != existingProjectNodes.constEnd()
+ && newProjectFileIter != newProjectFiles.constEnd()) {
+ if ((*existingNodeIter)->path() < *newProjectFileIter) {
+ toRemove << *existingNodeIter;
+ ++existingNodeIter;
+ } else if ((*existingNodeIter)->path() > *newProjectFileIter) {
+ if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
+ Qt4PriFileNode *priFileNode
+ = new Qt4PriFileNode(m_project,
+ *newProjectFileIter);
+ priFileNode->update(file, reader);
+ toAdd << priFileNode;
+ } else {
+ toAdd << createSubProFileNode(*newProjectFileIter);
+ }
+ ++newProjectFileIter;
+ } else { // *existingNodeIter->path() == *newProjectFileIter
+ if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
+ Qt4PriFileNode *priFileNode = static_cast<Qt4PriFileNode*>(*existingNodeIter);
+ priFileNode->update(file, reader);
+ }
+
+ ++existingNodeIter;
+ ++newProjectFileIter;
+ }
+ }
+ while (existingNodeIter != existingProjectNodes.constEnd()) {
+ toRemove << *existingNodeIter;
+ ++existingNodeIter;
+ }
+ while (newProjectFileIter != newProjectFiles.constEnd()) {
+ if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
+ Qt4PriFileNode *priFileNode
+ = new Qt4PriFileNode(m_project,
+ *newProjectFileIter);
+ priFileNode->update(file, reader);
+ toAdd << priFileNode;
+ } else {
+ toAdd << createSubProFileNode(*newProjectFileIter);
+ }
+ ++newProjectFileIter;
+ }
+
+ if (!toRemove.isEmpty())
+ removeProjectNodes(toRemove);
+ if (!toAdd.isEmpty())
+ addProjectNodes(toAdd);
+
+ Qt4PriFileNode::update(fileForCurrentProject, reader);
+
+ // update other variables
+ QHash<Qt4Variable, QStringList> newVarValues;
+ newVarValues[CxxCompilerVar] << reader->value(QLatin1String("QMAKE_CXX"));
+ newVarValues[DefinesVar] = reader->values(QLatin1String("DEFINES"));
+ newVarValues[IncludePathVar] = includePaths(reader);
+ newVarValues[UiDirVar] = uiDirPaths(reader);
+ newVarValues[MocDirVar] = mocDirPaths(reader);
+
+ if (m_varValues != newVarValues) {
+ m_varValues = newVarValues;
+ foreach (NodesWatcher *watcher, watchers())
+ if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
+ emit qt4Watcher->variablesChanged(this, m_varValues, newVarValues);
+ }
+
+ updateGeneratedFiles();
+ m_project->qt4ProjectManager()->proFileCache()->updateDependencies(reader->includeFiles().toSet(), this);
+
+ delete reader;
+ foreach (NodesWatcher *watcher, watchers())
+ if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
+ emit qt4Watcher->proFileUpdated(this);
+}
+
+void Qt4ProFileNode::fileChanged(const QString &filePath)
+{
+ CppTools::CppModelManagerInterface *modelManager =
+ m_core->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
+
+ modelManager->updateSourceFiles(QStringList() << filePath);
+}
+
+namespace {
+ // find all ui files in project
+ class FindUiFileNodesVisitor : public ProjectExplorer::NodesVisitor {
+ public:
+ void visitProjectNode(ProjectNode *projectNode)
+ {
+ visitFolderNode(projectNode);
+ }
+ void visitFolderNode(FolderNode *folderNode)
+ {
+ foreach (FileNode *fileNode, folderNode->fileNodes()) {
+ if (fileNode->fileType() == ProjectExplorer::FormType)
+ uiFileNodes << fileNode;
+ }
+ }
+ QList<FileNode*> uiFileNodes;
+ };
+}
+
+/*
+ Adds ui_xxx.h files to tree and monitors them / the UI_DIR directory for changes
+ */
+void Qt4ProFileNode::updateGeneratedFiles()
+{
+ if (m_projectType != ApplicationTemplate
+ && m_projectType != LibraryTemplate)
+ return;
+
+ FindUiFileNodesVisitor uiFilesVisitor;
+ this->accept(&uiFilesVisitor);
+ const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes;
+
+ // monitor uic dir (only if there are .ui files)
+
+ QSet<QString> oldUiDirs = m_dirWatcher->directories().toSet();
+ QSet<QString> newUiDirs =
+ (!uiFiles.isEmpty()) ? m_varValues[UiDirVar].toSet() : QSet<QString>();
+ foreach (const QString &uiDir, oldUiDirs - newUiDirs)
+ m_dirWatcher->removeDirectory(uiDir);
+ foreach (const QString &uiDir, newUiDirs - oldUiDirs)
+ m_dirWatcher->addDirectory(uiDir);
+
+ // update generated files
+
+ QList<FileNode*> existingFileNodes;
+ foreach (FileNode *file, fileNodes()) {
+ if (file->isGenerated())
+ existingFileNodes << file;
+ }
+ QStringList newFilePaths;
+ foreach (const QString &uicDir, m_varValues[UiDirVar]) {
+ foreach (FileNode *uiFile, uiFiles) {
+ const QString uiHeaderFilePath
+ = QString("%1/ui_%2.h").arg(uicDir, QFileInfo(uiFile->path()).baseName());
+ if (QFileInfo(uiHeaderFilePath).exists())
+ newFilePaths << uiHeaderFilePath;
+ }
+ }
+
+ QList<FileNode*> toRemove;
+ QList<FileNode*> toAdd;
+
+ qSort(newFilePaths);
+ qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
+
+ QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
+ QList<QString>::const_iterator newPathIter = newFilePaths.constBegin();
+ while (existingNodeIter != existingFileNodes.constEnd()
+ && newPathIter != newFilePaths.constEnd()) {
+ if ((*existingNodeIter)->path() < *newPathIter) {
+ toRemove << *existingNodeIter;
+ ++existingNodeIter;
+ } else if ((*existingNodeIter)->path() > *newPathIter) {
+ toAdd << new FileNode(*newPathIter, ProjectExplorer::HeaderType, true);
+ ++newPathIter;
+ } else { // *existingNodeIter->path() == *newPathIter
+ ++existingNodeIter;
+ ++newPathIter;
+ }
+ }
+ while (existingNodeIter != existingFileNodes.constEnd()) {
+ toRemove << *existingNodeIter;
+ ++existingNodeIter;
+ }
+ while (newPathIter != newFilePaths.constEnd()) {
+ toAdd << new FileNode(*newPathIter, ProjectExplorer::HeaderType, true);
+ ++newPathIter;
+ }
+
+ if (!toRemove.isEmpty()) {
+ foreach (FileNode *file, toRemove)
+ m_dirWatcher->removeFile(file->path());
+ removeFileNodes(toRemove, this);
+ }
+ if (!toAdd.isEmpty()) {
+ foreach (FileNode *file, toAdd)
+ m_dirWatcher->addFile(file->path());
+ addFileNodes(toAdd, this);
+ }
+}
+
+ProFileReader *Qt4ProFileNode::createProFileReader() const
+{
+ ProFileReader *reader = new ProFileReader(m_cache);
+ connect(reader, SIGNAL(errorFound(const QString &)),
+ m_project, SLOT(proFileParseError(const QString &)));
+
+ QtVersion *version = m_project->qtVersion(m_project->activeBuildConfiguration());
+ if (version->isValid()) {
+ reader->setQtVersion(version);
+ }
+
+ QHash<QString,QStringList> variables;
+ variables.insert(QLatin1String("OUT_PWD"), QStringList(buildDir()));
+ reader->addVariables(variables);
+
+ return reader;
+}
+
+Qt4ProFileNode *Qt4ProFileNode::createSubProFileNode(const QString &path)
+{
+ Qt4ProFileNode *subProFileNode = new Qt4ProFileNode(m_project, path);
+ subProFileNode->update();
+ return subProFileNode;
+}
+
+QStringList Qt4ProFileNode::uiDirPaths(ProFileReader *reader) const
+{
+ QStringList candidates = reader->absolutePathValues(QLatin1String("UI_DIR"),
+ buildDir(),
+ ProFileReader::ExistingPaths);
+ return candidates;
+}
+
+QStringList Qt4ProFileNode::mocDirPaths(ProFileReader *reader) const
+{
+ QStringList candidates = reader->absolutePathValues(QLatin1String("MOC_DIR"),
+ buildDir(),
+ ProFileReader::ExistingPaths);
+ return candidates;
+}
+
+QStringList Qt4ProFileNode::includePaths(ProFileReader *reader) const
+{
+ QStringList paths;
+ paths = reader->absolutePathValues(QLatin1String("INCLUDEPATH"),
+ m_projectDir,
+ ProFileReader::ExistingPaths);
+ paths << uiDirPaths(reader) << mocDirPaths(reader);
+ paths.removeDuplicates();
+ return paths;
+}
+
+QStringList Qt4ProFileNode::subDirsPaths(ProFileReader *reader) const
+{
+ QStringList subProjectPaths;
+
+ const QStringList subDirVars = reader->values(QLatin1String("SUBDIRS"));
+
+ foreach (const QString &subDirVar, subDirVars) {
+ // Special case were subdir is just an identifier:
+ // "SUBDIR = subid
+ // subid.subdir = realdir"
+
+ QString realDir;
+ QString realFile;
+ const QString subDirKey = subDirVar + QLatin1String(".subdir");
+ if (reader->contains(subDirKey))
+ realDir = reader->value(subDirKey);
+ else
+ realDir = subDirVar;
+ QFileInfo info(realDir);
+ if (!info.isAbsolute())
+ realDir = QString("%1/%2").arg(m_projectDir, realDir);
+
+#ifdef QTEXTENDED_QBUILD_SUPPORT
+ // QBuild only uses project files named qbuild.pro, and subdirs are implied
+ if (m_isQBuildProject)
+ return qBuildSubDirsPaths(realDir);
+#endif
+ if (info.suffix().isEmpty() || info.isDir()) {
+ realFile = QString("%1/%2.pro").arg(realDir, info.fileName());
+ if (!QFile::exists(realFile)) {
+ // parse directory for pro files - if there is only one, use that
+ QDir dir(realDir);
+ QStringList files = dir.entryList(QStringList() << "*.pro", QDir::Files);
+ if (files.size() == 1) {
+ realFile = QString("%1/%2").arg(realDir, files.first());
+ } else {
+ m_project->proFileParseError(tr("Could not find .pro file for sub dir '%1' in '%2'")
+ .arg(subDirVar).arg(realDir));
+ realFile = QString::null;
+ }
+ }
+ } else {
+ realFile = realDir;
+ }
+
+ if (!realFile.isEmpty() && !subProjectPaths.contains(realFile))
+ subProjectPaths << realFile;
+ }
+
+ return subProjectPaths;
+}
+
+QStringList Qt4ProFileNode::qBuildSubDirsPaths(const QString &scanDir) const
+{
+ QStringList subProjectPaths;
+
+ // With QBuild we only look for project files named qbuild.pro
+ QString realFile = scanDir + "/qbuild.pro";
+ if (QFile::exists(realFile))
+ subProjectPaths << realFile;
+
+ // With QBuild 'subdirs' are implied
+ QDir dir(scanDir);
+ QStringList subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ foreach (QString subDir, subDirs) {
+ // 'tests' sub directories are an exception to the 'QBuild scans everything' rule.
+ // Tests are only build with the 'make test' command, in which case QBuild WILL look
+ // for a tests subdir and run everything in there.
+ if (subDir != "tests")
+ subProjectPaths += qBuildSubDirsPaths(scanDir + "/" + subDir);
+ }
+
+ return subProjectPaths;
+}
+
+QString Qt4ProFileNode::buildDir() const
+{
+ const QDir srcDirRoot = QFileInfo(m_project->rootProjectNode()->path()).absoluteDir();
+ const QString relativeDir = srcDirRoot.relativeFilePath(m_projectDir);
+ return QDir(m_project->buildDirectory(m_project->activeBuildConfiguration())).absoluteFilePath(relativeDir);
+}
+
+/*
+ Sets project type to InvalidProject & deletes all subprojects/files/virtual folders
+ */
+void Qt4ProFileNode::invalidate()
+{
+ if (m_projectType == InvalidProject)
+ return;
+
+ clear();
+
+ // remove monitored files/directories
+ foreach (const QString &file, m_dirWatcher->files())
+ m_dirWatcher->removeFile(file);
+ foreach (const QString &dir, m_dirWatcher->directories())
+ m_dirWatcher->removeDirectory(dir);
+
+
+ // change project type
+ Qt4ProjectType oldType = m_projectType;
+ m_projectType = InvalidProject;
+
+
+ foreach (NodesWatcher *watcher, watchers())
+ if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
+ emit qt4Watcher->projectTypeChanged(this, oldType, InvalidProject);
+}
+
+Qt4NodesWatcher::Qt4NodesWatcher(QObject *parent)
+ : NodesWatcher(parent)
+{
+}
diff --git a/src/plugins/qt4projectmanager/qt4nodes.h b/src/plugins/qt4projectmanager/qt4nodes.h
new file mode 100644
index 0000000000..7f311e813c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4nodes.h
@@ -0,0 +1,234 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4NODES_H
+#define QT4NODES_H
+
+#include <projectexplorer/projectnodes.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QTimer>
+
+// defined in proitems.h
+QT_BEGIN_NAMESPACE
+class ProFile;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace Qt4ProjectManager {
+
+// Import base classes into namespace
+using ProjectExplorer::Node;
+using ProjectExplorer::FileNode;
+using ProjectExplorer::FolderNode;
+using ProjectExplorer::ProjectNode;
+using ProjectExplorer::NodesWatcher;
+
+// Import enums into namespace
+using ProjectExplorer::NodeType;
+using ProjectExplorer::FileNodeType;
+using ProjectExplorer::FolderNodeType;
+using ProjectExplorer::ProjectNodeType;
+
+using ProjectExplorer::UnknownFileType;
+using ProjectExplorer::ProjectFileType;
+
+class Qt4Project;
+
+namespace Internal {
+
+using ProjectExplorer::FileType;
+
+class ProFileCache;
+class ProFileReader;
+class DirectoryWatcher;
+
+// Type of projects
+enum Qt4ProjectType {
+ InvalidProject = 0,
+ ApplicationTemplate,
+ LibraryTemplate,
+ ScriptTemplate,
+ SubDirsTemplate
+};
+
+// Other variables of interest
+enum Qt4Variable {
+ DefinesVar = 1,
+ IncludePathVar,
+ CxxCompilerVar,
+ UiDirVar,
+ MocDirVar
+};
+
+class Qt4PriFileNode;
+class Qt4ProFileNode;
+
+// Implements ProjectNode for qt4 pro files
+class Qt4PriFileNode : public ProjectExplorer::ProjectNode {
+ Q_OBJECT
+ Q_DISABLE_COPY(Qt4PriFileNode)
+public:
+ Qt4PriFileNode(Qt4Project *project,
+ const QString &filePath);
+
+ void update(ProFile *includeFile, ProFileReader *reader);
+
+// ProjectNode interface
+ QList<ProjectAction> supportedActions() const;
+
+ bool hasTargets() const { return false; }
+
+ bool addSubProjects(const QStringList &proFilePaths);
+ bool removeSubProjects(const QStringList &proFilePaths);
+
+ bool addFiles(const FileType fileType, const QStringList &filePaths,
+ QStringList *notAdded = 0);
+ bool removeFiles(const FileType fileType, const QStringList &filePaths,
+ QStringList *notRemoved = 0);
+ bool renameFile(const FileType fileType,
+ const QString &filePath, const QString &newFilePath);
+
+private slots:
+ void save();
+
+protected:
+ void clear();
+ static QStringList varNames(FileType type);
+
+ enum ChangeType {
+ AddToProFile,
+ RemoveFromProFile
+ };
+
+ bool changeIncludes(ProFile *includeFile,
+ const QStringList &proFilePaths,
+ ChangeType change);
+
+ void changeFiles(const FileType fileType,
+ const QStringList &filePaths,
+ QStringList *notChanged,
+ ChangeType change);
+
+private:
+ bool priFileWritable(const QString &path);
+ bool saveModifiedEditors(const QString &path);
+
+ Core::ICore *m_core;
+ Qt4Project *m_project;
+ QString m_projectFilePath;
+ QString m_projectDir;
+ ProFile *m_includeFile;
+ QTimer *m_saveTimer;
+
+ // managed by Qt4ProFileNode
+ friend class Qt4ProFileNode;
+};
+
+// Implements ProjectNode for qt4 pro files
+class Qt4ProFileNode : public Qt4PriFileNode {
+ Q_OBJECT
+ Q_DISABLE_COPY(Qt4ProFileNode)
+public:
+ Qt4ProFileNode(Qt4Project *project,
+ const QString &filePath,
+ QObject *parent = 0);
+
+ bool hasTargets() const;
+
+ Qt4ProjectType projectType() const;
+
+ QStringList variableValue(const Qt4Variable var) const;
+
+public slots:
+ void update();
+
+private slots:
+ void fileChanged(const QString &filePath);
+
+private:
+ void updateGeneratedFiles();
+
+ ProFileReader *createProFileReader() const;
+ Qt4ProFileNode *createSubProFileNode(const QString &path);
+
+ QStringList uiDirPaths(ProFileReader *reader) const;
+ QStringList mocDirPaths(ProFileReader *reader) const;
+ QStringList includePaths(ProFileReader *reader) const;
+ QStringList subDirsPaths(ProFileReader *reader) const;
+ QStringList qBuildSubDirsPaths(const QString &scanDir) const;
+
+ QString buildDir() const;
+
+ void invalidate();
+
+ Qt4ProjectType m_projectType;
+ QHash<Qt4Variable, QStringList> m_varValues;
+ bool m_isQBuildProject;
+
+ ProFileCache *m_cache;
+ DirectoryWatcher *m_dirWatcher;
+
+ friend class Qt4NodeHierarchy;
+};
+
+class Qt4NodesWatcher : public ProjectExplorer::NodesWatcher {
+ Q_OBJECT
+ Q_DISABLE_COPY(Qt4NodesWatcher)
+public:
+ Qt4NodesWatcher(QObject *parent = 0);
+
+signals:
+ void projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *projectNode,
+ const Qt4ProjectManager::Internal::Qt4ProjectType oldType,
+ const Qt4ProjectManager::Internal::Qt4ProjectType newType);
+
+ void variablesChanged(Qt4ProFileNode *projectNode,
+ const QHash<Qt4Variable, QStringList> &oldValues,
+ const QHash<Qt4Variable, QStringList> &newValues);
+
+ void proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *projectNode);
+
+private:
+ // let them emit signals
+ friend class Qt4ProFileNode;
+ friend class Qt4PriFileNode;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // QT4NODES_H
diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp
new file mode 100644
index 0000000000..e642c309f7
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4project.cpp
@@ -0,0 +1,897 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4project.h"
+#include "qt4projectmanager.h"
+#include "profilecache.h"
+#include "profilereader.h"
+#include "makestep.h"
+#include "qmakestep.h"
+#include "deployhelper.h"
+#include "qt4runconfiguration.h"
+#include "qtversionmanager.h"
+#include "qt4nodes.h"
+#include "qt4buildconfigwidget.h"
+#include "qt4buildenvironmentwidget.h"
+#include "qt4projectmanagerconstants.h"
+#include "projectloadwizard.h"
+#include "gdbmacrosbuildstep.h"
+
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/coreconstants.h>
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <projectexplorer/nodesvisitor.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/customexecutablerunconfiguration.h>
+
+#include <QtGui/QFileDialog>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+using namespace ProjectExplorer;
+using Core::VariableManager;
+
+enum { debug = 0 };
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+// Qt4ProjectFiles: Struct for (Cached) lists of files in a project
+struct Qt4ProjectFiles {
+ void clear();
+ bool equals(const Qt4ProjectFiles &f) const;
+
+ QStringList files[ProjectExplorer::FileTypeSize];
+ QStringList generatedFiles[ProjectExplorer::FileTypeSize];
+ QStringList proFiles;
+};
+
+void Qt4ProjectFiles::clear()
+{
+ for (int i = 0; i < FileTypeSize; ++i) {
+ files[i].clear();
+ generatedFiles[i].clear();
+ }
+ proFiles.clear();
+}
+
+bool Qt4ProjectFiles::equals(const Qt4ProjectFiles &f) const
+{
+ for (int i = 0; i < FileTypeSize; ++i)
+ if (files[i] != f.files[i] || generatedFiles[i] != f.generatedFiles[i])
+ return false;
+ if (proFiles != f.proFiles)
+ return false;
+ return true;
+}
+
+inline bool operator==(const Qt4ProjectFiles &f1, const Qt4ProjectFiles &f2)
+{ return f1.equals(f2); }
+
+inline bool operator!=(const Qt4ProjectFiles &f1, const Qt4ProjectFiles &f2)
+{ return !f1.equals(f2); }
+
+QDebug operator<<(QDebug d, const Qt4ProjectFiles &f)
+{
+ QDebug nsp = d.nospace();
+ nsp << "Qt4ProjectFiles: proFiles=" << f.proFiles << '\n';
+ for (int i = 0; i < FileTypeSize; ++i)
+ nsp << "Type " << i << " files=" << f.files[i] << " generated=" << f.generatedFiles[i] << '\n';
+ return d;
+}
+
+// A visitor to collect all files of a project in a Qt4ProjectFiles struct
+class ProjectFilesVisitor : public ProjectExplorer::NodesVisitor
+{
+ Q_DISABLE_COPY(ProjectFilesVisitor)
+ ProjectFilesVisitor(Qt4ProjectFiles *files);
+public:
+
+ static void findProjectFiles(Qt4ProFileNode *rootNode, Qt4ProjectFiles *files);
+
+ void visitProjectNode(ProjectNode *projectNode);
+ void visitFolderNode(FolderNode *folderNode);
+
+private:
+ Qt4ProjectFiles *m_files;
+};
+
+ProjectFilesVisitor::ProjectFilesVisitor(Qt4ProjectFiles *files) :
+ m_files(files)
+{
+}
+
+void ProjectFilesVisitor::findProjectFiles(Qt4ProFileNode *rootNode, Qt4ProjectFiles *files)
+{
+ files->clear();
+ ProjectFilesVisitor visitor(files);
+ rootNode->accept(&visitor);
+ for (int i = 0; i < FileTypeSize; ++i) {
+ qSort(files->files[i]);
+ qSort(files->generatedFiles[i]);
+ }
+ qSort(files->proFiles);
+}
+
+void ProjectFilesVisitor::visitProjectNode(ProjectNode *projectNode)
+{
+ const QString path = projectNode->path();
+ if (!m_files->proFiles.contains(path))
+ m_files->proFiles.append(path);
+ visitFolderNode(projectNode);
+}
+
+void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
+{
+ foreach (FileNode *fileNode, folderNode->fileNodes()) {
+ const QString path = fileNode->path();
+ const int type = fileNode->fileType();
+ QStringList &targetList = fileNode->isGenerated() ? m_files->generatedFiles[type] : m_files->files[type];
+ if (!targetList.contains(path))
+ targetList.push_back(path);
+ }
+}
+
+}
+}
+
+// ----------- Qt4ProjectFile
+Qt4ProjectFile::Qt4ProjectFile(Qt4Project *project, const QString &filePath, QObject *parent)
+ : Core::IFile(parent),
+ m_mimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)),
+ m_project(project),
+ m_filePath(filePath)
+{
+}
+
+bool Qt4ProjectFile::save(const QString &)
+{
+ Core::IFile *file = fileFromCache();
+ return file && file->save();
+}
+
+QString Qt4ProjectFile::fileName() const
+{
+ return m_filePath;
+}
+
+QString Qt4ProjectFile::defaultPath() const
+{
+ return QString();
+}
+
+QString Qt4ProjectFile::suggestedFileName() const
+{
+ return QString();
+}
+
+QString Qt4ProjectFile::mimeType() const
+{
+ return m_mimeType;
+}
+
+bool Qt4ProjectFile::isModified() const
+{
+ Core::IFile *file = fileFromCache();
+ return file && fileFromCache()->isModified();
+}
+
+bool Qt4ProjectFile::isReadOnly() const
+{
+ Core::IFile *file = fileFromCache();
+ return file && fileFromCache()->isReadOnly();
+}
+
+bool Qt4ProjectFile::isSaveAsAllowed() const
+{
+ return false;
+}
+
+void Qt4ProjectFile::modified(Core::IFile::ReloadBehavior *)
+{
+}
+
+Core::IFile *Qt4ProjectFile::fileFromCache() const
+{
+ ProFileCache *cache = m_project->qt4ProjectManager()->proFileCache();
+ Core::IFile *fi = cache->fileInterface(fileName());
+ if (!fi && debug)
+ qWarning() << "Could not retrieve IFile interface from ProFileCache";
+ return fi;
+}
+
+/*!
+ /class Qt4Project
+
+ Qt4Project manages information about an individual Qt 4 (.pro) project file.
+ */
+
+Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
+ m_manager(manager),
+ m_rootProjectNode(new Qt4ProFileNode(this, fileName, this)),
+ m_nodesWatcher(new Internal::Qt4NodesWatcher(this)),
+ m_fileInfo(new Qt4ProjectFile(this, fileName, this)),
+ m_isApplication(true),
+ m_projectFiles(new Qt4ProjectFiles)
+{
+ m_rootProjectNode->registerWatcher(m_nodesWatcher);
+ connect(m_nodesWatcher, SIGNAL(foldersAdded()), this, SLOT(updateFileList()));
+ connect(m_nodesWatcher, SIGNAL(foldersRemoved()), this, SLOT(updateFileList()));
+ connect(m_nodesWatcher, SIGNAL(filesAdded()), this, SLOT(updateFileList()));
+ connect(m_nodesWatcher, SIGNAL(filesRemoved()), this, SLOT(updateFileList()));
+ connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)),
+ this, SLOT(scheduleUpdateCodeModel()));
+
+ connect(qt4ProjectManager()->versionManager(), SIGNAL(defaultQtVersionChanged()),
+ this, SLOT(defaultQtVersionChanged()));
+ connect(qt4ProjectManager()->versionManager(), SIGNAL(qtVersionsChanged()),
+ this, SLOT(qtVersionsChanged()));
+
+ m_updateCodeModelTimer.setSingleShot(true);
+ m_updateCodeModelTimer.setInterval(20);
+ connect(&m_updateCodeModelTimer, SIGNAL(timeout()), this, SLOT(updateCodeModel()));
+}
+
+Qt4Project::~Qt4Project()
+{
+ delete m_projectFiles;
+}
+
+void Qt4Project::defaultQtVersionChanged()
+{
+ if (qtVersionId(activeBuildConfiguration()) == 0)
+ update();
+}
+
+void Qt4Project::qtVersionsChanged()
+{
+ foreach (QString bc, buildConfigurations()) {
+ if (!qt4ProjectManager()->versionManager()->version(qtVersionId(bc))->isValid()) {
+ setQtVersion(bc, 0);
+ if(bc == activeBuildConfiguration())
+ update();
+ }
+ }
+}
+
+void Qt4Project::updateFileList()
+{
+ Qt4ProjectFiles newFiles;
+ ProjectFilesVisitor::findProjectFiles(m_rootProjectNode, &newFiles);
+ if (newFiles != *m_projectFiles) {
+ *m_projectFiles = newFiles;
+ emit fileListChanged();
+ if (debug)
+ qDebug() << Q_FUNC_INFO << *m_projectFiles;
+ }
+}
+
+void Qt4Project::restoreSettingsImpl(PersistentSettingsReader &settingsReader)
+{
+ Project::restoreSettingsImpl(settingsReader);
+
+ addDefaultBuild();
+
+ // Ensure that the qt version in each build configuration is valid
+ // or if not, is reset to the default
+ foreach (const QString &bc, buildConfigurations())
+ qtVersionId(bc);
+
+ update();
+
+ // restored old runconfigurations
+ if (runConfigurations().isEmpty()) {
+ // Oha no runConfigurations, add some
+ QList<Qt4ProFileNode *> list;
+ collectApplicationProFiles(list, m_rootProjectNode);
+
+ if (!list.isEmpty()) {
+ foreach (Qt4ProFileNode *node, list) {
+ QSharedPointer<RunConfiguration> rc(new Qt4RunConfiguration(this, node->path()));
+ addRunConfiguration(rc);
+ }
+ setActiveRunConfiguration(runConfigurations().first());
+ } else {
+ QSharedPointer<RunConfiguration> rc(new ProjectExplorer::CustomExecutableRunConfiguration(this));
+ addRunConfiguration(rc);
+ setActiveRunConfiguration(rc);
+ m_isApplication = false;
+ }
+ }
+
+ // Now connect
+ connect(m_nodesWatcher, SIGNAL(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)),
+ this, SLOT(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)));
+ connect(m_nodesWatcher, SIGNAL(foldersAdded()), this, SLOT(checkForNewApplicationProjects()));
+
+ connect(m_nodesWatcher, SIGNAL(foldersRemoved()), this, SLOT(checkForDeletedApplicationProjects()));
+
+ connect(m_nodesWatcher, SIGNAL(projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *,
+ const Qt4ProjectManager::Internal::Qt4ProjectType,
+ const Qt4ProjectManager::Internal::Qt4ProjectType)),
+ this, SLOT(projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *,
+ const Qt4ProjectManager::Internal::Qt4ProjectType,
+ const Qt4ProjectManager::Internal::Qt4ProjectType)));
+
+ connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)),
+ this, SLOT(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)));
+
+}
+
+void Qt4Project::saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer)
+{
+ Project::saveSettingsImpl(writer);
+}
+
+namespace {
+ class FindQt4ProFiles: protected ProjectExplorer::NodesVisitor {
+ QList<Qt4ProFileNode *> m_proFiles;
+
+ public:
+ QList<Qt4ProFileNode *> operator()(ProjectNode *root)
+ {
+ m_proFiles.clear();
+ root->accept(this);
+ return m_proFiles;
+ }
+
+ protected:
+ virtual void visitProjectNode(ProjectNode *projectNode)
+ {
+ if (Qt4ProFileNode *pro = qobject_cast<Qt4ProFileNode *>(projectNode))
+ m_proFiles.append(pro);
+ }
+ };
+}
+
+void Qt4Project::scheduleUpdateCodeModel()
+{
+ m_updateCodeModelTimer.start();
+}
+
+void Qt4Project::updateCodeModel()
+{
+ if (debug)
+ qDebug()<<"Qt4Project::updateCodeModel()";
+
+ CppTools::CppModelManagerInterface *modelmanager =
+ m_manager->pluginManager()->getObject<CppTools::CppModelManagerInterface>();
+
+ if (! modelmanager)
+ return;
+
+ QStringList allIncludePaths;
+ QStringList allFrameworkPaths;
+
+ const QHash<QString, QString> versionInfo = qtVersion(activeBuildConfiguration())->versionInfo();
+ const QString newQtIncludePath = versionInfo.value(QLatin1String("QT_INSTALL_HEADERS"));
+ const QString newQtLibsPath = versionInfo.value(QLatin1String("QT_INSTALL_LIBS"));
+
+ QByteArray predefinedMacros;
+ QtVersion::ToolchainType t = qtVersion(activeBuildConfiguration())->toolchainType();
+ if (t == QtVersion::MinGW || t == QtVersion::OTHER) {
+ QStringList list = rootProjectNode()->variableValue(Internal::CxxCompilerVar);
+ QString qmake_cxx = list.isEmpty() ? QString::null : list.first();
+ qmake_cxx = environment(activeBuildConfiguration()).searchInPath(qmake_cxx);
+ m_preproc.setGcc(qmake_cxx);
+ predefinedMacros = m_preproc.predefinedMacros();
+ foreach (HeaderPath headerPath, m_preproc.systemHeaderPaths()) {
+ if (headerPath.kind() == HeaderPath::FrameworkHeaderPath)
+ allFrameworkPaths.append(headerPath.path());
+ else
+ allIncludePaths.append(headerPath.path());
+ }
+
+ } else if (t == QtVersion::MSVC || t == QtVersion::WINCE) {
+#ifdef QTCREATOR_WITH_MSVC_INCLUDES
+ Environment env = environment(activeBuildConfiguration());
+ allIncludePaths.append(env.value("INCLUDE").split(QLatin1Char(';')));
+#endif
+ predefinedMacros +=
+ "#define __WIN32__\n"
+ "#define __WIN32\n"
+ "#define _WIN32\n"
+ "#define WIN32\n"
+ "#define __WINNT__\n"
+ "#define __WINNT\n"
+ "#define WINNT\n"
+ "#define _X86_\n"
+ "#define __MSVCRT__\n";
+ }
+
+ allIncludePaths.append(newQtIncludePath);
+
+ QDir dir(newQtIncludePath);
+ foreach (QFileInfo info, dir.entryInfoList(QDir::Dirs)) {
+ if (! info.fileName().startsWith(QLatin1String("Qt")))
+ continue;
+ allIncludePaths.append(info.absoluteFilePath());
+ }
+
+#ifdef Q_OS_MAC
+ allFrameworkPaths.append(newQtLibsPath);
+ // put QtXXX.framework/Headers directories in include path since that qmake's behavior
+ QDir frameworkDir(newQtLibsPath);
+ foreach (QFileInfo info, frameworkDir.entryInfoList(QDir::Dirs)) {
+ if (! info.fileName().startsWith(QLatin1String("Qt")))
+ continue;
+ allIncludePaths.append(info.absoluteFilePath()+"/Headers");
+ }
+#endif
+
+ FindQt4ProFiles findQt4ProFiles;
+ QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
+ QByteArray definedMacros;
+
+ foreach (Qt4ProFileNode *pro, proFiles) {
+ foreach (const QString def, pro->variableValue(DefinesVar)) {
+ definedMacros += "#define ";
+ const int index = def.indexOf(QLatin1Char('='));
+ if (index == -1) {
+ definedMacros += def.toLatin1();
+ definedMacros += " 1\n";
+ } else {
+ const QString name = def.left(index);
+ const QString value = def.mid(index + 1);
+ definedMacros += name.toLatin1();
+ definedMacros += ' ';
+ definedMacros += value.toLocal8Bit();
+ definedMacros += '\n';
+ }
+ }
+
+ const QStringList proIncludePaths = pro->variableValue(IncludePathVar);
+ foreach (QString includePath, proIncludePaths) {
+ if (allIncludePaths.contains(includePath))
+ continue;
+
+ allIncludePaths.append(includePath);
+ }
+ }
+
+ QStringList files;
+ files += m_projectFiles->files[HeaderType];
+ files += m_projectFiles->generatedFiles[HeaderType];
+ files += m_projectFiles->files[SourceType];
+ files += m_projectFiles->generatedFiles[SourceType];
+
+ CppTools::CppModelManagerInterface::ProjectInfo *pinfo = modelmanager->projectInfo(this);
+
+ if (pinfo->defines == predefinedMacros &&
+ pinfo->includePaths == allIncludePaths &&
+ pinfo->frameworkPaths == allFrameworkPaths &&
+ pinfo->sourceFiles == files) {
+ // Nothing to update...
+ } else {
+ pinfo->defines = predefinedMacros;
+ // pinfo->defines += definedMacros; // ### FIXME: me
+ pinfo->includePaths = allIncludePaths;
+ pinfo->frameworkPaths = allFrameworkPaths;
+ pinfo->sourceFiles = files;
+
+ modelmanager->GC();
+ modelmanager->updateSourceFiles(pinfo->sourceFiles);
+ }
+}
+
+
+/*!
+ Updates complete project
+ */
+void Qt4Project::update()
+{
+ // TODO Maybe remove this method completely?
+ m_rootProjectNode->update();
+ //updateCodeModel();
+}
+
+ProFileReader *Qt4Project::createProFileReader() const
+{
+ ProFileReader *reader = new ProFileReader(m_manager->proFileCache());
+ connect(reader, SIGNAL(errorFound(const QString&)),
+ this, SLOT(proFileParseError(const QString&)));
+ QtVersion *version = qtVersion(activeBuildConfiguration());
+ if (version->isValid()) {
+ reader->setQtVersion(version);
+ }
+ return reader;
+}
+
+/*!
+ Returns whether the project is an application, or has an application as a subproject.
+ */
+bool Qt4Project::isApplication() const
+{
+ return m_isApplication;
+}
+
+ProjectExplorer::ProjectExplorerPlugin *Qt4Project::projectExplorer() const
+{
+ return m_manager->projectExplorer();
+}
+
+ProjectExplorer::IProjectManager *Qt4Project::projectManager() const
+{
+ return m_manager;
+}
+
+Qt4Manager *Qt4Project::qt4ProjectManager() const
+{
+ return m_manager;
+}
+
+QString Qt4Project::name() const
+{
+ return QFileInfo(file()->fileName()).completeBaseName();
+}
+
+Core::IFile *Qt4Project::file() const
+{
+ return m_fileInfo;
+}
+
+QStringList Qt4Project::files(FilesMode fileMode) const
+{
+ QStringList files;
+ for (int i = 0; i < FileTypeSize; ++i) {
+ files += m_projectFiles->files[i];
+ if (fileMode == AllFiles)
+ files += m_projectFiles->generatedFiles[i];
+ }
+ files += m_projectFiles->proFiles;
+ return files;
+}
+
+QList<Core::IFile *> Qt4Project::dependencies()
+{
+ QList<Core::IFile *> result;
+ ProFileCache *cache = m_manager->proFileCache();
+ foreach (const QString &file, cache->dependencies(m_rootProjectNode)) {
+ result << cache->fileInterface(file);
+ }
+ return result;
+}
+
+QList<ProjectExplorer::Project*> Qt4Project::dependsOn()
+{
+ // NBS implement dependsOn
+ return QList<Project *>();
+}
+
+void Qt4Project::addDefaultBuild()
+{
+ if (buildConfigurations().isEmpty()) {
+ // We don't have any buildconfigurations, so this is a new project
+ // The Project Load Wizard is a work of art
+ // It will ask the user what kind of build setup he want
+ // It will add missing Qt Versions
+ // And get the project into a buildable state
+
+ //TODO have a better check wheter there is already a configuration?
+ QMakeStep *qmakeStep = 0;
+ MakeStep *makeStep = 0;
+ GdbMacrosBuildStep *gdbmacrostep;
+
+ gdbmacrostep = new GdbMacrosBuildStep(this);
+ insertBuildStep(0, gdbmacrostep);
+
+ qmakeStep = new QMakeStep(this);
+ qmakeStep->setValue("mkspec", "");
+ insertBuildStep(1, qmakeStep);
+
+ makeStep = new MakeStep(this);
+ insertBuildStep(2, makeStep);
+
+ MakeStep* cleanStep = new MakeStep(this);
+ cleanStep->setValue("clean", true);
+ insertCleanStep(0, cleanStep);
+
+ ProjectLoadWizard wizard(this);
+ wizard.execDialog();
+ } else {
+ // Restoring configuration
+ // Do we already have a gdbmacrobuildstep?
+ // If not add it and disable linking of debugging helper
+ // TODO
+ }
+}
+
+void Qt4Project::newBuildConfiguration(const QString &buildConfiguration)
+{
+ Q_UNUSED(buildConfiguration);
+}
+
+void Qt4Project::proFileParseError(const QString &errorMessage)
+{
+ m_manager->core()->messageManager()->printToOutputPane(errorMessage);
+}
+
+Qt4ProFileNode *Qt4Project::rootProjectNode() const
+{
+ return m_rootProjectNode;
+}
+
+ProjectExplorer::Environment Qt4Project::baseEnvironment(const QString &buildConfiguration) const
+{
+ Environment env = useSystemEnvironment(buildConfiguration) ? Environment(QProcess::systemEnvironment()) : Environment();
+ env = qtVersion(buildConfiguration)->addToEnvironment(env);
+ return env;
+}
+
+ProjectExplorer::Environment Qt4Project::environment(const QString &buildConfiguration) const
+{
+ Environment env = baseEnvironment(buildConfiguration);
+ env.modify(userEnvironmentChanges(buildConfiguration));
+ return env;
+}
+
+QString Qt4Project::buildDirectory(const QString &buildConfiguration) const
+{
+ QString workingDirectory;
+ if (value(buildConfiguration, "useShadowBuild").toBool())
+ workingDirectory = value(buildConfiguration, "buildDirectory").toString();
+ if(workingDirectory.isEmpty())
+ workingDirectory = QFileInfo(file()->fileName()).absolutePath();
+ return workingDirectory;
+}
+
+void Qt4Project::setUseSystemEnvironment(const QString &buildConfiguration, bool b)
+{
+ setValue(buildConfiguration, "clearSystemEnvironment", !b);
+}
+
+bool Qt4Project::useSystemEnvironment(const QString &buildConfiguration) const
+{
+ bool b = !(value(buildConfiguration, "clearSystemEnvironment").isValid() && value(buildConfiguration, "clearSystemEnvironment").toBool());
+ return b;
+}
+
+QString Qt4Project::qtDir(const QString &buildConfiguration) const
+{
+ QtVersion *version = qtVersion(buildConfiguration);
+ if (version)
+ return version->path();
+ return QString::null;
+}
+
+QtVersion *Qt4Project::qtVersion(const QString &buildConfiguration) const
+{
+ return m_manager->versionManager()->version(qtVersionId(buildConfiguration));
+}
+
+int Qt4Project::qtVersionId(const QString &buildConfiguration) const
+{
+ if (debug)
+ qDebug()<<"Looking for qtVersion ID of "<<buildConfiguration;
+ int id = 0;
+ QVariant vid = value(buildConfiguration, "QtVersionId");
+ if(vid.isValid()) {
+ id = vid.toInt();
+ if (m_manager->versionManager()->version(id)->isValid()) {
+ return id;
+ } else {
+ const_cast<Qt4Project *>(this)->setValue(buildConfiguration, "QtVersionId", 0);
+ return 0;
+ }
+ } else {
+ // Backward compatibilty, we might have just the name:
+ QString vname = value(buildConfiguration, "QtVersion").toString();
+ if (debug)
+ qDebug()<<" Backward compatibility reading QtVersion"<<vname;
+ if(!vname.isEmpty()) {
+ const QList<QtVersion *> &versions = m_manager->versionManager()->versions();
+ foreach (const QtVersion * const version, versions) {
+ if(version->name() == vname) {
+ if (debug)
+ qDebug()<<"found name in versions";
+ const_cast<Qt4Project *>(this)->setValue(buildConfiguration, "QtVersionId", version->uniqueId());
+ return version->uniqueId();
+ }
+ }
+ }
+ }
+ if (debug)
+ qDebug()<<" using qtversion with id ="<<id;
+ // Nothing found, reset to default
+ const_cast<Qt4Project *>(this)->setValue(buildConfiguration, "QtVersionId", id);
+ return id;
+}
+
+void Qt4Project::setQtVersion(const QString &buildConfiguration, int id)
+{
+ setValue(buildConfiguration, "QtVersionId", id);
+}
+
+BuildStepConfigWidget *Qt4Project::createConfigWidget()
+{
+ return new Qt4BuildConfigWidget(this);
+}
+
+QList<BuildStepConfigWidget*> Qt4Project::subConfigWidgets()
+{
+ QList<BuildStepConfigWidget*> subWidgets;
+ subWidgets << new Qt4BuildEnvironmentWidget(this);
+ return subWidgets;
+}
+
+QList<ProjectExplorer::EnvironmentItem> Qt4Project::userEnvironmentChanges(const QString &buildConfig) const
+{
+ return EnvironmentItem::fromStringList(value(buildConfig, "userEnvironmentChanges").toStringList());
+}
+
+void Qt4Project::setUserEnvironmentChanges(const QString &buildConfig, const QList<ProjectExplorer::EnvironmentItem> &diff)
+{
+ setValue(buildConfig, "userEnvironmentChanges", EnvironmentItem::toStringList(diff));
+}
+
+/// **************************
+/// Qt4ProjectBuildConfigWidget
+/// **************************
+
+
+void Qt4Project::collectApplicationProFiles(QList<Qt4ProFileNode *> &list, Qt4ProFileNode *node)
+{
+ if (node->projectType() == Internal::ApplicationTemplate
+ || node->projectType() == Internal::ScriptTemplate) {
+ list.append(node);
+ }
+ foreach (ProjectNode *n, node->subProjectNodes()) {
+ Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(n);
+ if (qt4ProFileNode)
+ collectApplicationProFiles(list, qt4ProFileNode);
+ }
+}
+
+void Qt4Project::foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &nodes)
+{
+ QList<Qt4ProFileNode *> list;
+ foreach (FolderNode *node, nodes) {
+ Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(node);
+ if (qt4ProFileNode)
+ collectApplicationProFiles(list, qt4ProFileNode);
+ }
+ m_applicationProFileChange = list;
+}
+
+void Qt4Project::checkForNewApplicationProjects()
+{
+ // Check all new project nodes
+ // against all runConfigurations
+
+ foreach (Qt4ProFileNode *qt4proFile, m_applicationProFileChange) {
+ bool found = false;
+ foreach (QSharedPointer<RunConfiguration> rc, runConfigurations()) {
+ QSharedPointer<Qt4RunConfiguration> qtrc = rc.dynamicCast<Qt4RunConfiguration>();
+ if (qtrc && qtrc->proFilePath() == qt4proFile->path()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ QSharedPointer<Qt4RunConfiguration> newRc(new Qt4RunConfiguration(this, qt4proFile->path()));
+ addRunConfiguration(newRc);
+ m_isApplication = true;
+ }
+ }
+}
+
+void Qt4Project::checkForDeletedApplicationProjects()
+{
+ QStringList paths;
+ foreach (Qt4ProFileNode * node, applicationProFiles())
+ paths.append(node->path());
+
+ qDebug()<<"Still existing paths :"<<paths;
+
+ QList<QSharedPointer<Qt4RunConfiguration> > removeList;
+ foreach (QSharedPointer<RunConfiguration> rc, runConfigurations()) {
+ if (QSharedPointer<Qt4RunConfiguration> qt4rc = rc.dynamicCast<Qt4RunConfiguration>()) {
+ if (!paths.contains(qt4rc->proFilePath())) {
+ removeList.append(qt4rc);
+ qDebug()<<"Removing runConfiguration for "<<qt4rc->proFilePath();
+ }
+ }
+ }
+
+ bool resetActiveRunConfiguration = false;
+ QSharedPointer<RunConfiguration> rc(new ProjectExplorer::CustomExecutableRunConfiguration(this));
+ foreach(QSharedPointer<Qt4RunConfiguration> qt4rc, removeList) {
+ removeRunConfiguration(qt4rc);
+ if (activeRunConfiguration() == qt4rc)
+ resetActiveRunConfiguration = true;
+ }
+
+ if (runConfigurations().isEmpty()) {
+ QSharedPointer<RunConfiguration> rc(new ProjectExplorer::CustomExecutableRunConfiguration(this));
+ addRunConfiguration(rc);
+ setActiveRunConfiguration(rc);
+ m_isApplication = false;
+ } else if (resetActiveRunConfiguration) {
+ setActiveRunConfiguration(runConfigurations().first());
+ }
+}
+
+QList<Qt4ProFileNode *> Qt4Project::applicationProFiles() const
+{
+ QList<Qt4ProFileNode *> list;
+ collectApplicationProFiles(list, rootProjectNode());
+ return list;
+}
+
+void Qt4Project::projectTypeChanged(Qt4ProFileNode *node, const Qt4ProjectType oldType, const Qt4ProjectType newType)
+{
+ if (oldType == Internal::ApplicationTemplate
+ || oldType == Internal::ScriptTemplate) {
+ // check wheter we need to delete a Run Configuration
+ checkForDeletedApplicationProjects();
+ }
+
+ if (newType == Internal::ApplicationTemplate
+ || newType == Internal::ScriptTemplate) {
+ // add a new Run Configuration
+ m_applicationProFileChange.clear();
+ m_applicationProFileChange.append(node);
+ checkForNewApplicationProjects();
+ }
+}
+
+void Qt4Project::proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *node)
+{
+ foreach (QSharedPointer<RunConfiguration> rc, runConfigurations()) {
+ if (QSharedPointer<Qt4RunConfiguration> qt4rc = rc.dynamicCast<Qt4RunConfiguration>()) {
+ if (qt4rc->proFilePath() == node->path()) {
+ qt4rc->updateCachedValues();
+ }
+ }
+ }
+}
+
+
+QMakeStep *Qt4Project::qmakeStep() const
+{
+ QMakeStep *qs = 0;
+ foreach(BuildStep *bs, buildSteps())
+ if ( (qs = qobject_cast<QMakeStep *>(bs)) != 0)
+ return qs;
+ return 0;
+}
+
+MakeStep *Qt4Project::makeStep() const
+{
+ MakeStep *qs = 0;
+ foreach(BuildStep *bs, buildSteps())
+ if ((qs = qobject_cast<MakeStep *>(bs)) != 0)
+ return qs;
+ return 0;
+}
diff --git a/src/plugins/qt4projectmanager/qt4project.h b/src/plugins/qt4projectmanager/qt4project.h
new file mode 100644
index 0000000000..c67c5dc9bd
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4project.h
@@ -0,0 +1,239 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4PROJECT_H
+#define QT4PROJECT_H
+
+#include "qtversionmanager.h"
+#include "qt4nodes.h"
+#include "gccpreprocessor.h"
+#include "qmakestep.h"
+#include "makestep.h"
+
+#include <coreplugin/ifile.h>
+#include <projectexplorer/applicationrunconfiguration.h>
+#include <projectexplorer/projectnodes.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QStringList>
+#include <QtCore/QPointer>
+#include <QtGui/QDirModel>
+#include "qtextended_integration.h"
+
+namespace Core {
+ class IWizard;
+}
+
+namespace CppTools {
+ class ICppCodeModel;
+}
+
+QT_BEGIN_NAMESPACE
+class ProFile;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+ class ProFileReader;
+ class DeployHelperRunStep;
+ class FileItem;
+ class Qt4ProFileNode;
+ class Qt4RunConfiguration;
+ class GCCPreprocessor;
+ struct Qt4ProjectFiles;
+}
+
+class QMakeStep;
+class MakeStep;
+
+class Qt4Manager;
+class Qt4Project;
+class Qt4RunStep;
+
+class Qt4ProjectFile
+ : public Core::IFile
+{
+ Q_OBJECT
+
+ // needed for createProFileReader
+ friend class Internal::Qt4RunConfiguration;
+
+public:
+ Qt4ProjectFile(Qt4Project *project, const QString &filePath, QObject *parent = 0);
+
+ bool save(const QString &fileName = QString());
+ QString fileName() const;
+
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+ virtual QString mimeType() const;
+
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+
+ void modified(Core::IFile::ReloadBehavior *behavior);
+
+private:
+ Core::IFile *fileFromCache() const;
+
+ const QString m_mimeType;
+ Qt4Project *m_project;
+ QString m_filePath;
+};
+
+class Qt4Project
+ : public ProjectExplorer::Project
+{
+ Q_OBJECT
+
+public:
+ explicit Qt4Project(Qt4Manager *manager, const QString &proFile);
+ virtual ~Qt4Project();
+
+ QString name() const;
+ Core::IFile *file() const;
+ ProjectExplorer::IProjectManager *projectManager() const;
+ Qt4Manager *qt4ProjectManager() const;
+
+ QList<Core::IFile *> dependencies(); //NBS remove
+ QList<ProjectExplorer::Project *>dependsOn();
+
+ bool isApplication() const;
+
+ Internal::Qt4ProFileNode *rootProjectNode() const;
+
+ virtual QStringList files(FilesMode fileMode) const;
+
+ //building environment
+ ProjectExplorer::Environment environment(const QString &buildConfiguration) const;
+ ProjectExplorer::Environment baseEnvironment(const QString &buildConfiguration) const;
+ void setUserEnvironmentChanges(const QString &buildConfig, const QList<ProjectExplorer::EnvironmentItem> &diff);
+ QList<ProjectExplorer::EnvironmentItem> userEnvironmentChanges(const QString &buildConfig) const;
+
+ virtual QString buildDirectory(const QString &buildConfiguration) const;
+
+ //Qt4Project specific(?)
+ bool useSystemEnvironment(const QString &buildConfiguration) const;
+ void setUseSystemEnvironment(const QString &buildConfiguration, bool b);
+
+ // returns the CONFIG variable from the .pro file
+ QStringList qmakeConfig() const;
+ // returns the qtdir (depends on the current QtVersion)
+ QString qtDir(const QString &buildConfiguration) const;
+ //returns the qtVersion, if the project is set to use the default qt version, then
+ // that is returned
+ // to check wheter the project uses the default qt version use qtVersionId
+ Internal::QtVersion *qtVersion(const QString &buildConfiguration) const;
+
+ // returns the id of the qt version, if the project is using the default qt version
+ // this function returns 0
+ int qtVersionId(const QString &buildConfiguration) const;
+ //returns the name of the qt version, might be QString::Null, which means default qt version
+ // qtVersion is in general the better method to use
+ QString qtVersionName(const QString &buildConfiguration) const;
+
+ ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
+ QList<ProjectExplorer::BuildStepConfigWidget*> subConfigWidgets();
+
+ void setQtVersion(const QString &buildConfiguration, int id);
+ virtual void newBuildConfiguration(const QString &buildConfiguration);
+
+ QList<Internal::Qt4ProFileNode *> applicationProFiles() const;
+ Internal::ProFileReader *createProFileReader() const;
+
+ // Those functions arein a few places.
+ // The drawback is that we shouldn't actually depend on them beeing always there
+ // That is generally the stuff that is asked should normally be transfered to
+ // Qt4Project *
+ // So that we can later enable people to build qt4projects the way they would like
+ QMakeStep *qmakeStep() const;
+ MakeStep *makeStep() const;
+
+public slots:
+ void update();
+ void proFileParseError(const QString &errorMessage);
+ void scheduleUpdateCodeModel();
+
+private slots:
+ void updateCodeModel();
+ void defaultQtVersionChanged();
+ void qtVersionsChanged();
+ void updateFileList();
+
+ void foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &);
+ void checkForNewApplicationProjects();
+ void checkForDeletedApplicationProjects();
+ void projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *node,
+ const Qt4ProjectManager::Internal::Qt4ProjectType oldType,
+ const Qt4ProjectManager::Internal::Qt4ProjectType newType);
+ void proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *node);
+
+protected:
+ virtual void restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader &settingsReader);
+ virtual void saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer);
+
+private:
+ static void collectApplicationProFiles(QList<Internal::Qt4ProFileNode *> &list, Internal::Qt4ProFileNode *node);
+
+ QList<Internal::Qt4ProFileNode *> m_applicationProFileChange;
+ ProjectExplorer::ProjectExplorerPlugin *projectExplorer() const;
+
+ void addDefaultBuild();
+
+ static QString qmakeVarName(ProjectExplorer::FileType type);
+
+ Qt4Manager *m_manager;
+ Internal::Qt4ProFileNode *m_rootProjectNode;
+ Internal::Qt4NodesWatcher *m_nodesWatcher;
+
+ Qt4ProjectFile *m_fileInfo;
+ bool m_isApplication;
+
+ // Current configuration
+ QString m_oldQtIncludePath;
+ QString m_oldQtLibsPath;
+
+ // cached lists of all of files
+ Internal::Qt4ProjectFiles *m_projectFiles;
+
+ QTimer m_updateCodeModelTimer;
+ Internal::GCCPreprocessor m_preproc;
+
+ friend class Qt4ProjectFile;
+};
+
+} // namespace Qt4ProjectManager
+
+#endif // QT4PROJECT_H
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.cpp b/src/plugins/qt4projectmanager/qt4projectmanager.cpp
new file mode 100644
index 0000000000..43c509d234
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.cpp
@@ -0,0 +1,229 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4projectmanager.h"
+#include "qt4projectmanagerconstants.h"
+#include "qt4projectmanagerplugin.h"
+#include "qt4nodes.h"
+#include "qt4project.h"
+#include "profilecache.h"
+#include "profilereader.h"
+#include "qtversionmanager.h"
+#include "qmakestep.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/basefilewizard.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+#include <projectexplorer/project.h>
+#include <utils/listutils.h>
+
+#include <QtCore/QVariant>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QLinkedList>
+#include <QtGui/QMenu>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+using ProjectExplorer::BuildStep;
+using ProjectExplorer::FileType;
+using ProjectExplorer::HeaderType;
+using ProjectExplorer::SourceType;
+using ProjectExplorer::FormType;
+using ProjectExplorer::ResourceType;
+using ProjectExplorer::UnknownFileType;
+
+// Known file types of a Qt 4 project
+static const char* qt4FileTypes[] = {"CppHeaderFiles", "CppSourceFiles", "Qt4FormFiles", "Qt4ResourceFiles" };
+
+Qt4Manager::Qt4Manager(Qt4ProjectManagerPlugin *plugin, Core::ICore *core) :
+ m_mimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)),
+ m_plugin(plugin),
+ m_core(core),
+ m_projectExplorer(0),
+ m_contextProject(0),
+ m_languageID(0),
+ m_proFileCache(0)
+{
+ m_languageID = m_core->uniqueIDManager()->
+ uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
+ m_proFileCache = new ProFileCache(this);
+}
+
+Qt4Manager::~Qt4Manager()
+{
+}
+
+void Qt4Manager::init()
+{
+ m_projectExplorer = m_core->pluginManager()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+}
+
+int Qt4Manager::projectContext() const
+{
+ return m_plugin->projectContext();
+}
+
+int Qt4Manager::projectLanguage() const
+{
+ return m_languageID;
+}
+
+QString Qt4Manager::mimeType() const
+{
+ return m_mimeType;
+}
+
+ProjectExplorer::Project* Qt4Manager::openProject(const QString &fileName)
+{
+ typedef QMultiMap<QString, QString> DependencyMap;
+ const QString dotSubDir = QLatin1String(".subdir");
+ const QString dotDepends = QLatin1String(".depends");
+ const QChar slash = QLatin1Char('/');
+
+ QString errorMessage;
+
+ m_core->messageManager()->displayStatusBarMessage(tr("Loading project %1 ...").arg(fileName), 50000);
+
+ // TODO Make all file paths relative & remove this hack
+ // We convert the path to an absolute one here because qt4project.cpp
+ // && profileevaluator use absolute/canonical file paths all over the place
+ // Correct fix would be to remove these calls ...
+ QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
+
+ if (canonicalFilePath.isEmpty()) {
+ m_core->messageManager()->printToOutputPane(tr("Failed opening project '%1': Project file does not exist").arg(canonicalFilePath));
+ m_core->messageManager()->displayStatusBarMessage(tr("Failed opening project"), 5000);
+ return 0;
+ }
+
+ foreach (ProjectExplorer::Project *pi, projectExplorer()->session()->projects()) {
+ if (canonicalFilePath == pi->file()->fileName()) {
+ m_core->messageManager()->printToOutputPane(tr("Failed opening project '%1': Project already open").arg(canonicalFilePath));
+ m_core->messageManager()->displayStatusBarMessage(tr("Failed opening project"), 5000);
+ return 0;
+ }
+ }
+
+ m_core->messageManager()->displayStatusBarMessage(tr("Opening %1 ...").arg(fileName));
+ QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+
+ Qt4Project *pro = new Qt4Project(this, canonicalFilePath);
+
+ m_core->messageManager()->displayStatusBarMessage(tr("Done opening project"), 5000);
+ return pro;
+}
+
+ProjectExplorer::ProjectExplorerPlugin *Qt4Manager::projectExplorer() const
+{
+ return m_projectExplorer;
+}
+
+Core::ICore *Qt4Manager::core() const
+{
+ return m_core;
+}
+
+ExtensionSystem::PluginManager *Qt4Manager::pluginManager() const
+{
+ return m_core->pluginManager();
+}
+
+ProjectExplorer::Node *Qt4Manager::contextNode() const
+{
+ return m_contextNode;
+}
+
+void Qt4Manager::setContextNode(ProjectExplorer::Node *node)
+{
+ m_contextNode = node;
+}
+
+void Qt4Manager::setContextProject(ProjectExplorer::Project *project)
+{
+ m_contextProject = project;
+}
+
+ProjectExplorer::Project *Qt4Manager::contextProject() const
+{
+ return m_contextProject;
+}
+
+QtVersionManager *Qt4Manager::versionManager() const
+{
+ return m_plugin->versionManager();
+}
+
+void Qt4Manager::runQMake()
+{
+ runQMake(m_projectExplorer->currentProject());
+}
+
+void Qt4Manager::runQMakeContextMenu()
+{
+ runQMake(m_contextProject);
+}
+
+void Qt4Manager::runQMake(ProjectExplorer::Project *p)
+{
+ QMakeStep *qmakeStep = qobject_cast<Qt4Project *>(p)->qmakeStep();
+ //found qmakeStep, now use it
+ qmakeStep->setForced(true);
+ const QString &config = p->activeBuildConfiguration();
+ m_projectExplorer->buildManager()->appendStep(qmakeStep, config);
+}
+
+QString Qt4Manager::fileTypeId(ProjectExplorer::FileType type)
+{
+ switch (type) {
+ case HeaderType:
+ return QLatin1String(qt4FileTypes[0]);
+ case SourceType:
+ return QLatin1String(qt4FileTypes[1]);
+ case FormType:
+ return QLatin1String(qt4FileTypes[2]);
+ case ResourceType:
+ return QLatin1String(qt4FileTypes[3]);
+ case UnknownFileType:
+ default:
+ break;
+ }
+ return QString();
+}
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.h b/src/plugins/qt4projectmanager/qt4projectmanager.h
new file mode 100644
index 0000000000..86126cae5e
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4PROJECTMANAGER_H
+#define QT4PROJECTMANAGER_H
+
+#include <projectexplorer/iprojectmanager.h>
+#include <projectexplorer/projectnodes.h>
+#include <coreplugin/dialogs/iwizard.h>
+
+#include <QtCore/QModelIndex>
+
+namespace ExtensionSystem {
+class PluginManager;
+}
+
+namespace Core {
+class ICore;
+}
+
+namespace ProjectExplorer {
+class Project;
+class ProjectExplorerPlugin;
+}
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+class Qt4Builder;
+class ProFileCache;
+class ProFileEditor;
+class Qt4ProjectManagerPlugin;
+class QtVersionManager;
+}
+
+class Qt4Project;
+
+class Qt4Manager
+ : public ProjectExplorer::IProjectManager
+{
+ Q_OBJECT
+
+public:
+ Qt4Manager(Internal::Qt4ProjectManagerPlugin *plugin, Core::ICore *core);
+ ~Qt4Manager();
+
+ void init();
+ inline Internal::ProFileCache *proFileCache() const { return m_proFileCache; }
+
+ ProjectExplorer::ProjectExplorerPlugin *projectExplorer() const;
+ ExtensionSystem::PluginManager *pluginManager() const;
+ Core::ICore *core() const;
+
+ //ProjectExplorer::IProjectManager
+ int projectContext() const;
+ int projectLanguage() const;
+
+ virtual QString mimeType() const;
+ ProjectExplorer::Project* openProject(const QString &fileName);
+
+ // Context information used in the slot implementations
+ ProjectExplorer::Node *contextNode() const;
+ void setContextNode(ProjectExplorer::Node *node);
+ void setContextProject(ProjectExplorer::Project *project);
+ ProjectExplorer::Project *contextProject() const;
+
+ Internal::QtVersionManager *versionManager() const;
+
+ // Return the id string of a file
+ static QString fileTypeId(ProjectExplorer::FileType type);
+
+public slots:
+ void runQMake();
+ void runQMakeContextMenu();
+
+private:
+ void runQMake(ProjectExplorer::Project *p);
+
+ const QString m_mimeType;
+ Internal::Qt4ProjectManagerPlugin *m_plugin;
+ Core::ICore *m_core;
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+
+ ProjectExplorer::Node *m_contextNode;
+ ProjectExplorer::Project *m_contextProject;
+
+ int m_languageID;
+
+ Internal::ProFileCache *m_proFileCache;
+};
+
+} //namespace Qt4ProjectManager
+
+#endif //QT4PROJECTMANAGER_H
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro
new file mode 100644
index 0000000000..0118cf967c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro
@@ -0,0 +1,101 @@
+TEMPLATE = lib
+TARGET = Qt4ProjectManager
+QT += network
+include(../../qworkbenchplugin.pri)
+include(qt4projectmanager_dependencies.pri)
+HEADERS = qt4projectmanagerplugin.h \
+ qt4projectmanager.h \
+ qt4projectmanagerenums.h \
+ qtversionmanager.h \
+ qt4project.h \
+ qt4nodes.h \
+ profileeditor.h \
+ profilehighlighter.h \
+ profileeditorfactory.h \
+ profilereader.h \
+ profilecache.h \
+ wizards/qtprojectparameters.h \
+ wizards/guiappwizard.h \
+ wizards/consoleappwizard.h \
+ wizards/consoleappwizarddialog.h \
+ wizards/libraryparameters.h \
+ wizards/librarywizard.h \
+ wizards/librarywizarddialog.h \
+ wizards/guiappwizarddialog.h \
+ wizards/modulespage.h \
+ wizards/filespage.h \
+ wizards/qtwizard.h \
+ qt4projectmanagerconstants.h \
+ makestep.h \
+ qmakestep.h \
+ qmakebuildstepfactory.h \
+ gccparser.h \
+ msvcparser.h \
+ buildparserfactory.h \
+ deployhelper.h \
+ msvcenvironment.h \
+ cesdkhandler.h \
+ embeddedpropertiespage.h \
+ qt4runconfiguration.h \
+ speinfo.h \
+ headerpath.h \
+ gccpreprocessor.h \
+ qt4buildconfigwidget.h \
+ qt4buildenvironmentwidget.h \
+ projectloadwizard.h \
+ directorywatcher.h \
+ gdbmacrosbuildstep.h
+
+SOURCES = qt4projectmanagerplugin.cpp \
+ qt4projectmanager.cpp \
+ qtversionmanager.cpp \
+ qt4project.cpp \
+ qt4nodes.cpp \
+ profileeditor.cpp \
+ profilehighlighter.cpp \
+ profileeditorfactory.cpp \
+ profilereader.cpp \
+ profilecache.cpp \
+ wizards/qtprojectparameters.cpp \
+ wizards/guiappwizard.cpp \
+ wizards/consoleappwizard.cpp \
+ wizards/consoleappwizarddialog.cpp \
+ wizards/libraryparameters.cpp \
+ wizards/librarywizard.cpp \
+ wizards/librarywizarddialog.cpp \
+ wizards/guiappwizarddialog.cpp \
+ wizards/modulespage.cpp \
+ wizards/filespage.cpp \
+ wizards/qtwizard.cpp \
+ makestep.cpp \
+ qmakestep.cpp \
+ qmakebuildstepfactory.cpp \
+ gccparser.cpp \
+ msvcparser.cpp \
+ buildparserfactory.cpp \
+ deployhelper.cpp \
+ msvcenvironment.cpp \
+ cesdkhandler.cpp \
+ embeddedpropertiespage.cpp \
+ qt4runconfiguration.cpp \
+ speinfo.cpp \
+ gccpreprocessor.cpp \
+ qt4buildconfigwidget.cpp \
+ qt4buildenvironmentwidget.cpp \
+ projectloadwizard.cpp \
+ directorywatcher.cpp \
+ gdbmacrosbuildstep.cpp
+
+FORMS = qtversionmanager.ui \
+ envvariablespage.ui \
+ enveditdialog.ui \
+ proeditorcontainer.ui \
+ makestep.ui \
+ qmakestep.ui \
+ qt4buildconfigwidget.ui \
+ embeddedpropertiespage.ui \
+ qt4buildenvironmentwidget.ui
+RESOURCES = qt4projectmanager.qrc \
+ wizards/wizards.qrc
+include(../../../shared/proparser/proparser.pri)
+DEFINES += QT_NO_CAST_TO_ASCII
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.qrc b/src/plugins/qt4projectmanager/qt4projectmanager.qrc
new file mode 100644
index 0000000000..f733770e2f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/qt4projectmanager" >
+ <file>images/window.png</file>
+ <file>images/run_qmake.png</file>
+ <file>images/run_qmake_small.png</file>
+ <file>images/qt_project.png</file>
+ <file>Qt4ProjectManager.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager_dependencies.pri b/src/plugins/qt4projectmanager/qt4projectmanager_dependencies.pri
new file mode 100644
index 0000000000..df694f31fc
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanager_dependencies.pri
@@ -0,0 +1,4 @@
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/cpptools/cpptools.pri)
+include(../../plugins/cppeditor/cppeditor.pri)
+include(../../plugins/help/help.pri)
diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h b/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h
new file mode 100644
index 0000000000..67e5985f5f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4PROJECTMANAGERCONSTANTS_H
+#define QT4PROJECTMANAGERCONSTANTS_H
+
+namespace Qt4ProjectManager {
+namespace Constants {
+
+//contexts
+const char * const C_PROFILEEDITOR = ".pro File Editor";
+const char * const C_PROFILEEDITOR_PANEL = ".pro File Editor (embedded)";
+
+//settings pages
+const char * const QT_CATEGORY = "Qt4";
+const char * const QTVERSION_PAGE = "Qt Versions";
+const char * const BUILD_ENVIRONMENT_PAGE = "Build Environments";
+
+// kinds
+const char * const PROJECT_KIND = "Qt4";
+const char * const PROFILE_EDITOR = ".pro File Editor";
+const char * const PROFILE_MIMETYPE = "application/vnd.nokia.qt.qmakeprofile";
+const char * const PROINCLUDEFILE_MIMETYPE = "application/vnd.nokia.qt.qmakeproincludefile";
+const char * const CPP_SOURCE_MIMETYPE = "text/x-c++src";
+const char * const CPP_HEADER_MIMETYPE = "text/x-c++hdr";
+const char * const FORM_MIMETYPE = "application/x-designer";
+
+//actions
+const char * const NEWMENU = "Qt4.NewMenu";
+const char * const PROJECT_NEWMENU_SEPARATOR = "Qt4.NewMenuSeparator";
+const char * const SUBPROJECT_NEWMENU_SEPARATOR = "Qt4.SubProjectNewMenuSeparator";
+const char * const ADDTOPROJECT = "Qt4.AddToProject";
+const char * const RUNQMAKE = "Qt4Builder.RunQMake";
+const char * const RUNQMAKECONTEXTMENU = "Qt4Builder.RunQMakeContextMenu";
+
+//configurations
+const char * const CONFIG_DEBUG = "debug";
+const char * const CONFIG_RELEASE = "release";
+
+//global configurations
+const char * const GC_BUILDCONFIG = "Qt4.BuildConfig";
+const char * const GC_QTVERSION = "Qt4.QtVersion";
+const char * const GC_COMPILER = "Qt4.Compiler";
+
+// qmakestep
+const char * const QMAKESTEP = "trolltech.qt4projectmanager.qmake";
+const char * const MAKESTEP = "trolltech.qt4projectmanager.make";
+const char * const GDBMACROSBUILDSTEP = "trolltech.qt4projectmanager.gdbmaros";
+const char * const QT4RUNSTEP = "trolltech.qt4projectmanager.qt4runstep";
+
+// build parsers
+const char * const BUILD_PARSER_MSVC = "BuildParser.MSVC";
+const char * const BUILD_PARSER_GCC = "BuildParser.Gcc";
+
+// views
+const char * const VIEW_DETAILED = "Qt4.View.Detailed";
+const char * const VIEW_PROFILESONLY = "Qt4.View.ProjectHierarchy";
+} // namespace Constants
+} // namespace Qt4ProjectManager
+
+#endif // QT4PROJECTMANAGERCONSTANTS_H
diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerenums.h b/src/plugins/qt4projectmanager/qt4projectmanagerenums.h
new file mode 100644
index 0000000000..e6a9883d06
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanagerenums.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4PRO_ENUMS_H
+#define QT4PRO_ENUMS_H
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+enum ProfileFormats {
+ ProfileVariableFormat,
+ ProfileFunctionFormat,
+ ProfileCommentFormat,
+ NumProfileFormats
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif //QT4PRO_ENUMS_H
diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
new file mode 100644
index 0000000000..cb599bf514
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
@@ -0,0 +1,235 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4projectmanagerplugin.h"
+#include "qt4projectmanager.h"
+#include "wizards/consoleappwizard.h"
+#include "wizards/guiappwizard.h"
+#include "wizards/librarywizard.h"
+#include "profileeditorfactory.h"
+#include "qt4projectmanagerconstants.h"
+#include "qt4project.h"
+#include "profilecache.h"
+#include "qmakebuildstepfactory.h"
+#include "buildparserfactory.h"
+#include "qtversionmanager.h"
+#include "embeddedpropertiespage.h"
+#include "qt4runconfiguration.h"
+#include "profilereader.h"
+#include "gdbmacrosbuildstep.h"
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectnodes.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <texteditor/texteditoractionhandler.h>
+
+#include <QtCore/qplugin.h>
+#include <QtGui/QMenu>
+#include <QDebug>
+
+#ifdef WITH_TESTS
+#include <QTest>
+#include <extensionsystem/pluginmanager.h>
+#endif
+
+using namespace Qt4ProjectManager::Internal;
+using namespace Qt4ProjectManager;
+using ProjectExplorer::Project;
+
+Qt4ProjectManagerPlugin::~Qt4ProjectManagerPlugin()
+{
+ //removeObject(m_embeddedPropertiesPage);
+ //delete m_embeddedPropertiesPage;
+
+ removeObject(m_qtVersionManager);
+ delete m_qtVersionManager;
+
+ removeObject(m_proFileEditorFactory);
+ delete m_proFileEditorFactory;
+ removeObject(m_qt4ProjectManager);
+ delete m_qt4ProjectManager;
+}
+/*
+static Core::ICommand *createSeparator(Core::ActionManagerInterface *am,
+ QObject *parent,
+ const QString &name,
+ const QList<int> &context)
+{
+ QAction *tmpaction = new QAction(parent);
+ tmpaction->setSeparator(true);
+ return am->registerAction(tmpaction, name, context);
+}
+*/
+bool Qt4ProjectManagerPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!m_core->mimeDatabase()->addMimeTypes(QLatin1String(":qt4projectmanager/Qt4ProjectManager.mimetypes.xml"), errorMessage))
+ return false;
+
+ m_projectExplorer = m_core->pluginManager()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ //create and register objects
+ m_qt4ProjectManager = new Qt4Manager(this, m_core);
+ addObject(m_qt4ProjectManager);
+
+ TextEditor::TextEditorActionHandler *editorHandler
+ = new TextEditor::TextEditorActionHandler(m_core, Constants::C_PROFILEEDITOR);
+
+ m_proFileEditorFactory = new ProFileEditorFactory(m_qt4ProjectManager, editorHandler);
+ addObject(m_proFileEditorFactory);
+
+ GuiAppWizard *guiWizard = new GuiAppWizard(m_core);
+ addAutoReleasedObject(guiWizard);
+
+ ConsoleAppWizard *consoleWizard = new ConsoleAppWizard(m_core);
+ addAutoReleasedObject(consoleWizard);
+
+ LibraryWizard *libWizard = new LibraryWizard(m_core);
+ addAutoReleasedObject(libWizard);
+
+ addAutoReleasedObject(new QMakeBuildStepFactory);
+ addAutoReleasedObject(new MakeBuildStepFactory);
+ addAutoReleasedObject(new GdbMacrosBuildStepFactory);
+
+ addAutoReleasedObject(new GccParserFactory);
+ addAutoReleasedObject(new MsvcParserFactory);
+
+ m_qtVersionManager = new QtVersionManager;
+ addObject(m_qtVersionManager);
+
+ addAutoReleasedObject(new Qt4RunConfigurationFactory);
+ addAutoReleasedObject(new Qt4RunConfigurationFactoryUser);
+
+ // TODO reenable
+ //m_embeddedPropertiesPage = new EmbeddedPropertiesPage;
+ //addObject(m_embeddedPropertiesPage);
+
+ //menus
+ Core::IActionContainer *mbuild =
+ am->actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
+ Core::IActionContainer *mproject =
+ am->actionContainer(ProjectExplorer::Constants::M_PROJECTCONTEXT);
+
+ //register actions
+ m_projectContext = m_core->uniqueIDManager()->
+ uniqueIdentifier(Qt4ProjectManager::Constants::PROJECT_KIND);
+ QList<int> context = QList<int>() << m_projectContext;
+ Core::ICommand *command;
+
+ QIcon qmakeIcon(QLatin1String(":/qt4projectmanager/images/run_qmake.png"));
+ qmakeIcon.addFile(QLatin1String(":/qt4projectmanager/images/run_qmake_small.png"));
+ m_runQMakeAction = new QAction(qmakeIcon, tr("Run qmake"), this);
+ command = am->registerAction(m_runQMakeAction, Constants::RUNQMAKE, context);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_RUN);
+ connect(m_runQMakeAction, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMake()));
+
+ m_runQMakeActionContextMenu = new QAction(qmakeIcon, tr("Run qmake"), this);
+ command = am->registerAction(m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, context);
+ mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+ connect(m_runQMakeActionContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMakeContextMenu()));
+
+
+ connect(m_projectExplorer,
+ SIGNAL(aboutToShowContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)),
+ this, SLOT(updateContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)));
+
+ connect(m_projectExplorer->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project *)),
+ this, SLOT(buildStateChanged(ProjectExplorer::Project *)));
+ connect(m_projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
+ this, SLOT(currentProjectChanged()));
+
+ return true;
+}
+
+void Qt4ProjectManagerPlugin::extensionsInitialized()
+{
+ m_qt4ProjectManager->init();
+ m_proFileEditorFactory->initializeActions();
+}
+
+void Qt4ProjectManagerPlugin::updateContextMenu(Project *project,
+ ProjectExplorer::Node *node)
+{
+ m_qt4ProjectManager->setContextProject(project);
+ m_qt4ProjectManager->setContextNode(node);
+ m_runQMakeActionContextMenu->setEnabled(false);
+
+ if (qobject_cast<Qt4Project *>(project)) {
+ if (!m_projectExplorer->buildManager()->isBuilding(project))
+ m_runQMakeActionContextMenu->setEnabled(true);
+ }
+}
+
+QtVersionManager *Qt4ProjectManagerPlugin::versionManager() const
+{
+ return m_qtVersionManager;
+}
+
+void Qt4ProjectManagerPlugin::currentProjectChanged()
+{
+ m_runQMakeAction->setEnabled(!m_projectExplorer->buildManager()->isBuilding(m_projectExplorer->currentProject()));
+}
+
+void Qt4ProjectManagerPlugin::buildStateChanged(ProjectExplorer::Project *pro)
+{
+ ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
+ if (pro == currentProject)
+ m_runQMakeAction->setEnabled(!m_projectExplorer->buildManager()->isBuilding(currentProject));
+ if (pro == m_qt4ProjectManager->contextProject())
+ m_runQMakeActionContextMenu->setEnabled(!m_projectExplorer->buildManager()->isBuilding(pro));
+}
+
+#ifdef WITH_TESTS
+void Qt4ProjectManagerPlugin::testBasicProjectLoading()
+{
+
+ QString testDirectory = ExtensionSystem::PluginManager::instance()->testDataDirectory() + "/qt4projectmanager/";
+ QString test1 = testDirectory + "test1/test1.pro";
+ m_projectExplorer->openProject(test1);
+ QVERIFY(!m_projectExplorer->session()->projects().isEmpty());
+ Qt4Project *qt4project = qobject_cast<Qt4Project *>(m_projectExplorer->session()->projects().first());
+ QVERIFY(qt4project);
+ QVERIFY(qt4project->rootProjectNode()->projectType() == ApplicationTemplate);
+ QVERIFY(m_projectExplorer->currentProject() != 0);
+}
+
+void Qt4ProjectManagerPlugin::testNotYetImplemented()
+{
+ QCOMPARE(1+1, 2);
+}
+#endif
+
+Q_EXPORT_PLUGIN(Qt4ProjectManagerPlugin)
diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h
new file mode 100644
index 0000000000..d1f0815a5f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4PROJECTMANAGERPLUGIN_H
+#define QT4PROJECTMANAGERPLUGIN_H
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <coreplugin/icore.h>
+
+namespace Qt4ProjectManager {
+
+class Qt4Manager;
+
+namespace Internal {
+
+class ProFileEditorFactory;
+class ConsoleAppWizard;
+class GuiAppWizard;
+class QMakeBuildStepFactory;
+class MakeBuildStepFactory;
+class GccParserFactory;
+class MsvcParserFactory;
+class QtVersionManager;
+class EmbeddedPropertiesPage;
+
+class Qt4ProjectManagerPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ ~Qt4ProjectManagerPlugin();
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+ int projectContext() const { return m_projectContext; }
+ QtVersionManager *versionManager() const;
+
+
+private slots:
+ void updateContextMenu(ProjectExplorer::Project *project,
+ ProjectExplorer::Node *node);
+ void currentProjectChanged();
+ void buildStateChanged(ProjectExplorer::Project *pro);
+
+#ifdef WITH_TESTS
+ void testBasicProjectLoading();
+ void testNotYetImplemented();
+#endif
+
+private:
+ Core::ICore *m_core;
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ ProFileEditorFactory *m_proFileEditorFactory;
+ Qt4Manager *m_qt4ProjectManager;
+ QtVersionManager *m_qtVersionManager;
+ EmbeddedPropertiesPage *m_embeddedPropertiesPage;
+
+ int m_projectContext;
+
+ QAction *m_runQMakeAction;
+ QAction *m_runQMakeActionContextMenu;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif // QT4PROJECTMANAGERPLUGIN_H
diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp
new file mode 100644
index 0000000000..d2cead008a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp
@@ -0,0 +1,443 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qt4runconfiguration.h"
+#include "qt4project.h"
+#include "profilereader.h"
+#include "qt4nodes.h"
+#include "makestep.h"
+
+
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/variablemanager.h>
+#include <projectexplorer/buildstep.h>
+
+#include <QtGui/QFormLayout>
+#include <QtGui/QInputDialog>
+
+using namespace Qt4ProjectManager::Internal;
+using namespace Qt4ProjectManager;
+using ProjectExplorer::ApplicationRunConfiguration;
+using ProjectExplorer::PersistentSettingsReader;
+using ProjectExplorer::PersistentSettingsWriter;
+
+Qt4RunConfiguration::Qt4RunConfiguration(Qt4Project *pro, QString proFilePath)
+ : ApplicationRunConfiguration(pro), m_proFilePath(proFilePath), m_userSetName(false)
+{
+ setName(tr("Qt4RunConfiguration"));
+ if (!m_proFilePath.isEmpty()) {
+ updateCachedValues();
+ setName(QFileInfo(m_proFilePath).baseName());
+ }
+}
+
+Qt4RunConfiguration::~Qt4RunConfiguration()
+{
+}
+
+QString Qt4RunConfiguration::type() const
+{
+ return "Qt4ProjectManager.Qt4RunConfiguration";
+}
+
+QWidget *Qt4RunConfiguration::configurationWidget()
+{
+ QWidget *configWidget = new QWidget;
+ QFormLayout *toplayout = new QFormLayout(configWidget);
+ toplayout->setMargin(0);
+
+ QLabel *nameLabel = new QLabel(tr("Name:"));
+ QLineEdit *nameLineEdit = new QLineEdit(name());
+ nameLabel->setBuddy(nameLineEdit);
+ toplayout->addRow(nameLabel, nameLineEdit);
+
+ QLabel *executableLabel = new QLabel(tr("Executable:"));
+ QLabel *executableLabel2 = new QLabel(executable());
+ toplayout->addRow(executableLabel, executableLabel2);
+
+ QLabel *workingDirectoryLabel = new QLabel(tr("Working Directory:"));
+ QLabel *workingDirectoryLabel2 = new QLabel(workingDirectory());
+ toplayout->addRow(workingDirectoryLabel, workingDirectoryLabel2);
+
+ QLabel *argumentsLabel = new QLabel(tr("&Arguments:"));
+ QLineEdit *argumentsLineEdit = new QLineEdit(ProjectExplorer::Environment::joinArgumentList(commandLineArguments()));
+ argumentsLabel->setBuddy(argumentsLineEdit);
+ toplayout->addRow(argumentsLabel, argumentsLineEdit);
+
+ connect(argumentsLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(setCommandLineArguments(const QString&)));
+
+ connect(nameLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(nameEdited(const QString&)));
+
+ return configWidget;
+}
+
+void Qt4RunConfiguration::save(PersistentSettingsWriter &writer) const
+{
+ writer.saveValue("CommandLineArguments", m_commandLineArguments);
+ writer.saveValue("ProFile", m_proFilePath);
+ writer.saveValue("UserSetName", m_userSetName);
+ ApplicationRunConfiguration::save(writer);
+}
+
+void Qt4RunConfiguration::restore(const PersistentSettingsReader &reader)
+{
+ ApplicationRunConfiguration::restore(reader);
+ m_commandLineArguments = reader.restoreValue("CommandLineArguments").toStringList();
+ m_proFilePath = reader.restoreValue("ProFile").toString();
+ m_userSetName = reader.restoreValue("UserSetName").toBool();
+ if (!m_proFilePath.isEmpty()) {
+ updateCachedValues();
+ if (!m_userSetName)
+ setName(QFileInfo(m_proFilePath).baseName());
+ }
+}
+
+QString Qt4RunConfiguration::executable() const
+{
+ return resolveVariables(project()->activeBuildConfiguration(), m_executable);
+}
+
+ApplicationRunConfiguration::RunMode Qt4RunConfiguration::runMode() const
+{
+ return m_runMode;
+}
+
+QString Qt4RunConfiguration::workingDirectory() const
+{
+ return resolveVariables(project()->activeBuildConfiguration(), m_workingDir);
+}
+
+QStringList Qt4RunConfiguration::commandLineArguments() const
+{
+ return m_commandLineArguments;
+}
+
+ProjectExplorer::Environment Qt4RunConfiguration::environment() const
+{
+ Qt4Project *pro = qobject_cast<Qt4Project *>(project());
+ Q_ASSERT(pro);
+ return pro->environment(pro->activeBuildConfiguration());
+}
+
+void Qt4RunConfiguration::setCommandLineArguments(const QString &argumentsString)
+{
+ m_commandLineArguments = ProjectExplorer::Environment::parseCombinedArgString(argumentsString);
+}
+
+void Qt4RunConfiguration::nameEdited(const QString &name)
+{
+ if (name == "") {
+ setName(tr("Qt4RunConfiguration"));
+ m_userSetName = false;
+ } else {
+ setName(name);
+ m_userSetName = true;
+ }
+}
+
+QString Qt4RunConfiguration::proFilePath() const
+{
+ return m_proFilePath;
+}
+
+// and needs to be reloaded.
+// Check wheter it is
+void Qt4RunConfiguration::updateCachedValues()
+{
+ ProFileReader *reader = static_cast<Qt4Project *>(project())->createProFileReader();
+ if (!reader->readProFile(m_proFilePath)) {
+ delete reader;
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ core->messageManager()->printToOutputPane(QString("Could not parse %1. The Qt4 run configuration %2 can not be started.").arg(m_proFilePath).arg(name()));
+ return;
+ }
+
+ QString destDir;
+
+ if (reader->contains("DESTDIR")) {
+ // TODO Can return different destdirs for different scopes!
+ destDir = reader->value("DESTDIR");
+ if (QDir::isRelativePath(destDir)) {
+ destDir = "${BASEDIR}" + QLatin1Char('/') + destDir;
+ }
+ } else {
+ destDir = "${BASEDIR}";
+#if defined(Q_OS_WIN)
+ if (!reader->contains("DESTDIR"))
+ destDir += QLatin1Char('/') + "${QMAKE_BUILDCONFIG}";
+#endif
+ }
+
+#if defined (Q_OS_MAC)
+ if (!reader->values("-CONFIG").contains("app_bundle")) {
+ destDir += QLatin1Char('/')
+ + "${QMAKE_TARGET}"
+ + QLatin1String(".app/Contents/MacOS");
+ }
+#endif
+ m_workingDir = destDir;
+ m_executable = destDir + QLatin1Char('/') + "${QMAKE_TARGET}";
+
+#if defined (Q_OS_WIN)
+ m_executable += QLatin1String(".exe");
+#endif
+
+ m_targets = reader->values(QLatin1String("TARGET"));
+
+ m_srcDir = QFileInfo(m_proFilePath).path();
+ const QStringList config = reader->values(QLatin1String("CONFIG"));
+ m_runMode = ProjectExplorer::ApplicationRunConfiguration::Gui;
+
+ delete reader;
+}
+
+QString Qt4RunConfiguration::resolveVariables(const QString &buildConfiguration, const QString& in) const
+{
+ detectQtShadowBuild(buildConfiguration);
+
+ QString relSubDir = QFileInfo(project()->file()->fileName()).absoluteDir().relativeFilePath(m_srcDir);
+ QString baseDir = QDir(project()->buildDirectory(buildConfiguration)).absoluteFilePath(relSubDir);
+
+ Core::VariableManager *vm = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->variableManager();
+ if (!vm)
+ return QString();
+ QString dest;
+ bool found = false;
+ vm->insert("QMAKE_BUILDCONFIG", qmakeBuildConfigFromBuildConfiguration(buildConfiguration));
+ vm->insert("BASEDIR", baseDir);
+
+
+ /*
+ TODO This is a hack to detect correct target (there might be different targets in
+ different scopes)
+ */
+
+ // This code also works for workingDirectory,
+ // since directories are executable.
+ foreach (const QString &target, m_targets) {
+ dest = in;
+ vm->insert("QMAKE_TARGET", target);
+ dest = QDir::cleanPath(vm->resolve(dest));
+ vm->remove("QMAKE_TARGET");
+ QFileInfo fi(dest);
+ if (fi.exists() && (fi.isExecutable() || dest.endsWith(".js"))) {
+ found = true;
+ break;
+ }
+ }
+ vm->remove("BASEDIR");
+ vm->remove("QMAKE_BUILDCONFIG");
+ if (found)
+ return dest;
+ else
+ return QString();
+}
+
+/* This function tries to find out wheter qmake/make will put the binary in "/debug/" or in "/release/"
+ That is this function is strictly only for windows.
+ We look wheter make gets an explicit parameter "debug" or "release"
+ That works because if we have either debug or release there then it is surely a
+ debug_and_release buildconfiguration and thus we are put in a subdirectory.
+
+ Now if there is no explicit debug or release parameter, then we need to look at what qmake's CONFIG
+ value is, if it is not debug_and_release, we don't care and return ""
+ otherwise we look at wheter the default is debug or not
+
+ Note: When fixing this function consider those cases
+ qmake CONFIG+=debug_and_release CONFIG+=debug
+ make release
+ => we should return release
+
+ qmake CONFIG+=debug_and_release CONFIG+=debug
+ make
+ => we should return debug
+
+ qmake CONFIG-=debug_and_release CONFIG+=debug
+ make
+ => we should return "", since the executable is not put in a subdirectory
+
+ Not a function to be proud of
+*/
+QString Qt4RunConfiguration::qmakeBuildConfigFromBuildConfiguration(const QString &buildConfigurationName) const
+{
+ MakeStep *ms = qobject_cast<Qt4Project *>(project())->makeStep();
+ QStringList makeargs = ms->value(buildConfigurationName, "makeargs").toStringList();
+ if (makeargs.contains("debug"))
+ return "debug";
+ else if(makeargs.contains("release"))
+ return "release";
+
+ // Oh we don't have an explicit make argument
+ QMakeStep *qs = qobject_cast<Qt4Project *>(project())->qmakeStep();
+ QVariant qmakeBuildConfiguration = qs->value(buildConfigurationName, "buildConfiguration");
+ if (qmakeBuildConfiguration.isValid()) {
+ QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(qmakeBuildConfiguration.toInt());
+ if (projectBuildConfiguration & QtVersion::BuildAll) {
+ if (projectBuildConfiguration & QtVersion::DebugBuild)
+ return "debug";
+ else
+ return "release";
+ } else {
+ return "";
+ }
+ } else {
+ // Old sytle always CONFIG+=debug_and_release
+ if (qobject_cast<Qt4Project *>(project())->qtVersion(buildConfigurationName)->defaultBuildConfig() & QtVersion::DebugBuild)
+ return "debug";
+ else
+ return "release";
+ }
+
+ // enable us to infer the right string
+ return "";
+}
+
+/*!
+ Handle special case were a subproject of the qt directory is opened, and
+ qt was configured to be built as a shadow build -> also build in the sub-
+ project in the correct shadow build directory.
+ */
+void Qt4RunConfiguration::detectQtShadowBuild(const QString &buildConfiguration) const
+{
+ if (project()->activeBuildConfiguration() == buildConfiguration)
+ return;
+
+ const QString currentQtDir = static_cast<Qt4Project *>(project())->qtDir(buildConfiguration);
+ const QString qtSourceDir = static_cast<Qt4Project *>(project())->qtVersion(buildConfiguration)->sourcePath();
+
+ // if the project is a sub-project of Qt and Qt was shadow-built then automatically
+ // adjust the build directory of the sub-project.
+ if (project()->file()->fileName().startsWith(qtSourceDir) && qtSourceDir != currentQtDir) {
+ project()->setValue(buildConfiguration, "useShadowBuild", true);
+ QString buildDir = QFileInfo(project()->file()->fileName()).absolutePath();
+ buildDir.replace(qtSourceDir, currentQtDir);
+ project()->setValue(buildConfiguration, "buildDirectory", buildDir);
+ project()->setValue(buildConfiguration, "autoShadowBuild", true);
+ }
+}
+
+
+///
+/// Qt4RunConfigurationFactory
+/// This class is used to restore run settings (saved in .user files)
+///
+
+Qt4RunConfigurationFactory::Qt4RunConfigurationFactory()
+{
+}
+
+Qt4RunConfigurationFactory::~Qt4RunConfigurationFactory()
+{
+}
+
+// used to recreate the runConfigurations when restoring settings
+bool Qt4RunConfigurationFactory::canCreate(const QString &type) const
+{
+ return type == "Qt4ProjectManager.Qt4RunConfiguration";
+}
+
+QSharedPointer<ProjectExplorer::RunConfiguration> Qt4RunConfigurationFactory::create(ProjectExplorer::Project *project, const QString &type)
+{
+ Qt4Project *p = qobject_cast<Qt4Project *>(project);
+ Q_ASSERT(p);
+ Q_ASSERT(type == "Qt4ProjectManager.Qt4RunConfiguration");
+ // The right path is set in restoreSettings
+ QSharedPointer<ProjectExplorer::RunConfiguration> rc(new Qt4RunConfiguration(p, QString::null));
+ return rc;
+}
+
+QStringList Qt4RunConfigurationFactory::canCreate(ProjectExplorer::Project *pro) const
+{
+ Qt4Project *qt4project = qobject_cast<Qt4Project *>(pro);
+ if (qt4project)
+ return QStringList();
+ else
+ return QStringList();
+}
+
+QString Qt4RunConfigurationFactory::nameForType(const QString &type) const
+{
+ Q_UNUSED(type);
+ return "Run Qt4 application";
+}
+
+///
+/// Qt4RunConfigurationFactoryUser
+/// This class is used to create new RunConfiguration from the runsettings page
+///
+
+Qt4RunConfigurationFactoryUser::Qt4RunConfigurationFactoryUser()
+{
+}
+
+Qt4RunConfigurationFactoryUser::~Qt4RunConfigurationFactoryUser()
+{
+}
+
+bool Qt4RunConfigurationFactoryUser::canCreate(const QString &type) const
+{
+ Q_UNUSED(type);
+ return false;
+}
+
+QSharedPointer<ProjectExplorer::RunConfiguration> Qt4RunConfigurationFactoryUser::create(ProjectExplorer::Project *project, const QString &type)
+{
+ Qt4Project *p = qobject_cast<Qt4Project *>(project);
+ Q_ASSERT(p);
+
+ QString fileName = type.mid(QString("Qt4RunConfiguration.").size());
+ return QSharedPointer<ProjectExplorer::RunConfiguration>(new Qt4RunConfiguration(p, fileName));
+}
+
+QStringList Qt4RunConfigurationFactoryUser::canCreate(ProjectExplorer::Project *pro) const
+{
+ Qt4Project *qt4project = qobject_cast<Qt4Project *>(pro);
+ if (qt4project) {
+ QStringList applicationProFiles;
+ QList<Qt4ProFileNode *> list = qt4project->applicationProFiles();
+ foreach(Qt4ProFileNode * node, list) {
+ applicationProFiles.append("Qt4RunConfiguration." + node->path());
+ }
+ return applicationProFiles;
+ } else {
+ return QStringList();
+ }
+}
+
+QString Qt4RunConfigurationFactoryUser::nameForType(const QString &type) const
+{
+ QString fileName = type.mid(QString("Qt4RunConfiguration.").size());
+ return QFileInfo(fileName).baseName();
+}
diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.h b/src/plugins/qt4projectmanager/qt4runconfiguration.h
new file mode 100644
index 0000000000..6262082858
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt4runconfiguration.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QT4RUNCONFIGURATION_H
+#define QT4RUNCONFIGURATION_H
+
+#include <projectexplorer/applicationrunconfiguration.h>
+#include <QtCore/QStringList>
+
+namespace Qt4ProjectManager {
+
+class Qt4Project;
+
+namespace Internal {
+
+class Qt4ProFileNode;
+
+class Qt4RunConfiguration : public ProjectExplorer::ApplicationRunConfiguration
+{
+ Q_OBJECT
+public:
+ Qt4RunConfiguration(Qt4Project *pro, QString proFilePath);
+ virtual ~Qt4RunConfiguration();
+
+ virtual QString type() const;
+ virtual QWidget *configurationWidget();
+ virtual void save(ProjectExplorer::PersistentSettingsWriter &writer) const;
+ virtual void restore(const ProjectExplorer::PersistentSettingsReader &reader);
+
+ virtual QString executable() const;
+ virtual RunMode runMode() const;
+ virtual QString workingDirectory() const;
+ virtual QStringList commandLineArguments() const;
+ virtual ProjectExplorer::Environment environment() const;
+
+ QString proFilePath() const;
+
+ // Should just be called from qt4project, since that knows that the file changed on disc
+ void updateCachedValues();
+
+private slots:
+ void setCommandLineArguments(const QString &argumentsString);
+ void nameEdited(const QString&);
+
+private:
+ void detectQtShadowBuild(const QString &buildConfig) const;
+ QString resolveVariables(const QString &buildConfiguration, const QString& in) const;
+ QString qmakeBuildConfigFromBuildConfiguration(const QString &buildConfigurationName) const;
+
+ QStringList m_commandLineArguments;
+ Qt4ProFileNode *m_proFileNode;
+ QString m_proFilePath; // Full path to the Application Pro File
+
+ // Cached startup sub project information
+ QStringList m_targets;
+ QString m_executable;
+ QString m_srcDir;
+ QString m_workingDir;
+ ProjectExplorer::ApplicationRunConfiguration::RunMode m_runMode;
+ bool m_userSetName;
+};
+
+class Qt4RunConfigurationFactory : public ProjectExplorer::IRunConfigurationFactory
+{
+ Q_OBJECT
+public:
+ Qt4RunConfigurationFactory();
+ virtual ~Qt4RunConfigurationFactory();
+ virtual bool canCreate(const QString &type) const;
+ virtual QSharedPointer<ProjectExplorer::RunConfiguration> create(ProjectExplorer::Project *project, const QString &type);
+ QStringList canCreate(ProjectExplorer::Project *pro) const;
+ QString nameForType(const QString &type) const;
+};
+
+class Qt4RunConfigurationFactoryUser : public ProjectExplorer::IRunConfigurationFactory
+{
+ Q_OBJECT
+public:
+ Qt4RunConfigurationFactoryUser();
+ virtual ~Qt4RunConfigurationFactoryUser();
+ virtual bool canCreate(const QString &type) const;
+ virtual QSharedPointer<ProjectExplorer::RunConfiguration> create(ProjectExplorer::Project *project, const QString &type);
+ QStringList canCreate(ProjectExplorer::Project *pro) const;
+ QString nameForType(const QString &type) const;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // QT4RUNCONFIGURATION_H
diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp
new file mode 100644
index 0000000000..a1afa6c65b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp
@@ -0,0 +1,1278 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtversionmanager.h"
+#include "qt4projectmanagerconstants.h"
+#include "msvcenvironment.h"
+#include "cesdkhandler.h"
+
+#include <coreplugin/coreconstants.h>
+#include <help/helpplugin.h>
+
+#include <QtCore/QSettings>
+#include <QtCore/QStringRef>
+#include <QtCore/QTime>
+#include <QtCore/QProcess>
+#include <QtGui/QHeaderView>
+#include <QtGui/QFileDialog>
+#include <QtCore/QDebug>
+#include <QtGui/QMessageBox>
+
+using namespace Qt4ProjectManager::Internal;
+
+using ProjectExplorer::Environment;
+
+static const char *QtVersionsSectionName = "QtVersions";
+static const char *defaultQtVersionKey = "DefaultQtVersion";
+static const char *newQtVersionsKey = "NewQtVersions";
+
+QtVersionManager::QtVersionManager()
+ : m_emptyVersion(new QtVersion)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ QSettings *s = m_core->settings();
+ m_defaultVersion = s->value(defaultQtVersionKey, 0).toInt();
+
+ m_idcount = 1;
+ int size = s->beginReadArray(QtVersionsSectionName);
+ for (int i = 0; i < size; ++i) {
+ s->setArrayIndex(i);
+ // Find the right id
+ // Either something saved or something generated
+ // Note: This code assumes that either all ids are read from the settings
+ // or generated on the fly.
+ int id = s->value("Id", -1).toInt();
+ if (id == -1)
+ id = getUniqueId();
+ else if (id > m_idcount)
+ m_idcount = id;
+ QtVersion *version = new QtVersion(s->value("Name").toString(),
+ s->value("Path").toString(),
+ id,
+ s->value("IsSystemVersion", false).toBool());
+ version->setMingwDirectory(s->value("MingwDirectory").toString());
+ version->setPrependPath(s->value("PrependPath").toString());
+ version->setMsvcVersion(s->value("msvcVersion").toString());
+ m_versions.append(version);
+ }
+ s->endArray();
+ updateUniqueIdToIndexMap();
+
+ ++m_idcount;
+ addNewVersionsFromInstaller();
+ updateSystemVersion();
+
+ writeVersionsIntoSettings();
+ updateDocumentation();
+}
+
+QtVersionManager::~QtVersionManager()
+{
+ qDeleteAll(m_versions);
+ m_versions.clear();
+ delete m_emptyVersion;
+ m_emptyVersion = 0;
+}
+
+void QtVersionManager::addVersion(QtVersion *version)
+{
+ m_versions.append(version);
+ emit qtVersionsChanged();
+}
+
+void QtVersionManager::updateDocumentation()
+{
+ Help::HelpManager *helpManager = m_core->pluginManager()->getObject<Help::HelpManager>();
+ Q_ASSERT(helpManager);
+ if (!helpManager)
+ return;
+ QStringList fileEndings = QStringList() << "/qch/qt.qch" << "/qch/qmake.qch" << "/qch/designer.qch";
+ QStringList files;
+ foreach (QtVersion *version, m_versions) {
+ QString docPath = version->versionInfo().value("QT_INSTALL_DOCS");
+ foreach (const QString &fileEnding, fileEndings)
+ files << docPath+fileEnding;
+ }
+ helpManager->registerDocumentation(files);
+}
+
+int QtVersionManager::getUniqueId()
+{
+ return m_idcount++;
+}
+
+QString QtVersionManager::name() const
+{
+ return tr(Constants::QTVERSION_PAGE);
+}
+
+QString QtVersionManager::category() const
+{
+ return Constants::QT_CATEGORY;
+}
+
+QString QtVersionManager::trCategory() const
+{
+ return tr(Constants::QT_CATEGORY);
+}
+
+QWidget *QtVersionManager::createPage(QWidget *parent)
+{
+ if (m_widget)
+ delete m_widget;
+ m_widget = new QtDirWidget(parent, m_versions, m_defaultVersion);
+ return m_widget;
+}
+
+void QtVersionManager::updateUniqueIdToIndexMap()
+{
+ m_uniqueIdToIndex.clear();
+ for(int i=0; i<m_versions.size(); ++i)
+ m_uniqueIdToIndex.insert(m_versions.at(i)->uniqueId(), i);
+}
+
+void QtVersionManager::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_widget->finish();
+ QList<QtVersion*> newVersions = m_widget->versions();
+ bool versionPathsChanged = m_versions.size() != newVersions.size();
+ if (!versionPathsChanged) {
+ for (int i = 0; i < m_versions.size(); ++i) {
+ if (m_versions.at(i)->path() != newVersions.at(i)->path()) {
+ versionPathsChanged = true;
+ break;
+ }
+ }
+ }
+ m_versions = m_widget->versions();
+ if (versionPathsChanged)
+ updateDocumentation();
+ updateUniqueIdToIndexMap();
+
+ bool emitDefaultChanged = false;
+ if (m_defaultVersion != m_widget->defaultVersion()) {
+ m_defaultVersion = m_widget->defaultVersion();
+ emitDefaultChanged = true;
+ }
+
+ emit qtVersionsChanged();
+ if (emitDefaultChanged)
+ emit defaultQtVersionChanged();
+
+ writeVersionsIntoSettings();
+}
+
+void QtVersionManager::writeVersionsIntoSettings()
+{
+ QSettings *s = m_core->settings();
+ s->setValue(defaultQtVersionKey, m_defaultVersion);
+ s->beginWriteArray("QtVersions");
+ for (int i = 0; i < m_versions.size(); ++i) {
+ s->setArrayIndex(i);
+ s->setValue("Name", m_versions.at(i)->name());
+ s->setValue("Path", m_versions.at(i)->path());
+ s->setValue("Id", m_versions.at(i)->uniqueId());
+ s->setValue("MingwDirectory", m_versions.at(i)->mingwDirectory());
+ s->setValue("PrependPath", m_versions.at(i)->prependPath());
+ s->setValue("msvcVersion", m_versions.at(i)->msvcVersion());
+ s->setValue("IsSystemVersion", m_versions.at(i)->isSystemVersion());
+ }
+ s->endArray();
+}
+
+QList<QtVersion* > QtVersionManager::versions() const
+{
+ return m_versions;
+}
+
+QtVersion *QtVersionManager::version(int id) const
+{
+ int pos = m_uniqueIdToIndex.value(id, -1);
+ if (pos != -1)
+ return m_versions.at(pos);
+
+ if(m_defaultVersion < m_versions.count())
+ return m_versions.at(m_defaultVersion);
+ else
+ return m_emptyVersion;
+}
+
+void QtVersionManager::addNewVersionsFromInstaller()
+{
+ // Add new versions which may have been installed by the WB installer in the form:
+ // NewQtVersions="qt 4.3.2=c:\\qt\\qt432;qt embedded=c:\\qtembedded;"
+ // or NewQtVersions="qt 4.3.2=c:\\qt\\qt432=c:\\qtcreator\\mingw\\=prependToPath;
+ // Duplicate entries are not added, the first new version is set as default.
+ QSettings *settings = m_core->settings();
+ if (!settings->contains(newQtVersionsKey))
+ return;
+
+// qDebug()<<"QtVersionManager::addNewVersionsFromInstaller()";
+
+ QString newVersionsValue = settings->value(newQtVersionsKey).toString();
+ QStringList newVersionsList = newVersionsValue.split(';', QString::SkipEmptyParts);
+ bool defaultVersionWasReset = false;
+ foreach (QString newVersion, newVersionsList) {
+ QStringList newVersionData = newVersion.split('=');
+ if(newVersionData.count()>=2) {
+ if (QDir(newVersionData[1]).exists()) {
+ QtVersion *version = new QtVersion(newVersionData[0], newVersionData[1], m_idcount++ );
+ if(newVersionData.count() >= 3)
+ version->setMingwDirectory(newVersionData[2]);
+ if(newVersionData.count() >= 4)
+ version->setPrependPath(newVersionData[3]);
+
+ bool versionWasAlreadyInList = false;
+ foreach(const QtVersion * const it, m_versions) {
+ if(QDir(version->path()).canonicalPath() == QDir(it->path()).canonicalPath()) {
+ versionWasAlreadyInList = true;
+ break;
+ }
+ }
+
+ if (!versionWasAlreadyInList) {
+ m_versions.append(version);
+ } else {
+ // clean up
+ delete version;
+ }
+ if (!defaultVersionWasReset) {
+ m_defaultVersion = versionWasAlreadyInList? m_defaultVersion : m_versions.count() - 1;
+ defaultVersionWasReset = true;
+ }
+ }
+ }
+ }
+ settings->remove(newQtVersionsKey);
+ updateUniqueIdToIndexMap();
+}
+
+void QtVersionManager::updateSystemVersion()
+{
+ bool haveSystemVersion = false;
+ foreach (QtVersion *version, m_versions) {
+ if (version->isSystemVersion()) {
+ version->setPath(findSystemQt());
+ haveSystemVersion = true;
+ }
+ }
+ if (haveSystemVersion)
+ return;
+ QtVersion *version = new QtVersion(tr("System Qt"),
+ findSystemQt(),
+ getUniqueId(),
+ true);
+ m_versions.prepend(version);
+ updateUniqueIdToIndexMap();
+ if (m_versions.size() > 1) // we had other versions before adding system version
+ ++m_defaultVersion;
+}
+
+QStringList QtVersionManager::possibleQMakeCommands()
+{
+ // On windows noone has renamed qmake, right?
+#ifdef Q_OS_WIN
+ return QStringList() << "qmake.exe";
+#endif
+ // On unix some distributions renamed qmake to avoid clashes
+ QStringList result;
+ result << "qmake-qt4" << "qmake4" << "qmake";
+ return result;
+}
+
+bool QtVersionManager::checkQMakeVersion(const QString &qmakePath)
+{
+ QProcess qmake;
+ qmake.start(qmakePath, QStringList()<<"--version");
+ if (!qmake.waitForFinished())
+ return false;
+ QString output = qmake.readAllStandardOutput();
+ QRegExp regexp("(QMake version|Qmake version:)[\\s]*([\\d.]*)");
+ regexp.indexIn(output);
+ if (regexp.cap(2).startsWith("2."))
+ return true;
+ return false;
+}
+
+QString QtVersionManager::findSystemQt() const
+{
+ Environment env = Environment::systemEnvironment();
+ QStringList paths = env.path();
+ foreach (const QString &path, paths) {
+ foreach (const QString &possibleCommand, possibleQMakeCommands()) {
+ QFileInfo qmake(path + "/" + possibleCommand);
+ if (qmake.exists()) {
+ if (checkQMakeVersion(qmake.absoluteFilePath())) {
+ QDir dir(qmake.absoluteDir());
+ dir.cdUp();
+ return dir.absolutePath();
+ }
+ }
+ }
+ }
+ return tr("<not found>");
+}
+
+QtVersion *QtVersionManager::currentQtVersion() const
+{
+ if(m_defaultVersion < m_versions.count())
+ return m_versions.at(m_defaultVersion);
+ else
+ return m_emptyVersion;
+}
+
+//-----------------------------------------------------
+
+QtDirWidget::QtDirWidget(QWidget *parent, QList<QtVersion *> versions, int defaultVersion)
+ : QWidget(parent)
+ , m_versions(versions)
+ , m_defaultVersion(defaultVersion)
+ , m_specifyNameString(tr("<specify a name>"))
+ , m_specifyPathString(tr("<specify a path>"))
+{
+ m_ui.setupUi(this);
+
+ m_ui.addButton->setIcon(QIcon(Core::Constants::ICON_PLUS));
+ m_ui.delButton->setIcon(QIcon(Core::Constants::ICON_MINUS));
+
+ for (int i = 0; i < m_versions.count(); ++i) {
+ const QtVersion * const version = m_versions.at(i);
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.qtdirList);
+ item->setText(0, version->name());
+ item->setText(1, version->path());
+ item->setData(0, Qt::UserRole, version->uniqueId());
+ m_ui.defaultCombo->addItem(version->name());
+ if (i == m_defaultVersion)
+ m_ui.defaultCombo->setCurrentIndex(i);
+ }
+
+ connect(m_ui.nameEdit, SIGNAL(textEdited(const QString &)),
+ this, SLOT(updateCurrentQtName()));
+ connect(m_ui.pathEdit, SIGNAL(textEdited(const QString &)),
+ this, SLOT(updateCurrentQtPath()));
+ connect(m_ui.mingwLineEdit, SIGNAL(textEdited(const QString &)),
+ this, SLOT(updateCurrentMingwDirectory()));
+
+ connect(m_ui.addButton, SIGNAL(clicked()),
+ this, SLOT(addQtDir()));
+ connect(m_ui.delButton, SIGNAL(clicked()),
+ this, SLOT(removeQtDir()));
+ connect(m_ui.browseButton, SIGNAL(clicked()),
+ this, SLOT(browse()));
+ connect(m_ui.mingwBrowseButton, SIGNAL(clicked()),
+ this, SLOT(mingwBrowse()));
+
+ connect(m_ui.qtdirList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(versionChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+ connect(m_ui.defaultCombo, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(defaultChanged(int)));
+
+ connect(m_ui.msvcComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(msvcVersionChanged()));
+
+ showEnvironmentPage(0);
+ updateState();
+}
+
+void QtDirWidget::addQtDir()
+{
+ QtVersion *newVersion = new QtVersion(m_specifyNameString, m_specifyPathString);
+ m_versions.append(newVersion);
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.qtdirList);
+ item->setText(0, newVersion->name());
+ item->setText(1, newVersion->path());
+ item->setData(0, Qt::UserRole, newVersion->uniqueId());
+
+ m_ui.nameEdit->setText(newVersion->name());
+ m_ui.pathEdit->setText(newVersion->path());
+
+ m_ui.defaultCombo->addItem(newVersion->name());
+ m_ui.qtdirList->setCurrentItem(item);
+ m_ui.nameEdit->setFocus();
+ m_ui.nameEdit->selectAll();
+}
+
+void QtDirWidget::removeQtDir()
+{
+ QTreeWidgetItem *item = m_ui.qtdirList->currentItem();
+
+
+ int index = m_ui.qtdirList->indexOfTopLevelItem(item);
+ if (index < 0)
+ return;
+
+ for (int i = 0; i < m_ui.defaultCombo->count(); ++i) {
+ if (m_ui.defaultCombo->itemText(i) == item->text(0)) {
+ m_ui.defaultCombo->removeItem(i);
+ break;
+ }
+ }
+
+ delete item;
+
+ delete m_versions.takeAt(index);
+ updateState();
+}
+
+void QtDirWidget::updateState()
+{
+ bool enabled = (m_ui.qtdirList->currentItem() != 0);
+ bool isSystemVersion = (enabled
+ && m_versions.at(m_ui.qtdirList->indexOfTopLevelItem(m_ui.qtdirList->currentItem()))->isSystemVersion());
+ m_ui.delButton->setEnabled(enabled && !isSystemVersion);
+ m_ui.nameEdit->setEnabled(enabled && !isSystemVersion);
+ m_ui.pathEdit->setEnabled(enabled && !isSystemVersion);
+ m_ui.browseButton->setEnabled(enabled && !isSystemVersion);
+ m_ui.mingwBrowseButton->setEnabled(enabled);
+ m_ui.mingwLineEdit->setEnabled(enabled);
+}
+
+void QtDirWidget::showEnvironmentPage(QTreeWidgetItem *item)
+{
+ m_ui.msvcComboBox->setVisible(false);
+ if(item) {
+ int index = m_ui.qtdirList->indexOfTopLevelItem(item);
+ m_ui.errorLabel->setText("");
+ QtVersion::ToolchainType t = m_versions.at(index)->toolchainType();
+ if(t == QtVersion::MinGW) {
+ m_ui.msvcComboBox->setVisible(false);
+ m_ui.msvcLabel->setVisible(false);
+ m_ui.mingwLineEdit->setVisible(true);
+ m_ui.mingwLabel->setVisible(true);
+ m_ui.mingwBrowseButton->setVisible(true);
+ m_ui.mingwLineEdit->setText(m_versions.at(index)->mingwDirectory());
+ } else if(t == QtVersion::MSVC || t == QtVersion::WINCE){
+ m_ui.msvcComboBox->setVisible(false);
+ m_ui.msvcLabel->setVisible(true);
+ m_ui.mingwLineEdit->setVisible(false);
+ m_ui.mingwLabel->setVisible(false);
+ m_ui.mingwBrowseButton->setVisible(false);
+ QList<MSVCEnvironment> msvcenvironments = MSVCEnvironment::availableVersions();
+ if(msvcenvironments.count() == 0) {
+ m_ui.msvcLabel->setText(tr("No Visual Studio Installation found"));
+ } else if(msvcenvironments.count() == 1) {
+ m_ui.msvcLabel->setText( msvcenvironments.at(0).description());
+ } else {
+ m_ui.msvcComboBox->setVisible(true);
+ m_ui.msvcComboBox->clear();
+ bool block = m_ui.msvcComboBox->blockSignals(true);
+ foreach(const MSVCEnvironment msvcenv, msvcenvironments) {
+ m_ui.msvcComboBox->addItem(msvcenv.name());
+ if (msvcenv.name() == m_versions.at(index)->msvcVersion()) {
+ m_ui.msvcComboBox->setCurrentIndex(m_ui.msvcComboBox->count() - 1);
+ m_ui.msvcLabel->setText(msvcenv.description());
+ }
+ }
+ m_ui.msvcComboBox->blockSignals(block);
+ }
+ } else if(t == QtVersion::INVALID) {
+ m_ui.msvcComboBox->setVisible(false);
+ m_ui.msvcLabel->setVisible(false);
+ m_ui.mingwLineEdit->setVisible(false);
+ m_ui.mingwLabel->setVisible(false);
+ m_ui.mingwBrowseButton->setVisible(false);
+ if (!m_versions.at(index)->isInstalled())
+ m_ui.errorLabel->setText(tr("The Qt Version is not installed. Run make install")
+ .arg(m_versions.at(index)->path()));
+ else
+ m_ui.errorLabel->setText(tr("%1 is not a valid qt directory").arg(m_versions.at(index)->path()));
+ } else { //QtVersion::Other
+ m_ui.msvcComboBox->setVisible(false);
+ m_ui.msvcLabel->setVisible(false);
+ m_ui.mingwLineEdit->setVisible(false);
+ m_ui.mingwLabel->setVisible(false);
+ m_ui.mingwBrowseButton->setVisible(false);
+ m_ui.errorLabel->setText("Found qt version: " + m_versions.at(index)->mkspec());
+ }
+ } else {
+ m_ui.msvcComboBox->setVisible(false);
+ m_ui.msvcLabel->setVisible(false);
+ m_ui.mingwLineEdit->setVisible(false);
+ m_ui.mingwLabel->setVisible(false);
+ m_ui.mingwBrowseButton->setVisible(false);
+ }
+}
+
+void QtDirWidget::versionChanged(QTreeWidgetItem *item, QTreeWidgetItem *old)
+{
+ if(old) {
+ fixQtVersionName(m_ui.qtdirList->indexOfTopLevelItem(old));
+ }
+ if (item) {
+ m_ui.nameEdit->setText(item->text(0));
+ m_ui.pathEdit->setText(item->text(1));
+ } else {
+ m_ui.nameEdit->clear();
+ m_ui.pathEdit->clear();
+ }
+ showEnvironmentPage(item);
+ updateState();
+}
+
+void QtDirWidget::browse()
+{
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Select QTDIR"));
+
+ if (dir.isEmpty())
+ return;
+
+ dir = QDir::toNativeSeparators(dir);
+ m_ui.pathEdit->setText(dir);
+ updateCurrentQtPath();
+ if (m_ui.nameEdit->text().isEmpty() || m_ui.nameEdit->text() == m_specifyNameString) {
+ QStringList dirSegments = dir.split(QDir::separator(), QString::SkipEmptyParts);
+ if (!dirSegments.isEmpty())
+ m_ui.nameEdit->setText(dirSegments.last());
+ updateCurrentQtName();
+ }
+ updateState();
+}
+
+void QtDirWidget::mingwBrowse()
+{
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Select MinGW Directory"));
+ if (dir.isEmpty())
+ return;
+
+ dir = QDir::toNativeSeparators(dir);
+ m_ui.mingwLineEdit->setText(dir);
+ updateCurrentMingwDirectory();
+ updateState();
+}
+
+void QtDirWidget::defaultChanged(int)
+{
+ for (int i=0; i<m_ui.defaultCombo->count(); ++i) {
+ if (m_versions.at(i)->name() == m_ui.defaultCombo->currentText()) {
+ m_defaultVersion = i;
+ return;
+ }
+ }
+
+ m_defaultVersion = 0;
+}
+
+void QtDirWidget::updateCurrentQtName()
+{
+ QTreeWidgetItem *currentItem = m_ui.qtdirList->currentItem();
+ Q_ASSERT(currentItem);
+ int currentItemIndex = m_ui.qtdirList->indexOfTopLevelItem(currentItem);
+ m_versions[currentItemIndex]->setName(m_ui.nameEdit->text());
+ currentItem->setText(0, m_versions[currentItemIndex]->name());
+
+ m_ui.defaultCombo->setItemText(currentItemIndex, m_versions[currentItemIndex]->name());
+}
+
+
+void QtDirWidget::finish()
+{
+ if(QTreeWidgetItem *item = m_ui.qtdirList->currentItem())
+ fixQtVersionName(m_ui.qtdirList->indexOfTopLevelItem(item));
+}
+
+/* Checks that the qt version name is unique
+ * and otherwise changes the name
+ *
+ */
+void QtDirWidget::fixQtVersionName(int index)
+{
+ int count = m_versions.count();
+ for(int i=0; i<count; ++i) {
+ if(i != index) {
+ if(m_versions.at(i)->name() == m_versions.at(index)->name()) {
+ // Same name, find new name
+ QString name = m_versions.at(index)->name();
+ QRegExp regexp("^(.*)\\((\\d)\\)$");
+ if (regexp.exactMatch(name)) {
+ // Alreay in Name (#) format
+ name = regexp.cap(1) + "(" + QString().setNum(regexp.cap(2).toInt() + 1) + ")";
+ } else {
+ name = name + " (2)";
+ }
+ // set new name
+ m_versions[index]->setName(name);
+ m_ui.qtdirList->topLevelItem(index)->setText(0, name);
+ m_ui.defaultCombo->setItemText(index, name);
+
+ // Now check again...
+ fixQtVersionName(index);
+ }
+ }
+ }
+}
+
+void QtDirWidget::updateCurrentQtPath()
+{
+ QTreeWidgetItem *currentItem = m_ui.qtdirList->currentItem();
+ Q_ASSERT(currentItem);
+ int currentItemIndex = m_ui.qtdirList->indexOfTopLevelItem(currentItem);
+ m_versions[currentItemIndex]->setPath(m_ui.pathEdit->text());
+ currentItem->setText(1, m_versions[currentItemIndex]->path());
+
+ showEnvironmentPage(currentItem);
+}
+
+void QtDirWidget::updateCurrentMingwDirectory()
+{
+ QTreeWidgetItem *currentItem = m_ui.qtdirList->currentItem();
+ Q_ASSERT(currentItem);
+ int currentItemIndex = m_ui.qtdirList->indexOfTopLevelItem(currentItem);
+ m_versions[currentItemIndex]->setMingwDirectory(m_ui.mingwLineEdit->text());
+}
+
+void QtDirWidget::msvcVersionChanged()
+{
+ const QString &msvcVersion = m_ui.msvcComboBox->currentText();
+ QTreeWidgetItem *currentItem = m_ui.qtdirList->currentItem();
+ Q_ASSERT(currentItem);
+ int currentItemIndex = m_ui.qtdirList->indexOfTopLevelItem(currentItem);
+ m_versions[currentItemIndex]->setMsvcVersion(msvcVersion);
+
+ //get descriptionx
+ QList<MSVCEnvironment> msvcEnvironments = MSVCEnvironment::availableVersions();
+ foreach(const MSVCEnvironment &msvcEnv, msvcEnvironments) {
+ if(msvcEnv.name() == msvcVersion) {
+ m_ui.msvcLabel->setText(msvcEnv.description());
+ break;
+ }
+ }
+}
+
+QList<QtVersion *> QtDirWidget::versions() const
+{
+ return m_versions;
+}
+
+int QtDirWidget::defaultVersion() const
+{
+ return m_defaultVersion;
+}
+
+///
+/// QtVersion
+///
+
+QtVersion::QtVersion(const QString &name, const QString &path, int id, bool isSystemVersion)
+ : m_name(name), m_isSystemVersion(isSystemVersion), m_notInstalled(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true)
+{
+ setPath(path);
+ if(id == -1)
+ m_id = getUniqueId();
+ else
+ m_id = id;
+}
+
+QtVersion::QtVersion(const QString &name, const QString &path)
+ : m_name(name),
+ m_versionInfoUpToDate(false),
+ m_mkspecUpToDate(false),
+ m_isSystemVersion(false)
+{
+ setPath(path);
+ m_id = getUniqueId();
+}
+
+QString QtVersion::name() const
+{
+ return m_name;
+}
+
+QString QtVersion::path() const
+{
+ return m_path;
+}
+
+QString QtVersion::sourcePath() const
+{
+ return m_sourcePath;
+}
+
+QString QtVersion::mkspec() const
+{
+ updateMkSpec();
+ return m_mkspec;
+}
+
+QHash<QString,QString> QtVersion::versionInfo() const
+{
+ updateVersionInfo();
+ return m_versionInfo;
+}
+
+void QtVersion::setName(const QString &name)
+{
+ m_name = name;
+}
+
+void QtVersion::setPath(const QString &path)
+{
+ m_path = QDir::cleanPath(path);
+ updateSourcePath();
+ m_versionInfoUpToDate = false;
+ m_mkspecUpToDate = false;
+ m_qmakeCommand = QString::null;
+}
+
+void QtVersion::updateSourcePath()
+{
+ m_sourcePath = m_path;
+ QFile qmakeCache(m_path + QLatin1String("/.qmake.cache"));
+ if (qmakeCache.exists()) {
+ qmakeCache.open(QIODevice::ReadOnly | QIODevice::Text);
+ QTextStream stream(&qmakeCache);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ if (line.startsWith(QLatin1String("QT_SOURCE_TREE"))) {
+ m_sourcePath = line.split(QLatin1Char('=')).at(1).trimmed();
+ if (m_sourcePath.startsWith(QLatin1String("$$quote("))) {
+ m_sourcePath.remove(0, 8);
+ m_sourcePath.chop(1);
+ }
+ break;
+ }
+ }
+ }
+}
+
+// Returns the version that was used to build the project in that directory
+// That is returns the directory
+// To find out wheter we already have a qtversion for that directory call
+// QtVersion *QtVersionManager::qtVersionForDirectory(const QString directory);
+QString QtVersionManager::findQtVersionFromMakefile(const QString &directory)
+{
+ QString result = QString::null;
+ bool debugAdding = false;
+ QFile makefile(directory + "/Makefile" );
+ if (makefile.exists() && makefile.open(QFile::ReadOnly)) {
+ QTextStream ts(&makefile);
+ while (!ts.atEnd()) {
+ QString line = ts.readLine();
+ QRegExp r1("QMAKE\\s*=(.*)");
+ if (r1.exactMatch(line)) {
+ if (debugAdding)
+ qDebug()<<"#~~ QMAKE is:"<<r1.cap(1).trimmed();
+ QFileInfo qmake(r1.cap(1).trimmed());
+ QFileInfo binDir(qmake.absolutePath());
+ QString qtDir = binDir.absolutePath();
+ if (debugAdding)
+ qDebug() << "#~~ QtDir:"<<qtDir;
+ // Now we have the qtDir
+ // look through the qtversions wheter we already have that qt version setup
+ return qtDir;
+ }
+ }
+ makefile.close();
+ }
+ return result;
+}
+
+QtVersion *QtVersionManager::qtVersionForDirectory(const QString &directory)
+{
+ foreach(QtVersion *v, versions()) {
+ if (v->path() == directory) {
+ return v;
+ break;
+ }
+ }
+ return 0;
+}
+
+QtVersion::QmakeBuildConfig QtVersionManager::scanMakefileForQmakeConfig(const QString &directory, QtVersion::QmakeBuildConfig defaultBuildConfig)
+{
+ bool debugScan = false;
+ QtVersion::QmakeBuildConfig result = QtVersion::NoBuild;
+ QFile makefile(directory + "/Makefile" );
+ if (makefile.exists() && makefile.open(QFile::ReadOnly)) {
+ QTextStream ts(&makefile);
+ while (!ts.atEnd()) {
+ QString line = ts.readLine();
+ if (line.startsWith("# Command:")) {
+ // if nothing is specified
+ result = defaultBuildConfig;
+
+ // Actually parsing that line is not trivial in the general case
+ // There might things like this
+ // # Command: /home/dteske/git/bqt-45/bin/qmake -unix CONFIG+=debug\ release CONFIG\ +=\ debug_and_release\ debug -o Makefile test.pro
+ // which sets debug_and_release and debug
+ // or something like this:
+ //[...] CONFIG+=debug\ release CONFIG\ +=\ debug_and_release\ debug CONFIG\ -=\ debug_and_release CONFIG\ -=\ debug -o Makefile test.pro
+ // which sets -build_all and release
+
+ // To parse that, we search for the first CONFIG, then look for " " which is not after a "\" or the end
+ // And then look at each config individually
+ // we then remove all "\ " with just " "
+ // += sets adding flags
+ // -= sets removing flags
+ // and then split the string after the =
+ // and go over each item separetly
+ // debug sets/removes the flag DebugBuild
+ // release removes/sets the flag DebugBuild
+ // debug_and_release sets/removes the flag BuildAll
+ int pos = line.indexOf("CONFIG");
+ if (pos != -1) {
+ // Chopped of anything that is not interesting
+ line = line.mid(pos);
+ line = line.trimmed();
+ if (debugScan)
+ qDebug()<<"chopping line :"<<line;
+
+ //Now chop into parts that are intresting
+ QStringList parts;
+ int lastpos = 0;
+ for(int i=1; i<line.size(); ++i) {
+ if (line.at(i) == QLatin1Char(' ') && line.at(i-1) != QLatin1Char('\\')) {
+ // found a part
+ parts.append(line.mid(lastpos, i-lastpos));
+ if (debugScan)
+ qDebug()<<"part appended:"<<line.mid(lastpos, i-lastpos);
+ lastpos = i + 1; // Nex one starts after the space
+ }
+ }
+ parts.append(line.mid(lastpos));
+ if (debugScan)
+ qDebug()<<"part appended:"<<line.mid(lastpos);
+
+ foreach(const QString &part, parts) {
+ if(debugScan)
+ qDebug()<<"now interpreting part"<<part;
+ bool setFlags;
+ // Now try to understand each part for that we do a rather stupid approach, optimize it if you care
+ if (part.startsWith("CONFIG")) {
+ // Yep something interesting
+ if (part.indexOf("+=") != -1) {
+ setFlags = true;
+ } else if (part.indexOf("-=") != -1) {
+ setFlags = false;
+ } else {
+ setFlags = true;
+ if (debugScan)
+ qDebug()<<"This can never happen, except if we can't parse Makefiles...";
+ }
+ if (debugScan)
+ qDebug()<<"part has setFlags:"<<setFlags;
+ // now loop forward, looking for something that looks like debug, release or debug_and_release
+
+ for(int i=0; i<part.size(); ++i) {
+ int left = part.size() - i;
+ if (left >= 17 && QStringRef(&part, i, 17) == "debug_and_release") {
+ if (setFlags)
+ result = QtVersion::QmakeBuildConfig(result | QtVersion::BuildAll);
+ else
+ result = QtVersion::QmakeBuildConfig(result & ~QtVersion::BuildAll);
+ if (debugScan)
+ qDebug()<<"found debug_and_release new value"<<result;
+ i += 17;
+ } else if (left >=7 && QStringRef(&part, i, 7) == "release") {
+ if (setFlags)
+ result = QtVersion::QmakeBuildConfig(result & ~QtVersion::DebugBuild);
+ else
+ result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
+ if (debugScan)
+ qDebug()<<"found release new value"<<result;
+ i +=7;
+ } else if (left >= 5 && QStringRef(&part, i, 5) == "debug") {
+ if (setFlags)
+ result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
+ else
+ result = QtVersion::QmakeBuildConfig(result & ~QtVersion::DebugBuild);
+ if (debugScan)
+ qDebug()<<"found debug new value"<<result;
+ i+=5;
+ }
+ }
+ }
+ }
+ }
+ if (debugScan)
+ qDebug()<<"returning: "<<result;
+ if (debugScan)
+ qDebug()<<"buildall = "<<bool(result & QtVersion::BuildAll);
+ if (debugScan)
+ qDebug()<<"debug ="<<bool(result & QtVersion::DebugBuild);
+ }
+ }
+ makefile.close();
+ }
+ return result;
+}
+
+void QtVersion::updateVersionInfo() const
+{
+ if (m_versionInfoUpToDate)
+ return;
+ // extract data from qmake executable
+ m_versionInfo.clear();
+ m_notInstalled = false;
+ QFileInfo qmake(qmakeCommand());
+ if (qmake.exists()) {
+ QStringList variables = QStringList()
+ << "QT_INSTALL_DATA"
+ << "QT_INSTALL_LIBS"
+ << "QT_INSTALL_HEADERS"
+ << "QT_INSTALL_DEMOS"
+ << "QT_INSTALL_EXAMPLES"
+ << "QT_INSTALL_CONFIGURATION"
+ << "QT_INSTALL_TRANSLATIONS"
+ << "QT_INSTALL_PLUGINS"
+ << "QT_INSTALL_BINS"
+ << "QT_INSTALL_DOCS"
+ << "QT_INSTALL_PREFIX";
+ QStringList args = QStringList() << QString("-query")
+ << variables.join(" -query ").split(" ", QString::SkipEmptyParts);
+ QProcess process;
+ process.start(qmake.absoluteFilePath(), args, QIODevice::ReadOnly);
+ if (process.waitForFinished(2000)) {
+ QByteArray output = process.readAllStandardOutput();
+ QTextStream stream(&output);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine();
+ int index = line.indexOf(":");
+ if (index != -1)
+ m_versionInfo.insert(line.left(index), line.mid(index+1));
+ }
+ }
+
+ if (m_versionInfo.contains("QT_INSTALL_DATA"))
+ m_versionInfo.insert("QMAKE_MKSPECS", QDir::cleanPath(m_versionInfo.value("QT_INSTALL_DATA")+"/mkspecs"));
+
+ // Now check for a qt that is configured with a prefix but not installed
+ if (m_versionInfo.contains("QT_INSTALL_BINS")) {
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_BINS"));
+ if (!fi.exists())
+ m_notInstalled = true;
+ }
+ if (m_versionInfo.contains("QT_INSTALL_HEADERS")){
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_HEADERS"));
+ if (!fi.exists())
+ m_notInstalled = true;
+ }
+
+ // Parse qconfigpri
+ QString baseDir = m_versionInfo.contains("QT_INSTALL_DATA") ?
+ m_versionInfo.value("QT_INSTALL_DATA") :
+ m_path;
+ QFile qconfigpri(baseDir + QLatin1String("/mkspecs/qconfig.pri"));
+ if (qconfigpri.exists()) {
+ qconfigpri.open(QIODevice::ReadOnly | QIODevice::Text);
+ QTextStream stream(&qconfigpri);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ if (line.startsWith(QLatin1String("CONFIG"))) {
+ m_defaultConfigIsDebugAndRelease = false;
+ QStringList values = line.split(QLatin1Char('=')).at(1).trimmed().split(" ");
+ foreach(const QString &value, values) {
+ if (value == "debug")
+ m_defaultConfigIsDebug = true;
+ else if(value == "release")
+ m_defaultConfigIsDebug = false;
+ else if(value == "build_all")
+ m_defaultConfigIsDebugAndRelease = true;
+ }
+ }
+ }
+ }
+ }
+ m_versionInfoUpToDate = true;
+}
+
+bool QtVersion::isInstalled() const
+{
+ updateVersionInfo();
+ return !m_notInstalled;
+}
+
+void QtVersion::updateMkSpec() const
+{
+ if (m_mkspecUpToDate)
+ return;
+ //qDebug()<<"Finding mkspec for"<<path();
+
+ QString mkspec;
+ QFile f(path() + "/.qmake.cache");
+ if (f.exists() && f.open(QIODevice::ReadOnly)) {
+ while(!f.atEnd()) {
+ QByteArray line = f.readLine();
+ if(line.startsWith("QMAKESPEC")) {
+ const QList<QByteArray> &temp = line.split('=');
+ if(temp.size() == 2) {
+ mkspec = temp.at(1).trimmed();
+ if (mkspec.startsWith("$$QT_BUILD_TREE/mkspecs/"))
+ mkspec = mkspec.mid(QString("$$QT_BUILD_TREE/mkspecs/").length());
+ else if (mkspec.startsWith("$$QT_BUILD_TREE\\mkspecs\\"))
+ mkspec = mkspec.mid(QString("$$QT_BUILD_TREE\\mkspecs\\").length());
+ }
+ break;
+ }
+ }
+ f.close();
+ } else {
+ // no .qmake.cache so look at the default mkspec
+ QString mkspecPath = versionInfo().value("QMAKE_MKSPECS");
+ if (mkspecPath.isEmpty())
+ mkspecPath = path() + "/mkspecs/default";
+ else
+ mkspecPath = mkspecPath + "/default";
+// qDebug() << "default mkspec is located at" << mkspecPath;
+#ifdef Q_OS_WIN
+ QFile f2(mkspecPath + "/qmake.conf");
+ if (f2.exists() && f2.open(QIODevice::ReadOnly)) {
+ while(!f2.atEnd()) {
+ QByteArray line = f2.readLine();
+ if(line.startsWith("QMAKESPEC_ORIGINAL")) {
+ const QList<QByteArray> &temp = line.split('=');
+ if (temp.size() == 2) {
+ mkspec = temp.at(1);
+ }
+ break;
+ }
+ }
+ f2.close();
+ }
+#elif defined(Q_OS_MAC)
+ QFile f2(mkspecPath + "/qmake.conf");
+ if (f2.exists() && f2.open(QIODevice::ReadOnly)) {
+ while(!f2.atEnd()) {
+ QByteArray line = f2.readLine();
+ if(line.startsWith("MAKEFILE_GENERATOR")) {
+ const QList<QByteArray> &temp = line.split('=');
+ if (temp.size() == 2) {
+ const QByteArray &value = temp.at(1);
+ if (value.contains("XCODE")) {
+ // we don't want to generate xcode projects...
+// qDebug() << "default mkspec is xcode, falling back to g++";
+ mkspec = "macx-g++";
+ } else {
+ //resolve mkspec link
+ QFileInfo f3(mkspecPath);
+ if (f3.isSymLink()) {
+ mkspec = f3.symLinkTarget();
+ }
+ }
+ }
+ break;
+ }
+ }
+ f2.close();
+ }
+#else
+ QFileInfo f2(mkspecPath);
+ if (f2.isSymLink()) {
+ mkspec = f2.symLinkTarget();
+ }
+#endif
+ }
+
+ int index =mkspec.lastIndexOf('/');
+ if(index == -1)
+ index = mkspec.lastIndexOf('\\');
+ if (index >= 0 && QDir(mkspec.left(index)).canonicalPath() == QDir(m_path + "/mkspecs/").canonicalPath())
+ mkspec = mkspec.mid(index+1).trimmed();
+
+ m_mkspec = mkspec;
+ m_mkspecUpToDate = true;
+// qDebug()<<"mkspec for "<<m_path<<" is "<<mkspec;
+}
+
+QString QtVersion::makeCommand() const
+{
+#ifdef Q_OS_WIN
+ const QString &spec = mkspec();
+ if (spec.startsWith("win32-msvc") || spec == QLatin1String("win32-icc"))
+ return "nmake.exe";
+ else if(spec.startsWith("wince"))
+ return "nmake.exe";
+ else
+ return "mingw32-make.exe";
+#else
+ return "make";
+#endif
+}
+
+QString QtVersion::qmakeCommand() const
+{
+ // We can't use versionInfo QT_INSTALL_BINS here
+ // because that functions calls us to find out the values for versionInfo
+ if (!m_qmakeCommand.isNull())
+ return m_qmakeCommand;
+
+ QDir qtDir = path() + "/bin/";
+ foreach(const QString &possibleCommand, QtVersionManager::possibleQMakeCommands()) {
+ QString s = qtDir.absoluteFilePath(possibleCommand);
+ QFileInfo qmake(s);
+ if (qmake.exists() && qmake.isExecutable()) {
+ if (QtVersionManager::checkQMakeVersion(qmake.absoluteFilePath())) {
+ m_qmakeCommand = qmake.absoluteFilePath();
+ return qmake.absoluteFilePath();
+ }
+ }
+ }
+ return QString::null;
+}
+
+QtVersion::ToolchainType QtVersion::toolchainType() const
+{
+ if (!isValid())
+ return INVALID;
+ const QString &spec = mkspec();
+ if(spec.startsWith("win32-msvc") || spec == QLatin1String("win32-icc"))
+ return MSVC;
+ else if(spec == "win32-g++")
+ return MinGW;
+ else if(spec == QString::null)
+ return INVALID;
+ else if(spec.startsWith("wince"))
+ return WINCE;
+ else
+ return OTHER;
+}
+
+QString QtVersion::mingwDirectory() const
+{
+ return m_mingwDirectory;
+}
+
+void QtVersion::setMingwDirectory(const QString &directory)
+{
+ m_mingwDirectory = directory;
+}
+
+QString QtVersion::prependPath() const
+{
+ return m_prependPath;
+}
+
+void QtVersion::setPrependPath(const QString &directory)
+{
+ m_prependPath = directory;
+}
+
+QString QtVersion::msvcVersion() const
+{
+ return m_msvcVersion;
+}
+
+void QtVersion::setMsvcVersion(const QString &version)
+{
+ m_msvcVersion = version;
+}
+
+Environment QtVersion::addToEnvironment(const Environment &env)
+{
+ Environment e(env);
+ e.set("QTDIR", m_path);
+ QString qtdirbin = versionInfo().value("QT_INSTALL_BINS");
+ e.prependOrSetPath(qtdirbin);
+ // add libdir, includedir and bindir
+ // or add Mingw dirs
+ // or do nothing on other
+ QtVersion::ToolchainType t = toolchainType();
+ if(t == QtVersion::MinGW) {
+ QFileInfo mingwFileInfo(m_mingwDirectory + "/bin");
+ if(mingwFileInfo.exists())
+ e.prependOrSetPath(m_mingwDirectory + "/bin");
+ } else if(t == QtVersion::MSVC) {
+ QList<MSVCEnvironment> list = MSVCEnvironment::availableVersions();
+ if(list.count() == 1) {
+ e = list.at(0).addToEnvironment(e);
+ } else {
+ foreach(const MSVCEnvironment &m, list) {
+ if(m.name() == m_msvcVersion) {
+ e = m.addToEnvironment(e);
+ break;
+ }
+ }
+ }
+ } else if(t == QtVersion::WINCE) {
+ QString msvcPath;
+ // Find MSVC path
+ QList<MSVCEnvironment> list = MSVCEnvironment::availableVersions();
+ if(list.count() == 1) {
+ msvcPath = list.at(0).path();
+ e = list.at(0).addToEnvironment(e);
+ } else {
+ foreach(const MSVCEnvironment &m, list) {
+ if(m.name() == m_msvcVersion) {
+ e = m.addToEnvironment(e);
+ msvcPath = m.path();
+ break;
+ }
+ }
+ }
+ msvcPath += "/";
+
+// qDebug()<<"MSVC path"<<msvcPath;
+// qDebug()<<"looking for platform name in"<< path() + "/mkspecs/" + mkspec() +"/qmake.conf";
+ // Find Platform name
+
+ QString platformName = CeSdkHandler::platformName(path() + "/mkspecs/" + mkspec()+ "/qmake.conf");
+// qDebug()<<"Platform Name"<<platformName;
+
+ CeSdkHandler cesdkhandler;
+ cesdkhandler.parse(msvcPath);
+ e = cesdkhandler.find(platformName).addToEnvironment(e);
+ } else if(t == QtVersion::OTHER) {
+ if(!m_prependPath.isEmpty())
+ e.prependOrSetPath(m_prependPath);
+ }
+ return e;
+}
+
+int QtVersion::uniqueId() const
+{
+ return m_id;
+}
+
+int QtVersion::getUniqueId()
+{
+ QtVersionManager *vm = ExtensionSystem::PluginManager::instance()->getObject<QtVersionManager>();
+ return vm->getUniqueId();
+}
+
+bool QtVersion::isValid() const
+{
+ return (!(m_id == -1 || m_path == QString::null || m_name == QString::null || mkspec() == QString::null) && !m_notInstalled);
+}
+
+QtVersion::QmakeBuildConfig QtVersion::defaultBuildConfig() const
+{
+ updateVersionInfo();
+ QtVersion::QmakeBuildConfig result = QtVersion::QmakeBuildConfig(0);
+ if (m_defaultConfigIsDebugAndRelease)
+ result = QtVersion::BuildAll;
+ if (m_defaultConfigIsDebug)
+ result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
+ return result;
+}
diff --git a/src/plugins/qt4projectmanager/qtversionmanager.h b/src/plugins/qt4projectmanager/qtversionmanager.h
new file mode 100644
index 0000000000..833e4655cf
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qtversionmanager.h
@@ -0,0 +1,214 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTVERSIONMANAGER_H
+#define QTVERSIONMANAGER_H
+
+#include <QtCore/QPointer>
+#include <QtGui/QWidget>
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <coreplugin/icore.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+#include <QDebug>
+#include "ui_qtversionmanager.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class QtDirWidget;
+
+class QtVersion {
+ friend class QtDirWidget; //for changing name and path
+ friend class QtVersionManager;
+public:
+ QtVersion(const QString &name, const QString &path);
+ QtVersion(const QString &name, const QString &path, int id, bool isSystemVersion = false);
+ QtVersion()
+ :m_name(QString::null), m_path(QString::null), m_id(-1)
+ { }
+
+ bool isValid() const; //TOOD check that the dir exists and the name is non empty
+ bool isInstalled() const;
+ bool isSystemVersion() const { return m_isSystemVersion; }
+
+ QString name() const;
+ QString path() const;
+ QString sourcePath() const;
+ QString mkspec() const;
+ QString makeCommand() const;
+ QString qmakeCommand() const;
+ // Returns the PREFIX, BINPREFIX, DOCPREFIX and similar information
+ QHash<QString,QString> versionInfo() const;
+
+ enum ToolchainType { MinGW, MSVC, WINCE, OTHER, INVALID };
+
+ ToolchainType toolchainType() const;
+
+ QString mingwDirectory() const;
+ void setMingwDirectory(const QString &directory);
+ QString prependPath() const;
+ void setPrependPath(const QString &string);
+ QString msvcVersion() const;
+ void setMsvcVersion(const QString &version);
+ ProjectExplorer::Environment addToEnvironment(const ProjectExplorer::Environment &env);
+
+ int uniqueId() const;
+
+ enum QmakeBuildConfig
+ {
+ NoBuild = 1,
+ DebugBuild = 2,
+ BuildAll = 8
+ };
+
+ QmakeBuildConfig defaultBuildConfig() const;
+private:
+ static int getUniqueId();
+ void setName(const QString &name);
+ void setPath(const QString &path);
+ void updateSourcePath();
+ void updateVersionInfo() const;
+ void updateMkSpec() const;
+ QString m_name;
+ mutable bool m_versionInfoUpToDate;
+ mutable bool m_mkspecUpToDate;
+ QString m_path;
+ QString m_sourcePath;
+ mutable QString m_mkspec; // updated lazily
+ QString m_mingwDirectory;
+ QString m_prependPath;
+ QString m_msvcVersion;
+ mutable QHash<QString,QString> m_versionInfo; // updated lazily
+ int m_id;
+ bool m_isSystemVersion;
+ mutable bool m_notInstalled;
+ mutable bool m_defaultConfigIsDebug;
+ mutable bool m_defaultConfigIsDebugAndRelease;
+ mutable QString m_qmakeCommand;
+ Q_DISABLE_COPY(QtVersion);
+};
+
+
+class QtDirWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QtDirWidget(QWidget *parent, QList<QtVersion *> versions, int defaultVersion);
+ QList<QtVersion *> versions() const;
+ int defaultVersion() const;
+ void finish();
+private:
+ void showEnvironmentPage(QTreeWidgetItem * item);
+ void fixQtVersionName(int index);
+ Ui::QtVersionManager m_ui;
+ QList<QtVersion *> m_versions;
+ int m_defaultVersion;
+ QString m_specifyNameString;
+ QString m_specifyPathString;
+
+private slots:
+ void versionChanged(QTreeWidgetItem *item, QTreeWidgetItem *old);
+ void addQtDir();
+ void removeQtDir();
+ void updateState();
+ void browse();
+ void mingwBrowse();
+ void defaultChanged(int index);
+ void updateCurrentQtName();
+ void updateCurrentQtPath();
+ void updateCurrentMingwDirectory();
+ void msvcVersionChanged();
+};
+
+class QtVersionManager : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ QtVersionManager();
+ ~QtVersionManager();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ void writeVersionsIntoSettings();
+
+ QList<QtVersion *> versions() const;
+
+ QtVersion * version(int id) const;
+ QtVersion * currentQtVersion() const;
+
+ // internal
+ int getUniqueId();
+
+ QtVersion::QmakeBuildConfig scanMakefileForQmakeConfig(const QString &directory, QtVersion::QmakeBuildConfig defaultBuildConfig);
+ QString findQtVersionFromMakefile(const QString &directory);
+ QtVersion *qtVersionForDirectory(const QString &directory);
+
+ // Used by the projectloadwizard
+ void addVersion(QtVersion *version);
+
+ // returns something like qmake4, qmake, qmake-qt4 or whatever distributions have chosen (used by QtVersion)
+ static QStringList possibleQMakeCommands();
+ // return true if the qmake at qmakePath is qt4 (used by QtVersion)
+ static bool checkQMakeVersion(const QString &qmakePath);
+signals:
+ void defaultQtVersionChanged();
+ void qtVersionsChanged();
+private:
+
+ void addNewVersionsFromInstaller();
+ void updateSystemVersion();
+ void updateDocumentation();
+ QString findSystemQt() const;
+ static int indexOfVersionInList(const QtVersion * const version, const QList<QtVersion *> &list);
+ void updateUniqueIdToIndexMap();
+
+ Core::ICore *m_core;
+ QPointer<QtDirWidget> m_widget;
+
+ QtVersion *m_emptyVersion;
+ int m_defaultVersion;
+ QList<QtVersion *> m_versions;
+ QMap<int, int> m_uniqueIdToIndex;
+ int m_idcount;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif //QTVERSIONMANAGER_H
diff --git a/src/plugins/qt4projectmanager/qtversionmanager.ui b/src/plugins/qt4projectmanager/qtversionmanager.ui
new file mode 100644
index 0000000000..de93505cb0
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qtversionmanager.ui
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Qt4ProjectManager::Internal::QtVersionManager</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::QtVersionManager">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>823</width>
+ <height>929</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Qt versions</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="3">
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="addButton">
+ <property name="minimumSize">
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>+</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="delButton">
+ <property name="minimumSize">
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0" colspan="3">
+ <widget class="QTreeWidget" name="qtdirList">
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Path</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="versionNameLabel">
+ <property name="text">
+ <string>Version Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="pathEdit"/>
+ </item>
+ <item row="2" column="2">
+ <widget class="QToolButton" name="browseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="mingwLabel">
+ <property name="text">
+ <string>MinGw Directory:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="mingwLineEdit"/>
+ </item>
+ <item row="3" column="2">
+ <widget class="QToolButton" name="mingwBrowseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="3">
+ <widget class="QLabel" name="msvcLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0" colspan="4">
+ <widget class="QLabel" name="errorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2">
+ <widget class="QComboBox" name="msvcComboBox"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="defaultLabel">
+ <property name="text">
+ <string>Default Qt Version:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="defaultCombo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>qtdirList</tabstop>
+ <tabstop>delButton</tabstop>
+ <tabstop>nameEdit</tabstop>
+ <tabstop>pathEdit</tabstop>
+ <tabstop>defaultCombo</tabstop>
+ <tabstop>browseButton</tabstop>
+ </tabstops>
+ <resources>
+ <include location="../../libs/cplusplus/cplusplus.qrc"/>
+ <include location="../../libs/extensionsystem/pluginview.qrc"/>
+ <include location="../bookmarks/bookmarks.qrc"/>
+ <include location="../coreplugin/core.qrc"/>
+ <include location="../coreplugin/fancyactionbar.qrc"/>
+ <include location="../cppeditor/cppeditor.qrc"/>
+ <include location="../cpptools/cpptools.qrc"/>
+ <include location="../designer/designer.qrc"/>
+ <include location="../find/find.qrc"/>
+ <include location="../gdbdebugger/gdbdebugger.qrc"/>
+ <include location="../help/help.qrc"/>
+ <include location="../perforce/perforce.qrc"/>
+ <include location="../projectexplorer/projectexplorer.qrc"/>
+ <include location="../../../shared/proparser/proparser.qrc"/>
+ <include location="qt4projectmanager.qrc"/>
+ <include location="wizards/wizards.qrc"/>
+ <include location="../quickopen/quickopen.qrc"/>
+ <include location="../resourceeditor/resourceeditor.qrc"/>
+ <include location="../texteditor/texteditor.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/speinfo.cpp b/src/plugins/qt4projectmanager/speinfo.cpp
new file mode 100644
index 0000000000..f82e9d875a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/speinfo.cpp
@@ -0,0 +1,805 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "speinfo.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QVariant>
+#include <QtDebug>
+
+using namespace Qt4ProjectManager::Internal;
+
+bool SPEInfo::m_listsInitialized = false;
+QList<SPEInfoItem*> SPEInfo::m_configurationList;
+QList<SPEInfoItem*> SPEInfo::m_platformList;
+QList<SPEInfoItem*> SPEInfo::m_variableList;
+QList<SPEInfoItem*> SPEInfo::m_qtmoduleList;
+QList<SPEInfoItem*> SPEInfo::m_templateList;
+QList<SPEInfoItem*> SPEInfo::m_operatorList;
+
+QHash<QPair<SPEInfoItem::InfoKind, QString> ,SPEInfoItem*> SPEInfo::m_itemHash;
+
+const QString SPEInfoItem::keyType("valuetype");
+const QString SPEInfoItem::valueFile("file");
+const QString SPEInfoItem::valuePath("path");
+const QString SPEInfoItem::keyIncludedByDefault("includedbydefault");
+const QString SPEInfoItem::keyImageFileName("imagefilename");
+
+// Configurations (Debug, Release, ...)
+class InfoItemConfigurationCross : public SPEInfoItem
+{
+public:
+ InfoItemConfigurationCross(): SPEInfoItem("", Configuration) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Debug and Release"); }
+};
+
+class InfoItemConfigurationDebug : public SPEInfoItem
+{
+public:
+ InfoItemConfigurationDebug(): SPEInfoItem("debug", Configuration) {}
+ QString name(void) const {return QCoreApplication::translate("SimpleProEditor", "Debug specific");}
+};
+
+class InfoItemConfigurationRelease : public SPEInfoItem
+{
+public:
+ InfoItemConfigurationRelease(): SPEInfoItem("release", Configuration) {}
+ QString name(void) const {return QCoreApplication::translate("SimpleProEditor", "Release specific");}
+};
+
+
+// Platforms (Windows, Mac, ...)
+class InfoItemPlatformCross : public SPEInfoItem
+{
+public:
+ InfoItemPlatformCross(): SPEInfoItem("", Platform) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "All platforms"); }
+};
+
+class InfoItemPlatformWindows : public SPEInfoItem
+{
+public:
+ InfoItemPlatformWindows(): SPEInfoItem("win32", Platform) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "MS Windows specific"); }
+};
+
+class InfoItemPlatformUnix : public SPEInfoItem
+{
+public:
+ InfoItemPlatformUnix(): SPEInfoItem("unix", Platform) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Linux/Unix specific"); }
+};
+
+class InfoItemPlatformOSX : public SPEInfoItem
+{
+public:
+ InfoItemPlatformOSX(): SPEInfoItem("macx", Platform) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Mac OSX specific"); }
+};
+
+
+// Variables (Target options, Libraries, Defines, ...)
+class InfoItemVariableTargetOptions : public SPEInfoItem
+{
+public:
+ InfoItemVariableTargetOptions(): SPEInfoItem("TEMPLATE", Variable)
+ {
+ m_data.insert(keyImageFileName, ":/variableimages/images/target.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Target Options");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Type and name of the target.");
+ }
+};
+
+class InfoItemVariableDefines : public SPEInfoItem
+{
+public:
+ InfoItemVariableDefines(): SPEInfoItem("DEFINES", Variable)
+ {
+ m_data.insert(keyImageFileName, ":/variableimages/images/defines.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Preprocessor Definitions");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Setting of the preprocessor definitions.");
+ }
+};
+
+class InfoItemVariableIncludePath : public SPEInfoItem
+{
+public:
+ InfoItemVariableIncludePath(): SPEInfoItem("INCLUDEPATH", Variable)
+ {
+ m_data.insert(keyType, valuePath);
+ m_data.insert(keyImageFileName, ":/variableimages/images/includes.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Include path"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Setting of the pathes where the header files are located.");
+ }
+};
+
+class InfoItemVariableLibs : public SPEInfoItem
+{
+public:
+ InfoItemVariableLibs(): SPEInfoItem("LIBS", Variable)
+ {
+ m_data.insert(keyImageFileName, ":/variableimages/images/libs.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Libraries");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Defining the libraries to link the target against and the pathes where these are located.");
+ }
+};
+
+class InfoItemVariableSources : public SPEInfoItem
+{
+public:
+ InfoItemVariableSources(): SPEInfoItem("SOURCES", Variable)
+ {
+ m_data.insert(keyType, valueFile);
+ m_data.insert(keyImageFileName, ":/variableimages/images/sources.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Source Files");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "");
+ }
+};
+
+class InfoItemVariableHeaders : public SPEInfoItem
+{
+public:
+ InfoItemVariableHeaders(): SPEInfoItem("HEADERS", Variable)
+ {
+ m_data.insert(keyType, valueFile);
+ m_data.insert(keyImageFileName, ":/variableimages/images/headers.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Header Files");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "");
+ }
+};
+
+class InfoItemVariableForms : public SPEInfoItem
+{
+public:
+ InfoItemVariableForms(): SPEInfoItem("FORMS", Variable)
+ {
+ m_data.insert(keyType, valueFile);
+ m_data.insert(keyImageFileName, ":/variableimages/images/forms.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Forms");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "");
+ }
+};
+
+class InfoItemVariableQtModules : public SPEInfoItem
+{
+public:
+ InfoItemVariableQtModules(): SPEInfoItem("QT", Variable)
+ {
+ m_data.insert(keyImageFileName, ":/variableimages/images/qtmodules.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Qt Modules");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Setting up which of the Qt modules will be used in the target application.");
+ }
+};
+
+class InfoItemVariableResources : public SPEInfoItem
+{
+public:
+ InfoItemVariableResources(): SPEInfoItem("RESOURCES", Variable)
+ {
+ m_data.insert(keyType, valueFile);
+ m_data.insert(keyImageFileName, ":/variableimages/images/resources.png");
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Resource files");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "");
+ }
+};
+
+class InfoItemVariableTarget : public SPEInfoItem
+{
+public:
+ InfoItemVariableTarget(): SPEInfoItem("TARGET", Variable) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Target name");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "The name of the resulting target.");
+ }
+};
+
+class InfoItemVariableConfig : public SPEInfoItem
+{
+public:
+ InfoItemVariableConfig(): SPEInfoItem("CONFIG", Variable) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Configuration");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Configuration.");
+ }
+};
+
+class InfoItemVariableDestdir : public SPEInfoItem
+{
+public:
+ InfoItemVariableDestdir(): SPEInfoItem("DESTDIR", Variable) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Destination directory");}
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Where the resulting target will be created.");
+ }
+};
+
+
+// Qt modules
+class InfoItemModulesCore : public SPEInfoItem
+{
+public:
+ InfoItemModulesCore(): SPEInfoItem("core", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, true);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtCore Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Core non-GUI classes used by other modules");
+ }
+};
+
+class InfoItemModulesGui : public SPEInfoItem
+{
+public:
+ InfoItemModulesGui(): SPEInfoItem("gui", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, true);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtGui Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Graphical user interface components");
+ }
+};
+
+class InfoItemModulesNetwork : public SPEInfoItem
+{
+public:
+ InfoItemModulesNetwork(): SPEInfoItem("network", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtNetwork Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for network programming");
+ }
+};
+
+class InfoItemModulesOpenGL : public SPEInfoItem
+{
+public:
+ InfoItemModulesOpenGL(): SPEInfoItem("opengl", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtOpenGL Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "OpenGL support classes");
+ }
+};
+
+class InfoItemModulesSql : public SPEInfoItem
+{
+public:
+ InfoItemModulesSql(): SPEInfoItem("sql", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtSql Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for database integration using SQL");
+ }
+};
+
+class InfoItemModulesScript : public SPEInfoItem
+{
+public:
+ InfoItemModulesScript(): SPEInfoItem("script", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtScript Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for evaluating Qt Scripts");
+ }
+};
+
+class InfoItemModulesSvg : public SPEInfoItem
+{
+public:
+ InfoItemModulesSvg(): SPEInfoItem("svg", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtSvg Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for displaying the contents of SVG files");
+ }
+};
+
+class InfoItemModulesWebKit : public SPEInfoItem
+{
+public:
+ InfoItemModulesWebKit(): SPEInfoItem("webkit", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtWebKit Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for displaying and editing Web content");
+ }
+};
+
+class InfoItemModulesXml : public SPEInfoItem
+{
+public:
+ InfoItemModulesXml(): SPEInfoItem("xml", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtXml Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for handling XML");
+ }
+};
+
+class InfoItemModulesXmlPatterns : public SPEInfoItem
+{
+public:
+ InfoItemModulesXmlPatterns(): SPEInfoItem("xmlpatterns", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtXmlPatterns Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "An XQuery/XPath engine for XML and custom data models");
+ }
+};
+
+class InfoItemModulesPhonon : public SPEInfoItem
+{
+public:
+ InfoItemModulesPhonon(): SPEInfoItem("phonon", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Phonon Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Multimedia framework classes");
+ }
+};
+
+class InfoItemModulesQt3Support : public SPEInfoItem
+{
+public:
+ InfoItemModulesQt3Support(): SPEInfoItem("qt3support", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Qt3Support Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes that ease porting from Qt 3 to Qt 4");
+ }
+};
+
+class InfoItemModulesTest : public SPEInfoItem
+{
+public:
+ InfoItemModulesTest(): SPEInfoItem("qtestlib", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtTest Module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Tool classes for unit testing");
+ }
+};
+
+class InfoItemModulesDBus : public SPEInfoItem
+{
+public:
+ InfoItemModulesDBus(): SPEInfoItem("dbus", QtModule)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "QtDBus module"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Classes for Inter-Process Communication using the D-Bus");
+ }
+};
+
+
+// Target templates
+class InfoItemTemplatesApp : public SPEInfoItem
+{
+public:
+ InfoItemTemplatesApp(): SPEInfoItem("app", Template)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Application"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Create a standalone application");
+ }
+};
+
+class InfoItemTemplatesDynamicLib : public SPEInfoItem
+{
+public:
+ InfoItemTemplatesDynamicLib(): SPEInfoItem("lib", Template)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Dynamic Library"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Create a dynamic library for usage in other applications");
+ }
+};
+
+class InfoItemTemplatesStaticLib : public SPEInfoItem
+{
+public:
+ InfoItemTemplatesStaticLib(): SPEInfoItem("staticlib", Template)
+ {
+ m_data.insert(keyIncludedByDefault, false);
+ }
+
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Static Library"); }
+ QString description(void) const
+ {
+ return QCoreApplication::translate("SimpleProEditor",
+ "Create a static library for usage in other applications");
+ }
+};
+
+// Variable operators
+class InfoItemOperatorsAdd : public SPEInfoItem
+{
+public:
+ InfoItemOperatorsAdd(): SPEInfoItem("+=", Operator) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Add Operator"); }
+};
+
+class InfoItemOperatorsRemove : public SPEInfoItem
+{
+public:
+ InfoItemOperatorsRemove(): SPEInfoItem("-=", Operator) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Remove Operator"); }
+};
+
+class InfoItemOperatorsReplace : public SPEInfoItem
+{
+public:
+ InfoItemOperatorsReplace(): SPEInfoItem("~=", Operator) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Replace Operator"); }
+};
+
+class InfoItemOperatorsSet : public SPEInfoItem
+{
+public:
+ InfoItemOperatorsSet(): SPEInfoItem("=", Operator) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Set Operator"); }
+};
+
+class InfoItemOperatorsUniqueAdd : public SPEInfoItem
+{
+public:
+ InfoItemOperatorsUniqueAdd(): SPEInfoItem("*=", Operator) {}
+ QString name(void) const { return QCoreApplication::translate("SimpleProEditor", "Unique Add Operator"); }
+};
+
+
+SPEInfoItem::SPEInfoItem(const QString &id, InfoKind kind)
+: m_id(id)
+, m_infoKind(kind)
+, m_parentItem(0)
+{
+}
+
+QString SPEInfoItem::name() const
+{
+ return "";
+}
+
+QString SPEInfoItem::description() const
+{
+ return "";
+}
+
+QVariant SPEInfoItem::data(const QString &key) const
+{
+ return m_data.value(key);
+}
+
+const SPEInfoItem *SPEInfoItem::parentItem(void) const
+{
+ return m_parentItem;
+}
+
+void SPEInfoItem::setParentItem(const SPEInfoItem *parentItem)
+{
+ m_parentItem = parentItem;
+}
+
+bool SPEInfoItem::isAncestorOf(const SPEInfoItem *successor) const
+{
+ const SPEInfoItem *ancestorCursor = successor;
+
+ while ((ancestorCursor = ancestorCursor->parentItem()) != NULL)
+ if (ancestorCursor == this)
+ return true;
+
+ return false;
+}
+
+QString SPEInfoItem::id() const
+{
+ return m_id;
+}
+
+SPEInfoItem::InfoKind SPEInfoItem::infoKind(void) const
+{
+ return m_infoKind;
+}
+
+SPEInfo::~SPEInfo()
+{
+ deleteLists();
+}
+
+const QList<SPEInfoItem*> *SPEInfo::list(SPEInfoItem::InfoKind kind)
+{
+ if (!m_listsInitialized)
+ initializeLists();
+ return
+ kind == SPEInfoItem::Configuration?&m_configurationList
+ :kind == SPEInfoItem::Platform?&m_platformList
+ :kind == SPEInfoItem::Variable?&m_variableList
+ :kind == SPEInfoItem::QtModule?&m_qtmoduleList
+ :kind == SPEInfoItem::Template?&m_templateList
+ :/*kind == SPEInfoItem::Operator?*/&m_operatorList
+ ;
+}
+
+const SPEInfoItem *SPEInfo::defaultInfoOfKind(SPEInfoItem::InfoKind kind)
+{
+ return list(kind)->at(0);
+}
+
+void SPEInfo::addListToHash(const QList<SPEInfoItem*> &list)
+{
+ foreach (SPEInfoItem *item, list)
+ m_itemHash.insert(qMakePair(item->infoKind(), item->id()), item);
+}
+
+void SPEInfo::initializeLists(void)
+{
+ InfoItemConfigurationCross *infoItemConfigurationCross = new InfoItemConfigurationCross;
+ InfoItemConfigurationDebug *infoItemConfigurationDebug = new InfoItemConfigurationDebug;
+ infoItemConfigurationDebug->setParentItem(infoItemConfigurationCross);
+ InfoItemConfigurationRelease *infoItemConfigurationRelease = new InfoItemConfigurationRelease;
+ infoItemConfigurationRelease->setParentItem(infoItemConfigurationCross);
+ m_configurationList
+ << infoItemConfigurationCross
+ << infoItemConfigurationDebug
+ << infoItemConfigurationRelease;
+ addListToHash(m_configurationList);
+
+ InfoItemPlatformCross *infoItemPlatformCross = new InfoItemPlatformCross;
+ InfoItemPlatformWindows *infoItemPlatformWindows = new InfoItemPlatformWindows;
+ infoItemPlatformWindows->setParentItem(infoItemPlatformCross);
+ InfoItemPlatformUnix *infoItemPlatformUnix = new InfoItemPlatformUnix;
+ infoItemPlatformUnix->setParentItem(infoItemPlatformCross);
+ InfoItemPlatformOSX *infoItemPlatformOSX = new InfoItemPlatformOSX;
+ infoItemPlatformOSX->setParentItem(infoItemPlatformUnix);
+ m_platformList
+ << infoItemPlatformCross
+ << infoItemPlatformWindows
+ << infoItemPlatformUnix
+ << infoItemPlatformOSX;
+ addListToHash(m_platformList);
+
+ m_variableList
+ << new InfoItemVariableTargetOptions
+ << new InfoItemVariableDefines
+ << new InfoItemVariableLibs
+ << new InfoItemVariableIncludePath
+ << new InfoItemVariableSources
+ << new InfoItemVariableHeaders
+ << new InfoItemVariableForms
+ << new InfoItemVariableQtModules
+ << new InfoItemVariableResources
+ << new InfoItemVariableTarget
+ << new InfoItemVariableConfig
+ << new InfoItemVariableDestdir;
+ addListToHash(m_variableList);
+
+ m_qtmoduleList
+ << new InfoItemModulesCore
+ << new InfoItemModulesGui
+ << new InfoItemModulesNetwork
+ << new InfoItemModulesOpenGL
+ << new InfoItemModulesScript
+ << new InfoItemModulesSql
+ << new InfoItemModulesSvg
+ << new InfoItemModulesWebKit
+ << new InfoItemModulesXml
+ << new InfoItemModulesXmlPatterns
+ << new InfoItemModulesPhonon
+ << new InfoItemModulesQt3Support
+ << new InfoItemModulesTest
+ << new InfoItemModulesDBus;
+ addListToHash(m_qtmoduleList);
+
+ m_templateList
+ << new InfoItemTemplatesApp
+ << new InfoItemTemplatesDynamicLib
+ << new InfoItemTemplatesStaticLib;
+ addListToHash(m_templateList);
+
+ m_operatorList
+ << new InfoItemOperatorsAdd
+ << new InfoItemOperatorsRemove
+ << new InfoItemOperatorsReplace
+ << new InfoItemOperatorsSet
+ << new InfoItemOperatorsUniqueAdd;
+ addListToHash(m_operatorList);
+
+ m_listsInitialized = true;
+}
+
+void SPEInfo::deleteLists(void)
+{
+ m_itemHash.clear();
+
+ static QList<SPEInfoItem*> *lists[] = {
+ &m_configurationList,
+ &m_platformList,
+ &m_variableList,
+ &m_qtmoduleList,
+ &m_templateList,
+ &m_operatorList
+ };
+
+ for (size_t i = 0; i < sizeof(lists)/sizeof(lists[0]); i++) {
+ qDeleteAll(*lists[i]);
+ lists[i]->clear();
+ }
+
+ m_listsInitialized = false;
+}
+
+const SPEInfoItem *SPEInfo::infoOfKindForId(SPEInfoItem::InfoKind kind,
+ const QString &id, const SPEInfoItem *defaultInfoItem)
+{
+ QPair<SPEInfoItem::InfoKind, QString > keyPair = qMakePair(kind, id);
+ return m_itemHash.contains(keyPair)?m_itemHash.value(keyPair):defaultInfoItem;
+}
+
+const SPEInfoItem *SPEInfo::platformInfoForId(const QString &id)
+{
+ return infoOfKindForId(SPEInfoItem::Platform, id, SPEInfo::defaultInfoOfKind(SPEInfoItem::Platform));
+}
+
+const SPEInfoItem *SPEInfo::configurationInfoForId(const QString &id)
+{
+ return infoOfKindForId(SPEInfoItem::Configuration, id, SPEInfo::defaultInfoOfKind(SPEInfoItem::Configuration));
+}
+
+static SPEInfo speInfoInstance; // it's destructor will call deleteLists()
diff --git a/src/plugins/qt4projectmanager/speinfo.h b/src/plugins/qt4projectmanager/speinfo.h
new file mode 100644
index 0000000000..4f5634a3b9
--- /dev/null
+++ b/src/plugins/qt4projectmanager/speinfo.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SIMPLEPROEDITORINFO_H
+#define SIMPLEPROEDITORINFO_H
+
+#include <QtGui/QPixmap>
+#include <QVariant>
+#include <QtCore/QHash>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class SPEInfoItem
+{
+public:
+ enum InfoKind {
+ Configuration,
+ Platform,
+ Variable,
+ QtModule,
+ Template,
+ Operator
+ };
+
+ SPEInfoItem(const QString &id, InfoKind kind);
+ virtual ~SPEInfoItem() {}
+
+ QString id(void) const;
+ InfoKind infoKind(void) const;
+ virtual QString name(void) const;
+ virtual QString description(void) const;
+ QVariant data(const QString &key) const;
+ const SPEInfoItem *parentItem(void) const;
+ void setParentItem(const SPEInfoItem *parentItem);
+
+ bool isAncestorOf(const SPEInfoItem *ancestor) const;
+
+ static const QString keyType;
+ static const QString valueFile;
+ static const QString valuePath;
+ static const QString keyIncludedByDefault;
+ static const QString keyImageFileName;
+
+protected:
+ QHash<QString, QVariant> m_data;
+
+private:
+ QString m_id;
+ InfoKind m_infoKind;
+ QPixmap m_image;
+ const class SPEInfoItem *m_parentItem;
+};
+
+class SPEInfo
+{
+public:
+ ~SPEInfo();
+
+ static const QList<SPEInfoItem*> *list(SPEInfoItem::InfoKind kind);
+ static const SPEInfoItem *defaultInfoOfKind(SPEInfoItem::InfoKind kind);
+ static const SPEInfoItem *platformInfoForId(const QString &id);
+ static const SPEInfoItem *configurationInfoForId(const QString &id);
+ static const SPEInfoItem *infoOfKindForId(SPEInfoItem::InfoKind kind,
+ const QString &id, const SPEInfoItem *defaultInfoItem = NULL);
+
+private:
+ static void addListToHash(const QList<SPEInfoItem*> &list);
+ static void initializeLists(void);
+ static void deleteLists(void);
+
+ static QList<SPEInfoItem*> m_configurationList;
+ static QList<SPEInfoItem*> m_platformList;
+ static QList<SPEInfoItem*> m_variableList;
+ static QList<SPEInfoItem*> m_qtmoduleList;
+ static QList<SPEInfoItem*> m_templateList;
+ static QList<SPEInfoItem*> m_operatorList;
+
+ static QHash<QPair<SPEInfoItem::InfoKind, QString> ,SPEInfoItem* > m_itemHash;
+
+ static bool m_listsInitialized;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif
diff --git a/src/plugins/qt4projectmanager/wizards/consoleappwizard.cpp b/src/plugins/qt4projectmanager/wizards/consoleappwizard.cpp
new file mode 100644
index 0000000000..0bb662012e
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/consoleappwizard.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "consoleappwizard.h"
+#include "consoleappwizarddialog.h"
+#include "qt4projectmanager.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <utils/pathchooser.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+
+#include <QtGui/QIcon>
+
+static const char *mainCppC =
+"#include <QtCore/QCoreApplication>\n\n"
+"int main(int argc, char *argv[])\n"
+"{\n"
+" QCoreApplication a(argc, argv);\n\n"
+" return a.exec();\n"
+"}\n";
+
+static const char *mainSourceFileC = "main";
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+
+ConsoleAppWizard::ConsoleAppWizard(Core::ICore *core) :
+ QtWizard(core, tr("Qt4 Console Application"),
+ tr("Creates a Qt4 console application."),
+ QIcon(":/wizards/images/console.png"))
+{
+}
+
+QWizard *ConsoleAppWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ ConsoleAppWizardDialog *dialog = new ConsoleAppWizardDialog(name(), icon(), extensionPages, parent);
+ dialog->setPath(defaultPath.isEmpty() ? Core::Utils::PathChooser::homePath() : defaultPath);
+ return dialog;
+}
+
+Core::GeneratedFiles
+ ConsoleAppWizard::generateFiles(const QWizard *w,
+ QString * /*errorMessage*/) const
+{
+ const ConsoleAppWizardDialog *wizard = qobject_cast< const ConsoleAppWizardDialog *>(w);
+ const QtProjectParameters params = wizard->parameters();
+ const QString projectPath = params.projectPath();
+
+ // Create files: Source
+
+ const QString sourceFileName = Core::BaseFileWizard::buildFileName(projectPath, QLatin1String(mainSourceFileC), sourceSuffix());
+ Core::GeneratedFile source(sourceFileName);
+ source.setContents(QLatin1String(mainCppC));
+ // Create files: Profile
+ const QString profileName = Core::BaseFileWizard::buildFileName(projectPath, params.name,profileSuffix());
+
+ Core::GeneratedFile profile(profileName);
+ QString contents;
+ {
+ QTextStream proStr(&contents);
+ QtProjectParameters::writeProFileHeader(proStr);
+ params.writeProFile(proStr);
+ proStr << "\n\nSOURCES += " << QFileInfo(sourceFileName).fileName() << '\n';
+ }
+ profile.setContents(contents);
+ return Core::GeneratedFiles() << source << profile;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/consoleappwizard.h b/src/plugins/qt4projectmanager/wizards/consoleappwizard.h
new file mode 100644
index 0000000000..5469923c33
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/consoleappwizard.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CONSOLEAPPWIZARD_H
+#define CONSOLEAPPWIZARD_H
+
+#include "qtwizard.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ModulesPage;
+
+class ConsoleAppWizard : public QtWizard
+{
+ Q_OBJECT
+
+public:
+ explicit ConsoleAppWizard(Core::ICore *core);
+
+protected:
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+
+ virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // CONSOLEAPPWIZARD_H
diff --git a/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp
new file mode 100644
index 0000000000..b893b30e6f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "consoleappwizarddialog.h"
+#include "consoleappwizard.h"
+#include "modulespage.h"
+
+#include <utils/projectintropage.h>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+ConsoleAppWizardDialog::ConsoleAppWizardDialog(const QString &templateName,
+ const QIcon &icon,
+ const QList<QWizardPage*> &extensionPages,
+ QWidget *parent) :
+ QWizard(parent),
+ m_introPage(new Core::Utils::ProjectIntroPage),
+ m_modulesPage(new ModulesPage)
+{
+ setWindowIcon(icon);
+ setWindowTitle(templateName);
+ Core::BaseFileWizard::setupWizard(this);
+ setOptions(QWizard::IndependentPages | QWizard::HaveNextButtonOnLastPage);
+
+ m_introPage->setDescription(tr("This wizard generates a Qt4 console application "
+ "project. The application derives from QCoreApplication and does not "
+ "present a GUI. You can press 'Finish' at any point in time."));
+
+ m_introPage->setFinalPage(true);
+ addPage(m_introPage);
+
+ m_modulesPage->setModuleSelected(QLatin1String("core"));
+ addPage(m_modulesPage);
+ foreach (QWizardPage *p, extensionPages)
+ addPage(p);
+}
+
+void ConsoleAppWizardDialog::setPath(const QString &path)
+{
+ m_introPage->setPath(path);
+}
+
+void ConsoleAppWizardDialog::setName(const QString &name)
+{
+ m_introPage->setName(name);
+}
+
+QtProjectParameters ConsoleAppWizardDialog::parameters() const
+{
+ QtProjectParameters rc;
+ rc.type = QtProjectParameters::ConsoleApp;
+ rc.name = m_introPage->name();
+ rc.path = m_introPage->path();
+ rc.selectedModules = m_modulesPage->selectedModules();
+ rc.deselectedModules = m_modulesPage-> deselectedModules();
+ return rc;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.h b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.h
new file mode 100644
index 0000000000..21d0fb5540
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CONSOLEAPPWIZARDDIALOG_H
+#define CONSOLEAPPWIZARDDIALOG_H
+
+#include <QtGui/QWizard>
+
+namespace Core {
+ namespace Utils {
+ class ProjectIntroPage;
+ }
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct QtProjectParameters;
+class ModulesPage;
+
+class ConsoleAppWizardDialog : public QWizard
+{
+ Q_OBJECT
+
+public:
+ explicit ConsoleAppWizardDialog(const QString &templateName,
+ const QIcon &icon,
+ const QList<QWizardPage*> &extensionPages,
+ QWidget *parent = 0);
+
+ QtProjectParameters parameters() const;
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private:
+ Core::Utils::ProjectIntroPage *m_introPage;
+ ModulesPage *m_modulesPage;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // CONSOLEAPPWIZARDDIALOG_H
diff --git a/src/plugins/qt4projectmanager/wizards/filespage.cpp b/src/plugins/qt4projectmanager/wizards/filespage.cpp
new file mode 100644
index 0000000000..2c2fb6c6ec
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/filespage.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filespage.h"
+
+#include <utils/newclasswidget.h>
+
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+FilesPage::FilesPage(QWidget *parent) :
+ QWizardPage(parent),
+ m_newClassWidget(new Core::Utils::NewClassWidget)
+{
+ m_newClassWidget->setPathInputVisible(false);
+ setTitle(tr("Class Information"));
+
+ QLabel *label = new QLabel(tr("Specify basic information about the classes "
+ "for which you want to generate skeleton source code files."));
+ label->setWordWrap(true);
+
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->addWidget(label);
+ vlayout->addItem(new QSpacerItem(0, 20));
+
+ vlayout->addWidget(m_newClassWidget);
+
+ vlayout->addItem(new QSpacerItem(0, 20));
+ m_errorLabel = new QLabel;
+ m_errorLabel->setStyleSheet(QLatin1String("color: red;"));
+ vlayout->addWidget(m_errorLabel);
+ setLayout(vlayout);
+
+ connect(m_newClassWidget, SIGNAL(validChanged()), this, SIGNAL(completeChanged()));
+}
+
+void FilesPage::setSuffixes(const QString &header, const QString &source, const QString &form)
+{
+ m_newClassWidget->setSourceExtension(source);
+ m_newClassWidget->setHeaderExtension(header);
+ if (!form.isEmpty())
+ m_newClassWidget->setFormExtension(form);
+}
+
+void FilesPage::setClassName(const QString &suggestedClassName)
+{
+ m_newClassWidget->setClassName(suggestedClassName);
+}
+
+
+bool FilesPage::isComplete() const
+{
+ QString error;
+ const bool complete = m_newClassWidget->isValid(&error);
+ m_errorLabel->setText(error);
+ return complete;
+}
+
+QString FilesPage::className() const
+{
+ return m_newClassWidget->className();
+}
+
+QString FilesPage::baseClassName() const
+{
+ return m_newClassWidget->baseClassName();
+}
+
+void FilesPage::setBaseClassName(const QString &b)
+{
+ m_newClassWidget->setBaseClassName(b);
+}
+
+QString FilesPage::sourceFileName() const
+{
+ return m_newClassWidget->sourceFileName();
+}
+
+QString FilesPage::headerFileName() const
+{
+ return m_newClassWidget->headerFileName();
+}
+
+QString FilesPage::formFileName() const
+{
+ return m_newClassWidget->formFileName();
+}
+
+bool FilesPage::namespacesEnabled() const
+{
+ return m_newClassWidget->namespacesEnabled();
+}
+
+void FilesPage::setNamespacesEnabled(bool b)
+{
+ m_newClassWidget->setNamespacesEnabled(b);
+}
+
+void FilesPage::setBaseClassInputVisible(bool visible)
+{
+ m_newClassWidget->setBaseClassInputVisible(visible);
+}
+
+bool FilesPage::isBaseClassInputVisible() const
+{
+ return m_newClassWidget->isBaseClassInputVisible();
+}
+
+QStringList FilesPage::baseClassChoices() const
+{
+ return m_newClassWidget->baseClassChoices();
+}
+
+void FilesPage::setBaseClassChoices(const QStringList &choices)
+{
+ m_newClassWidget->setBaseClassChoices(choices);
+}
+
+void FilesPage::setFormFileInputVisible(bool visible)
+{
+ m_newClassWidget->setFormInputVisible(visible);
+}
+
+bool FilesPage::isFormInputVisible() const
+{
+ return m_newClassWidget->isFormInputVisible();
+}
+
+bool FilesPage::formInputCheckable() const
+{
+ return m_newClassWidget->formInputCheckable();
+}
+
+bool FilesPage::formInputChecked() const
+{
+ return m_newClassWidget->formInputChecked();
+}
+
+void FilesPage::setFormInputCheckable(bool checkable)
+{
+ m_newClassWidget->setFormInputCheckable(checkable);
+}
+
+void FilesPage::setFormInputChecked(bool checked)
+{
+ m_newClassWidget->setFormInputChecked(checked);
+}
+
+
+
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/wizards/filespage.h b/src/plugins/qt4projectmanager/wizards/filespage.h
new file mode 100644
index 0000000000..fff6ec3fdc
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/filespage.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILESPAGE_H
+#define FILESPAGE_H
+
+#include <QtGui/QWizard>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+QT_END_NAMESPACE
+
+namespace Core {
+ namespace Utils {
+ class NewClassWidget;
+ }
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class FilesPage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ explicit FilesPage(QWidget *parent = 0);
+ virtual bool isComplete() const;
+
+ QString className() const;
+ void setClassName(const QString &suggestedClassName);
+
+ QString baseClassName() const;
+ QString sourceFileName() const;
+ QString headerFileName() const;
+ QString formFileName() const;
+
+ // API of the embedded NewClassWidget
+ bool namespacesEnabled() const;
+ bool isBaseClassInputVisible() const;
+ bool isFormInputVisible() const;
+ bool formInputCheckable() const;
+ bool formInputChecked() const;
+ QStringList baseClassChoices() const;
+
+ void setSuffixes(const QString &header, const QString &source, const QString &form = QString());
+
+public slots:
+ void setBaseClassName(const QString &);
+ void setNamespacesEnabled(bool b);
+ void setBaseClassInputVisible(bool visible);
+ void setBaseClassChoices(const QStringList &choices);
+ void setFormFileInputVisible(bool visible);
+ void setFormInputCheckable(bool checkable);
+ void setFormInputChecked(bool checked);
+
+
+private:
+ Core::Utils::NewClassWidget *m_newClassWidget;
+ QLabel *m_errorLabel;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // FILESPAGE_H
diff --git a/src/plugins/qt4projectmanager/wizards/guiappwizard.cpp b/src/plugins/qt4projectmanager/wizards/guiappwizard.cpp
new file mode 100644
index 0000000000..58b2808a0f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/guiappwizard.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "guiappwizard.h"
+#include "guiappwizarddialog.h"
+#include "qt4projectmanager.h"
+#include "modulespage.h"
+#include "filespage.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <utils/pathchooser.h>
+#include <projectexplorer/projectnodes.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSharedPointer>
+
+#include <QtGui/QIcon>
+
+static const char *mainSourceFileC = "main";
+static const char *mainWindowUiContentsC =
+"\n <widget class=\"QMenuBar\" name=\"menuBar\" />"
+"\n <widget class=\"QToolBar\" name=\"mainToolBar\" />"
+"\n <widget class=\"QWidget\" name=\"centralWidget\" />"
+"\n <widget class=\"QStatusBar\" name=\"statusBar\" />";
+
+static const char *baseClassesC[] = { "QMainWindow", "QWidget", "QDialog" };
+
+static inline QStringList baseClasses()
+{
+ QStringList rc;
+ const int baseClassCount = sizeof(baseClassesC)/sizeof(const char *);
+ for (int i = 0; i < baseClassCount; i++)
+ rc.push_back(QLatin1String(baseClassesC[i]));
+ return rc;
+}
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+
+GuiAppWizard::GuiAppWizard(Core::ICore *core) :
+ QtWizard(core,
+ tr("Qt4 Gui Application"),
+ tr("Creates a Qt4 Gui Application with one form."),
+ QIcon(":/wizards/images/gui.png"))
+{
+}
+
+QWizard *GuiAppWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ GuiAppWizardDialog *dialog = new GuiAppWizardDialog(name(), icon(), extensionPages, parent);
+ dialog->setPath(defaultPath.isEmpty() ? Core::Utils::PathChooser::homePath() : defaultPath);
+ // Order! suffixes first to generate files correctly
+ dialog->setSuffixes(headerSuffix(), sourceSuffix(), formSuffix());
+ dialog->setBaseClasses(baseClasses());
+ return dialog;
+}
+
+Core::GeneratedFiles GuiAppWizard::generateFiles(const QWizard *w,
+ QString *errorMessage) const
+{
+ const GuiAppWizardDialog *dialog = qobject_cast<const GuiAppWizardDialog *>(w);
+ const QtProjectParameters projectParams = dialog->projectParameters();
+ const QString projectPath = projectParams.projectPath();
+ const GuiAppParameters params = dialog->parameters();
+
+ // Generate file names. Note that the path for the project files is the
+ // newly generated project directory.
+ const QString templatePath = templateDir();
+ // Create files: main source
+ QString contents;
+ const QString mainSourceFileName = buildFileName(projectPath, QLatin1String(mainSourceFileC), sourceSuffix());
+ Core::GeneratedFile mainSource(mainSourceFileName);
+ if (!parametrizeTemplate(templatePath, QLatin1String("main.cpp"), params, &contents, errorMessage))
+ return Core::GeneratedFiles();
+ mainSource.setContents(contents);
+ // Create files: form source
+ const QString formSourceTemplate = params.designerForm ? QLatin1String("mywidget_form.cpp") : QLatin1String("mywidget.cpp");
+ const QString formSourceFileName = buildFileName(projectPath, params.sourceFileName, sourceSuffix());
+ Core::GeneratedFile formSource(formSourceFileName);
+ if (!parametrizeTemplate(templatePath, formSourceTemplate, params, &contents, errorMessage))
+ return Core::GeneratedFiles();
+ formSource.setContents(contents);
+ // Create files: form header
+ const QString formHeaderName = buildFileName(projectPath, params.headerFileName, headerSuffix());
+ const QString formHeaderTemplate = params.designerForm ? QLatin1String("mywidget_form.h") : QLatin1String("mywidget.h");
+ Core::GeneratedFile formHeader(formHeaderName);
+ if (!parametrizeTemplate(templatePath, formHeaderTemplate, params, &contents, errorMessage))
+ return Core::GeneratedFiles();
+ formHeader.setContents(contents);
+ // Create files: form
+ QSharedPointer<Core::GeneratedFile> form;
+ if (params.designerForm) {
+ const QString formName = buildFileName(projectPath, params.formFileName, formSuffix());
+ form = QSharedPointer<Core::GeneratedFile>(new Core::GeneratedFile(formName));
+ if (!parametrizeTemplate(templatePath, QLatin1String("widget.ui"), params, &contents, errorMessage))
+ return Core::GeneratedFiles();
+ form->setContents(contents);
+ }
+ // Create files: profile
+ const QString profileName = buildFileName(projectPath, projectParams.name, profileSuffix());
+ Core::GeneratedFile profile(profileName);
+ contents.clear();
+ {
+ QTextStream proStr(&contents);
+ QtProjectParameters::writeProFileHeader(proStr);
+ projectParams.writeProFile(proStr);
+ proStr << "\n\nSOURCES += " << QFileInfo(mainSourceFileName).fileName()
+ << "\\\n " << QFileInfo(formSource.path()).fileName()
+ << "\n\nHEADERS += " << QFileInfo(formHeader.path()).fileName();
+ if (params.designerForm)
+ proStr << "\n\nFORMS += " << QFileInfo(form->path()).fileName();
+ proStr << '\n';
+ }
+ profile.setContents(contents);
+ // List
+ Core::GeneratedFiles rc;
+ rc << mainSource << formSource << formHeader;
+ if (params.designerForm)
+ rc << *form;
+ rc << profile;
+ return rc;
+}
+
+bool GuiAppWizard::parametrizeTemplate(const QString &templatePath, const QString &templateName,
+ const GuiAppParameters &params,
+ QString *target, QString *errorMessage)
+{
+ QString fileName = templatePath;
+ fileName += QDir::separator();
+ fileName += templateName;
+ QFile inFile(fileName);
+ if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ *errorMessage = tr("The template file '%1' could not be opened for reading: %2").arg(fileName, inFile.errorString());
+ return false;
+ }
+ QString contents = QString::fromUtf8(inFile.readAll());
+
+ contents.replace(QLatin1String("%QAPP_INCLUDE%"), QLatin1String("QtGui/QApplication"));
+ contents.replace(QLatin1String("%INCLUDE%"), params.headerFileName);
+ contents.replace(QLatin1String("%CLASS%"), params.className);
+ contents.replace(QLatin1String("%BASECLASS%"), params.baseClassName);
+
+ const QChar dot = QLatin1Char('.');
+
+ QString preDef = params.headerFileName.toUpper();
+ preDef.replace(dot, QLatin1Char('_'));
+ contents.replace("%PRE_DEF%", preDef.toUtf8());
+
+ const QString uiFileName = params.formFileName;
+ QString uiHdr = QLatin1String("ui_");
+ uiHdr += uiFileName.left(uiFileName.indexOf(dot));
+ uiHdr += QLatin1String(".h");
+
+ contents.replace(QLatin1String("%UI_HDR%"), uiHdr);
+ if (params.baseClassName == QLatin1String("QMainWindow")) {
+ contents.replace(QLatin1String("%CENTRAL_WIDGET%"), QLatin1String(mainWindowUiContentsC));
+ } else {
+ contents.remove(QLatin1String("%CENTRAL_WIDGET%"));
+ }
+ *target = contents;
+ return true;
+}
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/guiappwizard.h b/src/plugins/qt4projectmanager/wizards/guiappwizard.h
new file mode 100644
index 0000000000..455c48fde8
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/guiappwizard.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GUIAPPWIZARD_H
+#define GUIAPPWIZARD_H
+
+#include <QtGui/QWizard>
+
+#include "qtwizard.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct GuiAppParameters;
+
+class GuiAppWizard : public QtWizard
+{
+ Q_DISABLE_COPY(GuiAppWizard)
+ Q_OBJECT
+
+public:
+ explicit GuiAppWizard(Core::ICore *core);
+
+protected:
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+
+ virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+
+private:
+ static bool parametrizeTemplate(const QString &templatePath, const QString &templateName,
+ const GuiAppParameters &params,
+ QString *target, QString *errorMessage);
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // GUIAPPWIZARD_H
diff --git a/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp
new file mode 100644
index 0000000000..80205c0604
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "guiappwizarddialog.h"
+#include "consoleappwizard.h"
+#include "modulespage.h"
+#include "filespage.h"
+#include "qtprojectparameters.h"
+
+#include <utils/projectintropage.h>
+
+#include <QtGui/QAbstractButton>
+
+enum PageId { IntroPageId, ModulesPageId, FilesPageId };
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+
+GuiAppParameters::GuiAppParameters() :
+ designerForm(true)
+{
+
+}
+
+
+GuiAppWizardDialog::GuiAppWizardDialog(const QString &templateName,
+ const QIcon &icon,
+ const QList<QWizardPage*> &extensionPages,
+ QWidget *parent) :
+ QWizard(parent),
+ m_introPage(new Core::Utils::ProjectIntroPage),
+ m_modulesPage(new ModulesPage),
+ m_filesPage(new FilesPage)
+{
+ setWindowIcon(icon);
+ setWindowTitle(templateName);
+ Core::BaseFileWizard::setupWizard(this);
+ setOptions(QWizard::IndependentPages);
+
+ m_introPage->setDescription(tr("This wizard generates a Qt4 GUI application "
+ "project. The application derives by default from QApplication "
+ "and includes an empty widget."));
+ setPage(IntroPageId, m_introPage);
+
+ const QString coreModule = QLatin1String("core");
+ const QString guiModule = QLatin1String("gui");
+ m_modulesPage->setModuleSelected(coreModule);
+ m_modulesPage->setModuleEnabled(coreModule, false);
+ m_modulesPage->setModuleSelected(guiModule);
+ m_modulesPage->setModuleEnabled(guiModule, false);
+ setPage(ModulesPageId, m_modulesPage);
+
+ m_filesPage->setFormInputCheckable(true);
+ setPage(FilesPageId, m_filesPage);
+
+ foreach (QWizardPage *p, extensionPages)
+ addPage(p);
+}
+
+void GuiAppWizardDialog::setBaseClasses(const QStringList &baseClasses)
+{
+ m_filesPage->setBaseClassChoices(baseClasses);
+ if (!baseClasses.empty())
+ m_filesPage->setBaseClassName(baseClasses.front());
+}
+
+void GuiAppWizardDialog::setSuffixes(const QString &header, const QString &source, const QString &form)
+{
+ m_filesPage->setSuffixes(header, source, form);
+}
+
+void GuiAppWizardDialog::setPath(const QString &path)
+{
+ m_introPage->setPath(path);
+}
+
+void GuiAppWizardDialog::setName(const QString &name)
+{
+ m_introPage->setName(name);
+}
+
+QtProjectParameters GuiAppWizardDialog::projectParameters() const
+{
+ QtProjectParameters rc;
+ rc.type = QtProjectParameters::GuiApp;
+ rc.name = m_introPage->name();
+ rc.path = m_introPage->path();
+ rc.selectedModules = m_modulesPage->selectedModules();
+ rc.deselectedModules = m_modulesPage-> deselectedModules();
+ return rc;
+}
+
+GuiAppParameters GuiAppWizardDialog::parameters() const
+{
+ GuiAppParameters rc;
+ rc.className = m_filesPage->className();
+ rc.baseClassName = m_filesPage->baseClassName();
+ rc.sourceFileName = m_filesPage->sourceFileName();
+ rc.headerFileName = m_filesPage->headerFileName();
+ rc.formFileName = m_filesPage->formFileName();
+ rc.designerForm = m_filesPage->formInputChecked();
+ return rc;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.h b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.h
new file mode 100644
index 0000000000..7ab8d0a197
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GUIAPPWIZARDDIALOG_H
+#define GUIAPPWIZARDDIALOG_H
+
+#include <QtGui/QWizard>
+
+namespace Core {
+ namespace Utils {
+ class ProjectIntroPage;
+ }
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct QtProjectParameters;
+class ModulesPage;
+class FilesPage;
+
+// Additional parameters required besides QtProjectParameters
+struct GuiAppParameters {
+ GuiAppParameters();
+ QString className;
+ QString baseClassName;
+ QString sourceFileName;
+ QString headerFileName;
+ QString formFileName;
+ bool designerForm;
+};
+
+class GuiAppWizardDialog : public QWizard
+{
+ Q_OBJECT
+
+public:
+ explicit GuiAppWizardDialog(const QString &templateName,
+ const QIcon &icon,
+ const QList<QWizardPage*> &extensionPages,
+ QWidget *parent = 0);
+
+ void setBaseClasses(const QStringList &baseClasses);
+ void setSuffixes(const QString &header, const QString &source, const QString &form);
+
+ QtProjectParameters projectParameters() const;
+ GuiAppParameters parameters() const;
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private:
+ Core::Utils::ProjectIntroPage *m_introPage;
+ ModulesPage *m_modulesPage;
+ FilesPage *m_filesPage;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // GUIAPPWIZARDDIALOG_H
diff --git a/src/plugins/qt4projectmanager/wizards/images/console.png b/src/plugins/qt4projectmanager/wizards/images/console.png
new file mode 100644
index 0000000000..7569a988f4
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/images/console.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/wizards/images/gui.png b/src/plugins/qt4projectmanager/wizards/images/gui.png
new file mode 100644
index 0000000000..c121959d9e
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/images/gui.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/wizards/images/lib.png b/src/plugins/qt4projectmanager/wizards/images/lib.png
new file mode 100644
index 0000000000..a4e818d986
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/images/lib.png
Binary files differ
diff --git a/src/plugins/qt4projectmanager/wizards/libraryparameters.cpp b/src/plugins/qt4projectmanager/wizards/libraryparameters.cpp
new file mode 100644
index 0000000000..c9f50fd335
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/libraryparameters.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "libraryparameters.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QStringList>
+
+#include <utils/codegeneration.h>
+
+// Contents of the header defining the shared library export.
+#define GUARD_VARIABLE "<GUARD>"
+#define EXPORT_MACRO_VARIABLE "<EXPORT_MACRO>"
+#define LIBRARY_MACRO_VARIABLE "<LIBRARY_MACRO>"
+
+static const char *globalHeaderContentsC =
+"#ifndef "GUARD_VARIABLE"\n"
+"#define "GUARD_VARIABLE"\n"
+"\n"
+"#include <QtCore/qglobal.h>\n"
+"\n"
+"#if defined("LIBRARY_MACRO_VARIABLE")\n"
+"# define "EXPORT_MACRO_VARIABLE" Q_DECL_EXPORT\n"
+"#else\n"
+"# define "EXPORT_MACRO_VARIABLE" Q_DECL_IMPORT\n"
+"#endif\n"
+"\n"
+"#endif // "GUARD_VARIABLE"\n";
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+void LibraryParameters::generateCode(QtProjectParameters:: Type t,
+ const QString &projectTarget,
+ const QString &headerName,
+ const QString &sharedHeader,
+ const QString &exportMacro,
+ int indentation,
+ QString *header,
+ QString *source) const
+{
+ QString rc;
+ QTextStream headerStr(header);
+
+ const QString indent = QString(indentation, QLatin1Char(' '));
+
+ // 1) Header
+ const QString guard = Core::Utils::headerGuard(headerFileName);
+ headerStr << "#ifndef " << guard
+ << "\n#define " << guard << '\n' << '\n';
+
+ if (!sharedHeader.isEmpty())
+ Core::Utils::writeIncludeFileDirective(sharedHeader, false, headerStr);
+
+ // include base class header
+ if (!baseClassName.isEmpty()) {
+ QString include;
+ if (!baseClassModule.isEmpty()) {
+ include += baseClassModule;
+ include += QLatin1Char('/');
+ }
+ include += baseClassName;
+ Core::Utils::writeIncludeFileDirective(include, true, headerStr);
+ headerStr << '\n';
+ }
+
+ // Do we have namespaces?
+ QStringList namespaceList = className.split(QLatin1String("::"));
+ if (namespaceList.empty()) // Paranoia!
+ return;
+
+ const QString unqualifiedClassName = namespaceList.back();
+ namespaceList.pop_back();
+
+ const QString namespaceIndent = Core::Utils::writeOpeningNameSpaces(namespaceList, indent, headerStr);
+
+ // Class declaraction
+ headerStr << '\n' << namespaceIndent << "class ";
+ if (t == QtProjectParameters::SharedLibrary && !exportMacro.isEmpty())
+ headerStr << exportMacro << ' ';
+
+ headerStr << unqualifiedClassName;
+ if (!baseClassName.isEmpty())
+ headerStr << " : public " << baseClassName;
+ headerStr << " {\n";
+
+ // Is this a QObject (plugin)
+ const bool inheritsQObject = t == QtProjectParameters::Qt4Plugin;
+ if (inheritsQObject) {
+ headerStr << namespaceIndent << indent << "Q_OBJECT\n"
+ << namespaceIndent << indent << "Q_DISABLE_COPY(" << unqualifiedClassName << ")\n";
+ }
+ headerStr << namespaceIndent << "public:\n";
+ if (inheritsQObject) {
+ headerStr << namespaceIndent << indent << "explicit " << unqualifiedClassName << "(QObject *parent = 0);\n";
+ } else {
+ headerStr << namespaceIndent << indent << unqualifiedClassName << "();\n";
+ }
+ headerStr << namespaceIndent << "};\n\n";
+ Core::Utils::writeClosingNameSpaces(namespaceList, indent, headerStr);
+ headerStr << "#endif // "<< guard << '\n';
+ /// 2) Source
+ QTextStream sourceStr(source);
+
+ Core::Utils::writeIncludeFileDirective(headerName, false, sourceStr);
+ sourceStr << '\n';
+
+ Core::Utils::writeOpeningNameSpaces(namespaceList, indent, sourceStr);
+ // Constructor
+ sourceStr << '\n' << namespaceIndent << unqualifiedClassName << "::" << unqualifiedClassName;
+ if (inheritsQObject) {
+ sourceStr << "(QObject *parent) :\n"
+ << namespaceIndent << indent << baseClassName << "(parent)\n";
+ } else {
+ sourceStr << "()\n";
+ }
+ sourceStr << namespaceIndent << "{\n" << namespaceIndent << "}\n";
+
+ Core::Utils::writeClosingNameSpaces(namespaceList, indent, sourceStr);
+
+ if (t == QtProjectParameters::Qt4Plugin)
+ sourceStr << '\n' << "Q_EXPORT_PLUGIN2(" << projectTarget << ", " << className << ")\n";
+}
+
+QString LibraryParameters::generateSharedHeader(const QString &globalHeaderFileName,
+ const QString &projectTarget,
+ const QString &exportMacro)
+{
+ QString contents = QLatin1String(globalHeaderContentsC);
+ contents.replace(QLatin1String(GUARD_VARIABLE), Core::Utils::headerGuard(globalHeaderFileName));
+ contents.replace(QLatin1String(EXPORT_MACRO_VARIABLE), exportMacro);
+ contents.replace(QLatin1String(LIBRARY_MACRO_VARIABLE), QtProjectParameters::libraryMacro(projectTarget));
+ return contents;
+}
+}
+}
+
diff --git a/src/plugins/qt4projectmanager/wizards/libraryparameters.h b/src/plugins/qt4projectmanager/wizards/libraryparameters.h
new file mode 100644
index 0000000000..ef70c32bf0
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/libraryparameters.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LIBRARYPARAMETERS_H
+#define LIBRARYPARAMETERS_H
+
+#include "qtprojectparameters.h"
+
+#include <QtCore/QString>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+// Additional parameters required besides QtProjectParameters for creating
+// libraries
+struct LibraryParameters {
+
+ // generate class
+ void generateCode(QtProjectParameters:: Type t,
+ const QString &projectTarget,
+ const QString &headerName,
+ const QString &sharedHeader,
+ const QString &exportMacro,
+ int indentation,
+ QString *header,
+ QString *source) const;
+
+ // Generate the code of the shared header containing the export macro
+ static QString generateSharedHeader(const QString &globalHeaderFileName,
+ const QString &projectTarget,
+ const QString &exportMacro);
+
+ QString className;
+ QString baseClassName;
+ QString sourceFileName;
+ QString headerFileName;
+ QString baseClassModule;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // LIBRARYPARAMETERS_H
diff --git a/src/plugins/qt4projectmanager/wizards/librarywizard.cpp b/src/plugins/qt4projectmanager/wizards/librarywizard.cpp
new file mode 100644
index 0000000000..953ef3908c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/librarywizard.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "librarywizard.h"
+#include "librarywizarddialog.h"
+#include "qt4projectmanager.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <utils/codegeneration.h>
+#include <utils/pathchooser.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtGui/QIcon>
+
+static const char *sharedHeaderPostfixC = "_global";
+
+namespace Qt4ProjectManager {
+
+namespace Internal {
+
+LibraryWizard::LibraryWizard(Core::ICore *core) :
+ QtWizard(core, tr("C++ Library"),
+ tr("Creates a C++ Library."),
+ QIcon(":/wizards/images/lib.png"))
+{
+}
+
+QWizard *LibraryWizard::createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const
+{
+ LibraryWizardDialog *dialog = new LibraryWizardDialog(name(), icon(), extensionPages, parent);
+ dialog->setPath(defaultPath.isEmpty() ? Core::Utils::PathChooser::homePath() : defaultPath);
+ dialog->setSuffixes(headerSuffix(), sourceSuffix(), formSuffix());
+ return dialog;
+}
+
+
+Core::GeneratedFiles LibraryWizard::generateFiles(const QWizard *w,
+ QString * /*errorMessage*/) const
+{
+ const LibraryWizardDialog *dialog = qobject_cast<const LibraryWizardDialog *>(w);
+ const QtProjectParameters projectParams = dialog->parameters();
+ const QString projectPath = projectParams.projectPath();
+ const LibraryParameters params = dialog->libraryParameters();
+
+ const QString sharedLibExportMacro = QtProjectParameters::exportMacro(projectParams.name);
+
+ Core::GeneratedFiles rc;
+ // Class header + source
+ const QString sourceFileName = buildFileName(projectPath, params.sourceFileName, sourceSuffix());
+ Core::GeneratedFile source(sourceFileName);
+
+ const QString headerFileFullName = buildFileName(projectPath, params.headerFileName, headerSuffix());
+ const QString headerFileName = QFileInfo(headerFileFullName).fileName();
+ Core::GeneratedFile header(headerFileFullName);
+
+ // Create files: global header for shared libs
+ QString globalHeaderFileName;
+ if (projectParams.type == QtProjectParameters::SharedLibrary) {
+ const QString globalHeaderName = buildFileName(projectPath, projectParams.name + QLatin1String(sharedHeaderPostfixC), headerSuffix());
+ Core::GeneratedFile globalHeader(globalHeaderName);
+ globalHeaderFileName = QFileInfo(globalHeader.path()).fileName();
+ globalHeader.setContents(LibraryParameters::generateSharedHeader(globalHeaderFileName, projectParams.name, sharedLibExportMacro));
+ rc.push_back(globalHeader);
+ }
+
+ // Generate code
+ QString headerContents, sourceContents;
+ params.generateCode(projectParams.type, projectParams.name, headerFileName,
+ globalHeaderFileName, sharedLibExportMacro,
+ /* indentation*/ 4, &headerContents, &sourceContents);
+
+ source.setContents(sourceContents);
+ header.setContents(headerContents);
+ rc.push_back(source);
+ rc.push_back(header);
+ // Create files: profile
+ const QString profileName = buildFileName(projectPath, projectParams.name, profileSuffix());
+ Core::GeneratedFile profile(profileName);
+ QString profileContents;
+ {
+ QTextStream proStr(&profileContents);
+ QtProjectParameters::writeProFileHeader(proStr);
+ projectParams.writeProFile(proStr);
+ proStr << "\nSOURCES += " << QFileInfo(source.path()).fileName()
+ << "\n\nHEADERS += " << headerFileName;
+ if (!globalHeaderFileName.isEmpty())
+ proStr << "\\\n " << globalHeaderFileName << '\n';
+ }
+ profile.setContents(profileContents);
+ rc.push_back(profile);
+ return rc;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/librarywizard.h b/src/plugins/qt4projectmanager/wizards/librarywizard.h
new file mode 100644
index 0000000000..0b797034b6
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/librarywizard.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LIBRARYWIZARD_H
+#define LIBRARYWIZARD_H
+
+#include "qtwizard.h"
+#include "libraryparameters.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct LibraryParameters;
+class ModulesPage;
+
+class LibraryWizard : public QtWizard
+{
+ Q_OBJECT
+
+public:
+ explicit LibraryWizard(Core::ICore *core);
+
+protected:
+ virtual QWizard *createWizardDialog(QWidget *parent,
+ const QString &defaultPath,
+ const WizardPageList &extensionPages) const;
+
+ virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+ QString *errorMessage) const;
+
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // LIBRARYWIZARD_H
diff --git a/src/plugins/qt4projectmanager/wizards/librarywizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/librarywizarddialog.cpp
new file mode 100644
index 0000000000..c0b2a755fc
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/librarywizarddialog.cpp
@@ -0,0 +1,268 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "librarywizarddialog.h"
+#include "consoleappwizard.h"
+#include "modulespage.h"
+#include "filespage.h"
+#include "libraryparameters.h"
+
+#include <utils/projectintropage.h>
+
+#include <QtGui/QComboBox>
+#include <QtGui/QLabel>
+
+#include <QtCore/QDebug>
+
+enum { debugLibWizard = 0 };
+enum { IntroPageId, ModulesPageId, FilePageId };
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct PluginBaseClasses {
+ const char *name;
+ const char *module;
+ // blank separated list or 0
+ const char *dependentModules;
+ const char *targetDirectory;
+};
+
+static const PluginBaseClasses pluginBaseClasses[] =
+{
+ { "QAccessiblePlugin", "QtGui", "QtCore", "accessible" },
+ { "QDecorationPlugin", "QtGui", "QtCore", 0},
+ { "QFontEnginePlugin", "QtGui", "QtCore", 0},
+ { "QIconEnginePluginV2", "QtGui", "QtCore", "imageformats" },
+ { "QImageIOPlugin", "QtGui", "QtCore", "imageformats" },
+ { "QScriptExtensionPlugin", "QtScript", "QtCore", 0 },
+ { "QSqlDriverPlugin", "QtSql", "QtCore", "sqldrivers" },
+ { "QStylePlugin", "QtGui", "QtCore", "styles" },
+ { "QTextCodecPlugin", "QtCore", 0, "codecs" }
+};
+
+enum { defaultPluginBaseClass = 7 };
+
+static const PluginBaseClasses *findPluginBaseClass(const QString &name)
+{
+ const int pluginBaseClassCount = sizeof(pluginBaseClasses)/sizeof(PluginBaseClasses);
+ for (int i = 0; i < pluginBaseClassCount; i++)
+ if (name == QLatin1String(pluginBaseClasses[i].name))
+ return pluginBaseClasses + i;
+ return 0;
+}
+
+// return dependencies of a plugin as a line ready for the 'QT=' line in a pro
+// file
+static QString pluginDependencies(const PluginBaseClasses *plb)
+{
+ QString dependencies;
+ const QChar blank = QLatin1Char(' ');
+ // Find the module names and convert to ids
+ QStringList pluginModules= plb->dependentModules ?
+ QString(QLatin1String(plb->dependentModules)).split(blank) :
+ QStringList();
+ pluginModules.push_back(QLatin1String(plb->module));
+ foreach(const QString &module, pluginModules) {
+ if (!dependencies.isEmpty())
+ dependencies += blank;
+ dependencies += ModulesPage::idOfModule(module);
+ }
+ return dependencies;
+}
+
+// A Project intro page with an additional type chooser.
+class LibraryIntroPage : public Core::Utils::ProjectIntroPage
+{
+ Q_DISABLE_COPY(LibraryIntroPage)
+public:
+ explicit LibraryIntroPage(QWidget *parent = 0);
+
+ QtProjectParameters::Type type() const;
+
+ virtual int nextId() const;
+
+private:
+ QComboBox *m_typeCombo;
+};
+
+LibraryIntroPage::LibraryIntroPage(QWidget *parent) :
+ Core::Utils::ProjectIntroPage(parent),
+ m_typeCombo(new QComboBox)
+{
+ m_typeCombo->setEditable(false);
+ m_typeCombo->addItem(LibraryWizardDialog::tr("Shared library"),
+ QVariant(QtProjectParameters::SharedLibrary));
+ m_typeCombo->addItem(LibraryWizardDialog::tr("Statically linked library"),
+ QVariant(QtProjectParameters::StaticLibrary));
+ m_typeCombo->addItem(LibraryWizardDialog::tr("Qt 4 plugin"),
+ QVariant(QtProjectParameters::Qt4Plugin));
+ insertControl(0, new QLabel(LibraryWizardDialog::tr("Type")), m_typeCombo);
+}
+
+QtProjectParameters::Type LibraryIntroPage::type() const
+{
+ return static_cast<QtProjectParameters::Type>(m_typeCombo->itemData(m_typeCombo->currentIndex()).toInt());
+}
+
+int LibraryIntroPage::nextId() const
+{
+ // The modules page is skipped in the case of a plugin since it knows its
+ // dependencies by itself
+ const int rc = type() == QtProjectParameters::Qt4Plugin ? FilePageId : ModulesPageId;
+ if (debugLibWizard)
+ qDebug() << Q_FUNC_INFO << "returns" << rc;
+ return rc;
+}
+
+// ------------------- LibraryWizardDialog
+LibraryWizardDialog::LibraryWizardDialog(const QString &templateName,
+ const QIcon &icon,
+ const QList<QWizardPage*> &extensionPages,
+ QWidget *parent) :
+ QWizard(parent),
+ m_introPage(new LibraryIntroPage),
+ m_modulesPage(new ModulesPage),
+ m_filesPage(new FilesPage),
+ m_pluginBaseClassesInitialized(false)
+{
+ setWindowIcon(icon);
+ setWindowTitle(templateName);
+ Core::BaseFileWizard::setupWizard(this);
+
+ // Note that QWizard::currentIdChanged() is emitted at strange times.
+ // Use the intro page instead, set up initially
+ m_introPage->setDescription(tr("This wizard generates a C++ library project."));
+
+ setPage(IntroPageId, m_introPage);
+
+ m_modulesPage->setModuleSelected(QLatin1String("core"));
+ setPage(ModulesPageId, m_modulesPage);
+
+ m_filesPage->setNamespacesEnabled(true);
+ m_filesPage->setFormFileInputVisible(false);
+ setPage(FilePageId, m_filesPage);
+
+ connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentIdChanged(int)));
+
+ foreach (QWizardPage *p, extensionPages)
+ addPage(p);
+}
+
+void LibraryWizardDialog::setSuffixes(const QString &header, const QString &source, const QString &form)
+{
+ m_filesPage->setSuffixes(header, source, form);
+}
+
+void LibraryWizardDialog::setPath(const QString &path)
+{
+ m_introPage->setPath(path);
+}
+
+void LibraryWizardDialog::setName(const QString &name)
+{
+ m_introPage->setName(name);
+}
+
+QtProjectParameters LibraryWizardDialog::parameters() const
+{
+ QtProjectParameters rc;
+ rc.type = m_introPage->type();
+ rc.name = m_introPage->name();
+ rc.path = m_introPage->path();
+ if (rc.type == QtProjectParameters::Qt4Plugin) {
+ // Plugin: Dependencies & Target directory
+ if (const PluginBaseClasses *plb = findPluginBaseClass(m_filesPage->baseClassName())) {
+ rc.selectedModules = pluginDependencies(plb);
+ if (plb->targetDirectory) {
+ rc.targetDirectory = QLatin1String("$$[QT_INSTALL_PLUGINS]/");
+ rc.targetDirectory += QLatin1String(plb->targetDirectory);
+ }
+ }
+ } else {
+ // Modules from modules page
+ rc.selectedModules = m_modulesPage->selectedModules();
+ rc.deselectedModules = m_modulesPage-> deselectedModules();
+ }
+ return rc;
+}
+
+void LibraryWizardDialog::slotCurrentIdChanged(int id)
+{
+ if (debugLibWizard)
+ qDebug() << Q_FUNC_INFO << id;
+ // Switching to files page: Set up base class accordingly (plugin)
+ if (id != FilePageId)
+ return;
+ switch (m_introPage->type()) {
+ case QtProjectParameters::Qt4Plugin:
+ if (!m_pluginBaseClassesInitialized) {
+ if (debugLibWizard)
+ qDebug("initializing for plugins");
+ QStringList baseClasses;
+ const int pluginBaseClassCount = sizeof(pluginBaseClasses)/sizeof(PluginBaseClasses);
+ Q_ASSERT(defaultPluginBaseClass < pluginBaseClassCount);
+ for (int i = 0; i < pluginBaseClassCount; i++)
+ baseClasses.push_back(QLatin1String(pluginBaseClasses[i].name));
+ m_filesPage->setBaseClassChoices(baseClasses);
+ m_filesPage->setBaseClassName(baseClasses.at(defaultPluginBaseClass));
+ m_pluginBaseClassesInitialized = true;
+ }
+ m_filesPage->setBaseClassInputVisible(true);
+ break;
+ default: {
+ // Urrm, figure out a good class name. Use project name this time
+ QString name = m_introPage->name();
+ name[0] = name.at(0).toUpper();
+ m_filesPage->setClassName(name);
+ m_filesPage->setBaseClassInputVisible(false);
+ }
+ break;
+ }
+}
+
+LibraryParameters LibraryWizardDialog::libraryParameters() const
+{
+ LibraryParameters rc;
+ rc.className = m_filesPage->className();
+ rc.baseClassName = m_filesPage->baseClassName();
+ rc.sourceFileName = m_filesPage->sourceFileName();
+ rc.headerFileName = m_filesPage->headerFileName();
+ if (!rc.baseClassName.isEmpty())
+ if (const PluginBaseClasses *plb = findPluginBaseClass(rc.baseClassName)) {
+ rc.baseClassModule = QLatin1String(plb->module);
+ }
+ return rc;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/librarywizarddialog.h b/src/plugins/qt4projectmanager/wizards/librarywizarddialog.h
new file mode 100644
index 0000000000..0fa91d1d70
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/librarywizarddialog.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LIBRARYWIZARDDIALOG_H
+#define LIBRARYWIZARDDIALOG_H
+
+#include <QtGui/QWizard>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct QtProjectParameters;
+class ModulesPage;
+class LibraryIntroPage;
+class FilesPage;
+struct LibraryParameters;
+
+// Library wizard dialog.
+class LibraryWizardDialog : public QWizard
+{
+ Q_OBJECT
+
+public:
+ explicit LibraryWizardDialog(const QString &templateName,
+ const QIcon &icon,
+ const QList<QWizardPage*> &extensionPages,
+ QWidget *parent = 0);
+
+ void setSuffixes(const QString &header, const QString &source, const QString &form= QString());
+
+ QtProjectParameters parameters() const;
+ LibraryParameters libraryParameters() const;
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private slots:
+ void slotCurrentIdChanged(int);
+
+private:
+ LibraryIntroPage *m_introPage;
+ ModulesPage *m_modulesPage;
+ FilesPage *m_filesPage;
+ bool m_pluginBaseClassesInitialized;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // LIBRARYWIZARDDIALOG_H
diff --git a/src/plugins/qt4projectmanager/wizards/modulespage.cpp b/src/plugins/qt4projectmanager/wizards/modulespage.cpp
new file mode 100644
index 0000000000..3894250b4c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/modulespage.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "modulespage.h"
+#include "speinfo.h"
+
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QCheckBox>
+#include <QtGui/QWidget>
+
+#include <QtCore/QDebug>
+
+#include <math.h>
+
+using namespace Qt4ProjectManager::Internal;
+
+ModulesPage::ModulesPage(QWidget *parent)
+ : QWizardPage(parent)
+{
+ setTitle(tr("Select required modules"));
+ QLabel *label = new QLabel(tr("Select the modules you want to include in your "
+ "project. The recommended modules for this project are selected by default."));
+ label->setWordWrap(true);
+
+ QVBoxLayout *vlayout = new QVBoxLayout();
+ vlayout->addWidget(label);
+ vlayout->addItem(new QSpacerItem(0, 20));
+
+ QGridLayout *layout = new QGridLayout;
+
+ const QList<SPEInfoItem*> infoItemsList = *SPEInfo::list(SPEInfoItem::QtModule);
+ int itemId = 0;
+ int rowsCount = (infoItemsList.count() + 1) / 2;
+ foreach (const SPEInfoItem *infoItem, infoItemsList) {
+ QCheckBox *moduleCheckBox = new QCheckBox(infoItem->name());
+ moduleCheckBox->setToolTip(infoItem->description());
+ moduleCheckBox->setWhatsThis(infoItem->description());
+ registerField(infoItem->id(), moduleCheckBox);
+ int row = itemId % rowsCount;
+ int column = itemId / rowsCount;
+ layout->addWidget(moduleCheckBox, row, column);
+ m_moduleCheckBoxMap[infoItem->id()] = moduleCheckBox;
+ itemId++;
+ }
+
+ vlayout->addLayout(layout);
+ setLayout(vlayout);
+}
+
+// Return the key that goes into the Qt config line for a module
+QString ModulesPage::idOfModule(const QString &module)
+{
+ const QList<SPEInfoItem*> infoItemsList = *SPEInfo::list(SPEInfoItem::QtModule);
+ foreach (const SPEInfoItem *infoItem, infoItemsList)
+ if (infoItem->name().startsWith(module))
+ return infoItem->id();
+ return QString();
+}
+
+QString ModulesPage::selectedModules() const
+{
+ return modules(true);
+}
+
+QString ModulesPage::deselectedModules() const
+{
+ return modules(false);
+}
+
+void ModulesPage::setModuleSelected(const QString &module, bool selected) const
+{
+ QCheckBox *checkBox = m_moduleCheckBoxMap[module];
+ Q_ASSERT(checkBox);
+ if (checkBox)
+ checkBox->setCheckState(selected?Qt::Checked:Qt::Unchecked);
+}
+
+void ModulesPage::setModuleEnabled(const QString &module, bool enabled) const
+{
+ QCheckBox *checkBox = m_moduleCheckBoxMap[module];
+ Q_ASSERT(checkBox);
+ if (checkBox)
+ checkBox->setEnabled(enabled);
+}
+
+QString ModulesPage::modules(bool selected) const
+{
+ QStringList modules;
+
+ const QList<SPEInfoItem*> infoItemsList = *SPEInfo::list(SPEInfoItem::QtModule);
+ foreach (const SPEInfoItem *infoItem, infoItemsList) {
+ if (selected != infoItem->data(SPEInfoItem::keyIncludedByDefault).toBool()
+ && selected == field(infoItem->id()).toBool())
+ modules << infoItem->id();
+ }
+
+ return modules.join(QString(QLatin1Char(' ')));
+}
diff --git a/src/plugins/qt4projectmanager/wizards/modulespage.h b/src/plugins/qt4projectmanager/wizards/modulespage.h
new file mode 100644
index 0000000000..a637fecc9b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/modulespage.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef MODULESPAGE_H
+#define MODULESPAGE_H
+
+#include <QtCore/QMap>
+#include <QtGui/QWizard>
+
+QT_BEGIN_NAMESPACE
+class QCheckBox;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ModulesPage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ explicit ModulesPage(QWidget* parent = 0);
+ QString selectedModules() const;
+ QString deselectedModules() const;
+ void setModuleSelected(const QString &module, bool selected = true) const;
+ void setModuleEnabled(const QString &module, bool enabled = true) const;
+
+ // Return the key that goes into the Qt config line for a module
+ static QString idOfModule(const QString &module);
+
+private:
+ QMap<QString, QCheckBox*> m_moduleCheckBoxMap;
+ QString modules(bool selected = true) const;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif
diff --git a/src/plugins/qt4projectmanager/wizards/qtprojectparameters.cpp b/src/plugins/qt4projectmanager/wizards/qtprojectparameters.cpp
new file mode 100644
index 0000000000..59bbbec58d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/qtprojectparameters.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtprojectparameters.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+// ----------- QtProjectParameters
+QtProjectParameters::QtProjectParameters() :
+ type(ConsoleApp)
+{
+ }
+
+QString QtProjectParameters::projectPath() const
+{
+ QString rc = path;
+ if (!rc.isEmpty())
+ rc += QDir::separator();
+ rc += name;
+ return rc;
+}
+
+void QtProjectParameters::writeProFile(QTextStream &str) const
+{
+ if (!selectedModules.isEmpty())
+ str << "QT += " << selectedModules << "\n\n";
+ if (!deselectedModules.isEmpty())
+ str << "QT -= " << deselectedModules << "\n\n";
+ if (!name.isEmpty())
+ str << "TARGET = " << name << '\n';
+ switch (type) {
+ case ConsoleApp:
+ // Mac: Command line apps should not be bundles
+ str << "CONFIG += console\nCONFIG -= app_bundle\n\n";
+ case GuiApp:
+ str << "TEMPLATE = app\n";
+ break;
+ case StaticLibrary:
+ str << "TEMPLATE = lib\nCONFIG += staticlib\n";
+ break;
+ case SharedLibrary:
+ str << "TEMPLATE = lib\n\nDEFINES += " << libraryMacro(name) << '\n';
+ break;
+ case Qt4Plugin:
+ str << "TEMPLATE = lib\nCONFIG += plugin\n";
+ break;
+ }
+
+ if (!targetDirectory.isEmpty())
+ str << "\nDESTDIR = " << targetDirectory << '\n';
+}
+
+void QtProjectParameters::writeProFileHeader(QTextStream &str)
+{
+ const QChar hash = QLatin1Char ('#');
+ const QChar nl = QLatin1Char('\n');
+ const QChar blank = QLatin1Char(' ');
+ // Format as '#-------\n# <Header> \n#---------'
+ QString header = QLatin1String(" Project created by ");
+ header += QCoreApplication::applicationName();
+ header += blank;
+ header += QDateTime::currentDateTime().toString(Qt::ISODate);
+ const QString line = QString(header.size(), QLatin1Char('-'));
+ str << hash << line << nl << hash << nl << hash << header << nl
+ << hash <<nl << hash << line << nl << nl;
+}
+
+
+QString createMacro(const QString &name, const QString &suffix)
+{
+ QString rc = name.toUpper();
+ const int extensionPosition = rc.indexOf(QLatin1Char('.'));
+ if (extensionPosition != -1)
+ rc.truncate(extensionPosition);
+ rc += suffix;
+ return rc;
+}
+
+QString QtProjectParameters::exportMacro(const QString &projectName)
+{
+ return createMacro(projectName, QLatin1String("SHARED_EXPORT"));
+}
+
+QString QtProjectParameters::libraryMacro(const QString &projectName)
+{
+ return createMacro(projectName, QLatin1String("_LIBRARY"));
+}
+
+
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/wizards/qtprojectparameters.h b/src/plugins/qt4projectmanager/wizards/qtprojectparameters.h
new file mode 100644
index 0000000000..94b0988183
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/qtprojectparameters.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTPROJECTPARAMETERS_H
+#define QTPROJECTPARAMETERS_H
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+// Create a macro name by taking a file name, upper casing it and
+// appending a suffix.
+QString createMacro(const QString &name, const QString &suffix);
+
+// Base parameters for application project generation with functionality to
+// write a .pro-file section.
+
+struct QtProjectParameters {
+ enum Type { ConsoleApp, GuiApp, StaticLibrary, SharedLibrary, Qt4Plugin };
+
+ QtProjectParameters();
+ // Return project path as "path/name"
+ QString projectPath() const;
+ void writeProFile(QTextStream &) const;
+ static void writeProFileHeader(QTextStream &);
+
+ // Shared library: Name of export macro (XXX_EXPORT)
+ static QString exportMacro(const QString &projectName);
+ // Shared library: name of #define indicating compilation within library
+ static QString libraryMacro(const QString &projectName);
+
+ Type type;
+ QString name;
+ QString path;
+ QString selectedModules;
+ QString deselectedModules;
+ QString targetDirectory;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // QTPROJECTPARAMETERS_H
diff --git a/src/plugins/qt4projectmanager/wizards/qtwizard.cpp b/src/plugins/qt4projectmanager/wizards/qtwizard.cpp
new file mode 100644
index 0000000000..0788caab04
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/qtwizard.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtwizard.h"
+#include "qt4project.h"
+#include "qt4projectmanagerconstants.h"
+
+#include <projectexplorer/projectexplorer.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+
+using namespace Qt4ProjectManager;
+using namespace Qt4ProjectManager::Internal;
+
+static inline Core::BaseFileWizardParameters
+ wizardParameters(const QString &name,
+ const QString &description,
+ const QIcon &icon)
+{
+ Core::BaseFileWizardParameters rc(Core::IWizard::ProjectWizard);
+ rc.setCategory(QLatin1String("Projects"));
+ rc.setTrCategory("Projects");
+ rc.setIcon(icon);
+ rc.setName(name);
+ rc.setDescription(description);
+ return rc;
+}
+
+// -------------------- QtWizard
+QtWizard::QtWizard(Core::ICore *core, const QString &name,
+ const QString &description, const QIcon &icon) :
+ Core::BaseFileWizard(wizardParameters(name, description, icon), core),
+ m_projectExplorer(ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>())
+{
+}
+
+QString QtWizard::sourceSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::CPP_SOURCE_MIMETYPE));
+}
+
+QString QtWizard::headerSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::CPP_HEADER_MIMETYPE));
+}
+
+QString QtWizard::formSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::FORM_MIMETYPE));
+}
+
+QString QtWizard::profileSuffix() const
+{
+ return preferredSuffix(QLatin1String(Constants::PROFILE_MIMETYPE));
+}
+
+bool QtWizard::postGenerateFiles(const Core::GeneratedFiles &l, QString *errorMessage)
+{
+ // Post-Generate: Open the project
+ const QString proFileName = l.back().path();
+ if (!m_projectExplorer->openProject(proFileName)) {
+ *errorMessage = tr("The project %1 could not be opened.").arg(proFileName);
+ return false;
+ }
+ return true;
+}
+
+QString QtWizard::templateDir() const
+{
+ QString rc = core()->resourcePath();
+ rc += QLatin1String("/templates/qt4project");
+ return rc;
+}
diff --git a/src/plugins/qt4projectmanager/wizards/qtwizard.h b/src/plugins/qt4projectmanager/wizards/qtwizard.h
new file mode 100644
index 0000000000..7b74f1381a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/qtwizard.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTWIZARD_H
+#define QTWIZARD_H
+
+#include "qtprojectparameters.h"
+
+#include <coreplugin/basefilewizard.h>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+class QDir;
+QT_END_NAMESPACE
+
+namespace ProjectExplorer {
+ class ProjectExplorerPlugin;
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+/* Base class for wizard creating Qt projects using QtProjectParameters.
+ * To implement a project wizard, overwrite:
+ * - createWizardDialog() to create up the dialog
+ * - generateFiles() to set their contents
+ * The base implementation provides the wizard parameters and opens
+ * and opens the finished project in postGenerateFiles().
+ * The pro-file must be the last one of the generated files. */
+
+class QtWizard : public Core::BaseFileWizard
+{
+ Q_DISABLE_COPY(QtWizard)
+ Q_OBJECT
+
+public:
+
+protected:
+ explicit QtWizard(Core::ICore *core, const QString &name,
+ const QString &description, const QIcon &icon);
+
+ QString templateDir() const;
+
+ QString sourceSuffix() const;
+ QString headerSuffix() const;
+ QString formSuffix() const;
+ QString profileSuffix() const;
+
+private:
+ bool postGenerateFiles(const Core::GeneratedFiles &l, QString *errorMessage);
+
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // QTWIZARD_H
diff --git a/src/plugins/qt4projectmanager/wizards/wizards.qrc b/src/plugins/qt4projectmanager/wizards/wizards.qrc
new file mode 100644
index 0000000000..e463369009
--- /dev/null
+++ b/src/plugins/qt4projectmanager/wizards/wizards.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/wizards" >
+ <file>images/console.png</file>
+ <file>images/gui.png</file>
+ <file>images/lib.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/qtestlib/QTestLibPlugin.qwp b/src/plugins/qtestlib/QTestLibPlugin.qwp
new file mode 100644
index 0000000000..d48704e276
--- /dev/null
+++ b/src/plugins/qtestlib/QTestLibPlugin.qwp
@@ -0,0 +1,16 @@
+<!DOCTYPE QtWorkbenchManifest>
+<qwp>
+ <pluginName>QTestLibPlugin</pluginName>
+ <author>Trolltech</author>
+ <requiredPluginList>
+ <requiredPlugin>
+ <name>ProjectExplorer</name>
+ <provider></provider>
+ </requiredPlugin>
+ </requiredPluginList>
+ <extendsInterfaceList>
+ <extendsInterface>
+ <name>Core::OutputPaneInterface</name>
+ </extendsInterface>
+ </extendsInterfaceList>
+</qwp>
diff --git a/src/plugins/qtestlib/images/pass.png b/src/plugins/qtestlib/images/pass.png
new file mode 100644
index 0000000000..b5238f7680
--- /dev/null
+++ b/src/plugins/qtestlib/images/pass.png
Binary files differ
diff --git a/src/plugins/qtestlib/qtestlib.pro b/src/plugins/qtestlib/qtestlib.pro
new file mode 100644
index 0000000000..5031b1d6b4
--- /dev/null
+++ b/src/plugins/qtestlib/qtestlib.pro
@@ -0,0 +1,14 @@
+TEMPLATE = lib
+TARGET = QTestLibPlugin
+QT += xml
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+
+SOURCES += qtestlibplugin.cpp
+HEADERS += qtestlibplugin.h
+RESOURCES += qtestlib.qrc
+
+LIBS += -lProjectExplorer \
+ -lQuickOpen \
+ -lUtils
diff --git a/src/plugins/qtestlib/qtestlib.qrc b/src/plugins/qtestlib/qtestlib.qrc
new file mode 100644
index 0000000000..fc0610e954
--- /dev/null
+++ b/src/plugins/qtestlib/qtestlib.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/Trolltech/QTestLibPlugin">
+ <file>images/pass.png</file>
+</qresource>
+</RCC>
diff --git a/src/plugins/qtestlib/qtestlibplugin.cpp b/src/plugins/qtestlib/qtestlibplugin.cpp
new file mode 100644
index 0000000000..d32c36467e
--- /dev/null
+++ b/src/plugins/qtestlib/qtestlibplugin.cpp
@@ -0,0 +1,501 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtestlibplugin.h"
+
+#include <QtCore/qplugin.h>
+#include <QIcon>
+#include <QDebug>
+#include <QKeySequence>
+#include <QAction>
+#include <QHeaderView>
+#include <QDomDocument>
+#include <QTemporaryFile>
+#include <texteditor/TextEditorInterfaces>
+#include <Qt4IProjectManagers>
+#include <QFileInfo>
+#include <QDir>
+#include <QStandardItemModel>
+#include <QTreeView>
+#include <QTextEdit>
+#include <QSplitter>
+#include <QVBoxLayout>
+#include <QComboBox>
+#include <QLabel>
+
+using namespace QTestLib::Internal;
+
+static QString incidentString(QTestFunction::IncidentType type)
+{
+ static QMap<QTestFunction::IncidentType, QString> strings;
+ if (strings.empty()) {
+ strings.insert(QTestFunction::Pass, QObject::tr("Pass"));
+ strings.insert(QTestFunction::XFail, QObject::tr("Expected Failure"));
+ strings.insert(QTestFunction::Fail, QObject::tr("Failure"));
+ strings.insert(QTestFunction::XPass, QObject::tr("Expected Pass"));
+ }
+ return strings.value(type, QString());
+}
+
+static QString messageString(QTestFunction::MessageType type)
+{
+ static QMap<QTestFunction::MessageType, QString> strings;
+ if (strings.empty()) {
+ strings.insert(QTestFunction::Warning, QObject::tr("Warning"));
+ strings.insert(QTestFunction::QWarning, QObject::tr("Qt Warning"));
+ strings.insert(QTestFunction::QDebug, QObject::tr("Qt Debug"));
+ strings.insert(QTestFunction::QSystem, QObject::tr("Critical"));
+ strings.insert(QTestFunction::QFatal, QObject::tr("Fatal"));
+ strings.insert(QTestFunction::Skip, QObject::tr("Skipped"));
+ strings.insert(QTestFunction::Info, QObject::tr("Info"));
+ }
+ return strings.value(type, QString());
+}
+
+static QTestFunction::IncidentType stringToIncident(const QString &str)
+{
+ if (str == QLatin1String("pass"))
+ return QTestFunction::Pass;
+ else if (str == QLatin1String("fail"))
+ return QTestFunction::Fail;
+ else if (str == QLatin1String("xfail"))
+ return QTestFunction::XFail;
+ else if (str == QLatin1String("xpass"))
+ return QTestFunction::XPass;
+ return QTestFunction::Fail; // ...
+}
+
+static QTestFunction::MessageType stringToMessageType(const QString &str)
+{
+ if (str == QLatin1String("warn"))
+ return QTestFunction::Warning;
+ else if (str == QLatin1String("system"))
+ return QTestFunction::QSystem;
+ else if (str == QLatin1String("qdebug"))
+ return QTestFunction::QDebug;
+ else if (str == QLatin1String("qwarn"))
+ return QTestFunction::QWarning;
+ else if (str == QLatin1String("qfatal"))
+ return QTestFunction::QFatal;
+ else if (str == QLatin1String("skip"))
+ return QTestFunction::Skip;
+ else if (str == QLatin1String("info"))
+ return QTestFunction::Info;
+ return QTestFunction::QSystem; // ...
+}
+
+// -----------------------------------
+QTestLibPlugin::QTestLibPlugin() :
+ m_projectExplorer(0),
+ m_core(0),
+ m_outputPane(0)
+{
+}
+
+QTestLibPlugin::~QTestLibPlugin()
+{
+ if (m_core && m_outputPane)
+ m_core->pluginManager()->removeObject(m_outputPane);
+}
+
+bool QTestLibPlugin::init(ExtensionSystem::PluginManagerInterface *app, QString * /*error_message*/)
+{
+ m_core = app->getObject<Core::ICore>();
+
+ m_projectExplorer = app->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+ connect(m_projectExplorer->qObject(), SIGNAL(aboutToExecuteProject(ProjectExplorer::Project *)),
+ this, SLOT(projectRunHook(ProjectExplorer::Project *)));
+
+ m_outputPane = new QTestOutputPane(this);
+ app->addObject(m_outputPane);
+
+ return true;
+}
+
+void QTestLibPlugin::extensionsInitialized()
+{
+}
+
+void QTestLibPlugin::projectRunHook(ProjectExplorer::Project *proj)
+{
+ return; //NBS TODO QTestlibplugin
+ if (!proj)
+ return;
+
+ m_projectDirectory = QString();
+ //NBS proj->setExtraApplicationRunArguments(QStringList());
+ //NBS proj->setCustomApplicationOutputHandler(0);
+
+ const QVariant config; //NBS = proj->projectProperty(ProjectExplorer::Constants::P_CONFIGVAR);
+ if (!config.toStringList().contains(QLatin1String("qtestlib")))
+ return;
+
+ {
+ QTemporaryFile tempFile;
+ tempFile.setAutoRemove(false);
+ tempFile.open();
+ m_outputFile = tempFile.fileName();
+ }
+
+ //NBS proj->setCustomApplicationOutputHandler(this);
+ //NBS proj->setExtraApplicationRunArguments(QStringList() << QLatin1String("-xml") << QLatin1String("-o") << m_outputFile);
+ const QString proFile = proj->fileName();
+ const QFileInfo fi(proFile);
+ if (QFile::exists(fi.absolutePath()))
+ m_projectDirectory = fi.absolutePath();
+}
+
+void QTestLibPlugin::clear()
+{
+ m_projectExplorer->applicationOutputWindow()->clear();
+}
+
+void QTestLibPlugin::appendOutput(const QString &out)
+{
+ m_projectExplorer->applicationOutputWindow()->appendOutput(out);
+}
+
+void QTestLibPlugin::processExited(int exitCode)
+{
+ m_projectExplorer->applicationOutputWindow()->processExited(exitCode);
+
+ QFile f(m_outputFile);
+ if (!f.open(QIODevice::ReadOnly))
+ return;
+
+ QDomDocument doc;
+ if (!doc.setContent(&f))
+ return;
+
+ f.close();
+ f.remove();
+
+ m_outputPane->clearContents();
+
+ const QString testFunctionTag = QLatin1String("TestFunction");
+ const QString nameAttr = QLatin1String("name");
+ const QString typeAttr = QLatin1String("type");
+ const QString incidentTag = QLatin1String("Incident");
+ const QString fileAttr = QLatin1String("file");
+ const QString lineAttr = QLatin1String("line");
+ const QString messageTag = QLatin1String("Message");
+ const QString descriptionItem = QLatin1String("Description");
+
+ for (QDomElement testElement = doc.documentElement().firstChildElement();
+ !testElement.isNull(); testElement = testElement.nextSiblingElement()) {
+
+ if (testElement.tagName() != testFunctionTag)
+ continue;
+
+ QTestFunction *function = new QTestFunction(testElement.attribute(nameAttr));
+
+ for (QDomElement e = testElement.firstChildElement();
+ !e.isNull(); e = e.nextSiblingElement()) {
+
+ const QString type = e.attribute(typeAttr);
+
+ if (e.tagName() == incidentTag) {
+ QString file = e.attribute(fileAttr);
+
+ if (!file.isEmpty()
+ && QFileInfo(file).isRelative()
+ && !m_projectDirectory.isEmpty()) {
+
+ QFileInfo fi(m_projectDirectory, file);
+ if (fi.exists())
+ file = fi.absoluteFilePath();
+ }
+
+ const QString line = e.attribute(lineAttr);
+ const QString details = e.text();
+
+ QTestFunction::IncidentType itype = stringToIncident(type);
+ function->addIncident(itype, file, line, details);
+ } else if (e.tagName() == messageTag ) {
+ QTestFunction::MessageType msgType = stringToMessageType(type);
+ function->addMessage(msgType, e.namedItem(descriptionItem).toElement().text());
+ }
+ }
+
+ m_outputPane->addFunction(function);
+ }
+
+ m_outputPane->show();
+}
+
+// -------- QTestFunction
+void QTestFunction::addIncident(IncidentType type,
+ const QString &file,
+ const QString &line,
+ const QString &details)
+{
+ QStandardItem *status = new QStandardItem(incidentString(type));
+ status->setData(QVariant::fromValue(type));
+
+ switch (type) {
+ case QTestFunction::Pass: status->setForeground(Qt::green); break;
+ case QTestFunction::Fail: status->setForeground(Qt::red); break;
+ case QTestFunction::XFail: status->setForeground(Qt::darkMagenta); break;
+ case QTestFunction::XPass: status->setForeground(Qt::darkGreen); break;
+ }
+
+ QStandardItem *location = new QStandardItem;
+ if (!file.isEmpty()) {
+ location->setText(file + QLatin1Char(':') + line);
+ location->setForeground(Qt::red);
+
+ QTestLocation loc;
+ loc.file = file;
+ loc.line = line;
+ location->setData(QVariant::fromValue(loc));
+ }
+
+ appendRow(QList<QStandardItem *>() << status << location);
+
+ if (!details.isEmpty()) {
+ status->setColumnCount(2);
+ status->appendRow(QList<QStandardItem *>() << new QStandardItem() << new QStandardItem(details));
+ }
+}
+
+void QTestFunction::addMessage(MessageType type, const QString &text)
+{
+ QStandardItem *status = new QStandardItem(messageString(type));
+ status->setData(QVariant::fromValue(type));
+ QStandardItem *msg = new QStandardItem(text);
+ appendRow(QList<QStandardItem *>() << status << msg);
+}
+
+bool QTestFunction::indexHasIncidents(const QModelIndex &function, IncidentType type)
+{
+ if (!function.isValid())
+ return false;
+ const QAbstractItemModel *m = function.model();
+ if (!m->hasChildren(function))
+ return false;
+
+ const int rows = m->rowCount(function);
+ for (int row = 0; row < rows; ++row) {
+ const QModelIndex child = m->index(row, 0, function);
+
+ QVariant tag = child.data(Qt::UserRole + 1);
+ if (tag.type() != QVariant::UserType
+ || tag.userType() != qMetaTypeId<QTestFunction::IncidentType>())
+ continue;
+
+ if (tag.value<QTestFunction::IncidentType>() == type)
+ return true;
+ }
+
+ return false;
+}
+// -------------- QTestOutputPane
+QTestOutputPane::QTestOutputPane(QTestLibPlugin *plugin) :
+ QObject(plugin),
+ m_plugin(plugin),
+ m_widget(0),
+ m_model(new QStandardItemModel(this))
+{
+ clearContents();
+}
+
+void QTestOutputPane::addFunction(QTestFunction *function)
+{
+ m_model->appendRow(function);
+}
+
+QWidget *QTestOutputPane::outputWidget(QWidget *parent)
+{
+ if (!m_widget)
+ m_widget = new QTestOutputWidget(m_model, m_plugin->coreInterface(), parent);
+ return m_widget;
+}
+
+QString QTestOutputPane::name() const
+{
+ return tr("Test Results");
+}
+
+void QTestOutputPane::clearContents()
+{
+ m_model->clear();
+ m_model->setColumnCount(2);
+ m_model->setHorizontalHeaderLabels(QStringList() << tr("Result") << tr("Message"));
+}
+
+void QTestOutputPane::visibilityChanged(bool visible)
+{
+ Q_UNUSED(visible)
+}
+
+void QTestOutputPane::show()
+{
+ if (m_widget)
+ m_widget->expand();
+ emit showPage();
+}
+
+// -------- QTestOutputFilter
+bool QTestOutputFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ if (sourceParent.isValid()) {
+ return true;
+ }
+
+ QModelIndex idx = sourceModel()->index(sourceRow, 0);
+ if (QTestFunction::indexHasIncidents(idx, m_filter))
+ return true;
+ else
+ return false;
+}
+
+// ------- QTestOutputWidget
+
+
+QTestOutputWidget::QTestOutputWidget(QStandardItemModel *model, Core::ICore *coreInterface, QWidget *parent):
+ QWidget(parent),
+ m_coreInterface(coreInterface),
+ m_model(model),
+ m_resultsView(new QTreeView(this)),
+ m_filterCombo(new QComboBox(this)),
+ m_filterModel(new QTestOutputFilter(this))
+{
+ m_resultsView->setModel(model);
+ m_resultsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_resultsView->header()->setStretchLastSection(true);
+ connect(m_resultsView, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(gotoLocation(QModelIndex)));
+
+ m_filterCombo->addItem(tr("All Incidents"));
+ m_filterCombo->addItem(incidentString(QTestFunction::Fail), QVariant::fromValue(QTestFunction::Fail));
+ m_filterCombo->addItem(incidentString(QTestFunction::Pass), QVariant::fromValue(QTestFunction::Pass));
+ m_filterCombo->addItem(incidentString(QTestFunction::XFail), QVariant::fromValue(QTestFunction::XFail));
+ m_filterCombo->addItem(incidentString(QTestFunction::XPass), QVariant::fromValue(QTestFunction::XPass));
+ connect(m_filterCombo, SIGNAL(activated(int)),
+ this, SLOT(activateComboFilter(int)));
+
+ QHBoxLayout *filterLayout = new QHBoxLayout;
+ filterLayout->addWidget(new QLabel(tr("Show Only:"), this));
+ filterLayout->addWidget(m_filterCombo);
+ filterLayout->addStretch();
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addLayout(filterLayout);
+ layout->addWidget(m_resultsView);
+
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->setSourceModel(m_model);
+}
+
+void QTestOutputWidget::expand()
+{
+ /*
+ const QAbstractItemModel *m = m_resultsView->model();
+ for (int r = 0, count = m->rowCount(); r < count; ++r) {
+ m_resultsView->expand(m->index(r, 0));
+ }
+ */
+ m_resultsView->expandAll();
+ m_resultsView->header()->resizeSections(QHeaderView::ResizeToContents);
+}
+
+void QTestOutputWidget::activateComboFilter(int index)
+{
+ QVariant tag = m_filterCombo->itemData(index);
+ if (!tag.isValid()) {
+ if (m_resultsView->model() != m_model)
+ m_resultsView->setModel(m_model);
+ } else {
+
+ QTestFunction::IncidentType incident = tag.value<QTestFunction::IncidentType>();
+ m_filterModel->setIncidentFilter(incident);
+
+ if (m_resultsView->model() != m_filterModel)
+ m_resultsView->setModel(m_filterModel);
+ }
+ expand();
+}
+
+void QTestOutputWidget::gotoLocation(QModelIndex index)
+{
+ if (!index.isValid())
+ return;
+
+ if (m_resultsView->model() == m_filterModel)
+ index = m_filterModel->mapToSource(index);
+
+ if (!index.isValid())
+ return;
+
+ const QAbstractItemModel *m = index.model();
+
+ QModelIndex parent = index.parent();
+ if (!parent.isValid())
+ return;
+
+ QModelIndex functionIndex = parent;
+ QModelIndex failureIndex = index;
+
+ QModelIndex grandParent = parent.parent();
+ if (grandParent.isValid()) {
+ functionIndex = grandParent;
+ failureIndex = parent;
+ }
+
+ if (!functionIndex.isValid())
+ return;
+
+ QModelIndex locationIndex = m->index(failureIndex.row(), 1, functionIndex);
+ if (!locationIndex.isValid())
+ return;
+
+ QVariant tag = locationIndex.data(Qt::UserRole + 1);
+ if (tag.type() != QVariant::UserType
+ || tag.userType() != qMetaTypeId<QTestLocation>())
+ return;
+
+ QTestLocation loc = tag.value<QTestLocation>();
+
+ m_coreInterface->editorManager()->openEditor(loc.file);
+ Core::EditorInterface *edtIface = m_coreInterface->editorManager()->currentEditor();
+ if (!edtIface)
+ return;
+ TextEditor::ITextEditor *editor =
+ qobject_cast<TextEditor::ITextEditor*>(edtIface->qObject());
+ if (!editor)
+ return;
+
+ editor->gotoLine(loc.line.toInt());
+}
+
+Q_EXPORT_PLUGIN(QTestLibPlugin)
diff --git a/src/plugins/qtestlib/qtestlibplugin.h b/src/plugins/qtestlib/qtestlibplugin.h
new file mode 100644
index 0000000000..dacd011520
--- /dev/null
+++ b/src/plugins/qtestlib/qtestlibplugin.h
@@ -0,0 +1,209 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTESTLIBPLUGIN_H
+#define QTESTLIBPLUGIN_H
+
+#include <coreplugin/ioutputpane.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <QPixmap>
+#include <QStandardItem>
+#include <QWidget>
+#include <QSortFilterProxyModel>
+
+class QStandardItemModel;
+class QTreeView;
+class QTextEdit;
+class QComboBox;
+
+namespace QTestLib {
+namespace Internal {
+
+class QTestLibPlugin;
+class QTestOutputWidget;
+
+struct QTestLocation
+{
+ QString file;
+ QString line;
+};
+
+class QTestFunction : public QStandardItem
+{
+public:
+ enum IncidentType {
+ Pass,
+ XFail,
+ Fail,
+ XPass
+ };
+
+ enum MessageType {
+ Warning,
+ QWarning,
+ QDebug,
+ QSystem,
+ QFatal,
+ Skip,
+ Info
+ };
+
+ inline QTestFunction(const QString &name)
+ : QStandardItem(name) {
+ setColumnCount(2);
+ // ### hardcoding colors sucks...
+ setForeground(Qt::darkBlue);
+ }
+
+ void addIncident(IncidentType type,
+ const QString &file = QString(),
+ const QString &line = QString(),
+ const QString &details = QString());
+
+ void addMessage(MessageType type, const QString &text);
+
+ static bool indexHasIncidents(const QModelIndex &function, IncidentType type);
+};
+
+class QTestOutputPane : public QObject,
+ public Core::IOutputPane
+{
+ Q_OBJECT
+ Q_INTERFACES(Core::IOutputPane)
+public:
+ QTestOutputPane(QTestLibPlugin *plugin);
+
+ void addFunction(QTestFunction *function);
+
+ virtual QWidget *outputWidget(QWidget *parent);
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+ virtual QString name() const;
+
+ virtual void clearContents();
+ virtual void visibilityChanged(bool visible);
+
+ void show();
+
+Q_SIGNALS:
+//signals
+ void showPage();
+
+private:
+ QTestLibPlugin *m_plugin;
+ QTestOutputWidget *m_widget;
+ QStandardItemModel *m_model;
+};
+
+class QTestOutputFilter : public QSortFilterProxyModel
+{
+public:
+ inline QTestOutputFilter(QObject *parent)
+ : QSortFilterProxyModel(parent), m_filter(QTestFunction::Fail)
+ {}
+
+ inline void setIncidentFilter(QTestFunction::IncidentType incident) {
+ m_filter = incident;
+ filterChanged();
+ }
+
+protected:
+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
+private:
+ QTestFunction::IncidentType m_filter;
+};
+
+class QTestOutputWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QTestOutputWidget(QStandardItemModel *model,
+ Core::ICore *iCore,
+ QWidget *parent);
+
+ void expand();
+
+private Q_SLOTS:
+ void activateComboFilter(int index);
+ void gotoLocation(QModelIndex index);
+
+private:
+ Core::ICore *m_coreInterface;
+ QStandardItemModel *m_model;
+ QTreeView *m_resultsView;
+ QComboBox *m_filterCombo;
+ QTestOutputFilter *m_filterModel;
+};
+
+class QTestLibPlugin : public QObject,
+ public ExtensionSystem::PluginInterface,
+ public ProjectExplorer::IApplicationOutput
+{
+ Q_OBJECT
+ Q_INTERFACES(ExtensionSystem::PluginInterface
+ ProjectExplorer::IApplicationOutput)
+
+public:
+ QTestLibPlugin();
+ virtual ~QTestLibPlugin();
+
+ bool init(ExtensionSystem::PluginManagerInterface *app, QString *error_message);
+ void extensionsInitialized();
+
+ inline Core::ICore *coreInterface() const {
+ return m_core;
+ }
+
+ // IApplicationOutput
+ virtual void clear();
+ virtual void appendOutput(const QString &out);
+ virtual void processExited(int exitCode);
+
+private slots:
+ void projectRunHook(ProjectExplorer::Project *project);
+
+private:
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ Core::ICore *m_core;
+ QString m_outputFile;
+ QString m_projectDirectory;
+ QTestOutputPane *m_outputPane;
+};
+
+} // namespace Internal
+} // namespace QTestLibPlugin
+
+Q_DECLARE_METATYPE(QTestLib::Internal::QTestLocation)
+Q_DECLARE_METATYPE(QTestLib::Internal::QTestFunction::IncidentType)
+Q_DECLARE_METATYPE(QTestLib::Internal::QTestFunction::MessageType)
+
+#endif // QTESTLIBPLUGIN_H
diff --git a/src/plugins/qtscripteditor/QtScriptEditor.mimetypes.xml b/src/plugins/qtscripteditor/QtScriptEditor.mimetypes.xml
new file mode 100644
index 0000000000..45f6c0b00b
--- /dev/null
+++ b/src/plugins/qtscripteditor/QtScriptEditor.mimetypes.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/javascript">
+ <alias type="application/x-javascript"/>
+ <alias type="text/javascript"/>
+ <sub-class-of type="text/plain"/>
+ <comment>Qt Script file</comment>
+ <comment xml:lang="bg">Програма на JavaScript</comment>
+ <comment xml:lang="ca">programa JavaScript</comment>
+ <comment xml:lang="cs">Program v JavaScriptu</comment>
+ <comment xml:lang="da">JavaScript-program</comment>
+ <comment xml:lang="de">JavaScript-Programm</comment>
+ <comment xml:lang="el">Ï€ÏόγÏαμμα JavaScript</comment>
+ <comment xml:lang="eo">JavaScript-programo</comment>
+ <comment xml:lang="es">programa en JavaScript</comment>
+ <comment xml:lang="eu">JavaScript programa</comment>
+ <comment xml:lang="fi">JavaScript-ohjelma</comment>
+ <comment xml:lang="fr">programme JavaScript</comment>
+ <comment xml:lang="hu">JavaScript-program</comment>
+ <comment xml:lang="it">Programma JavaScript</comment>
+ <comment xml:lang="ja">JavaScript プログラム</comment>
+ <comment xml:lang="ko">ìžë°”스í¬ë¦½íŠ¸ 프로그램</comment>
+ <comment xml:lang="lt">JavaScript programa</comment>
+ <comment xml:lang="ms">Program JavaScript</comment>
+ <comment xml:lang="nb">JavaScript-program</comment>
+ <comment xml:lang="nl">JavaScript-programma</comment>
+ <comment xml:lang="nn">JavaScript-program</comment>
+ <comment xml:lang="pl">Pogram JavaScript</comment>
+ <comment xml:lang="pt">programa JavaScript</comment>
+ <comment xml:lang="pt_BR">Programa JavaScript</comment>
+ <comment xml:lang="ru">программа JavaScript</comment>
+ <comment xml:lang="sq">program JavaScript</comment>
+ <comment xml:lang="sr">ЈаваÑкрипт програм</comment>
+ <comment xml:lang="sv">JavaScript-program</comment>
+ <comment xml:lang="uk">Програма на мові JavaScript</comment>
+ <comment xml:lang="vi">Chương trình JavaScript</comment>
+ <comment xml:lang="zh_CN">JavaScript 程åº</comment>
+ <comment xml:lang="zh_TW">JavaScript 程å¼</comment>
+ <glob pattern="*.js"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/qtscripteditor/QtScriptEditor.pluginspec b/src/plugins/qtscripteditor/QtScriptEditor.pluginspec
new file mode 100644
index 0000000000..3e70cf5568
--- /dev/null
+++ b/src/plugins/qtscripteditor/QtScriptEditor.pluginspec
@@ -0,0 +1,11 @@
+<plugin name="QtScriptEditor" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Editor for QtScript.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="TextEditor" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/qtscripteditor/qtscripteditor.cpp b/src/plugins/qtscripteditor/qtscripteditor.cpp
new file mode 100644
index 0000000000..d72fc1f631
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditor.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtscripteditor.h"
+#include "qtscripteditorconstants.h"
+#include "qtscripthighlighter.h"
+#include "qtscripteditorplugin.h"
+
+#include <indenter.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <texteditor/basetextdocument.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/textblockiterator.h>
+#include <texteditor/texteditorconstants.h>
+
+#include <QtGui/QMenu>
+
+namespace QtScriptEditor {
+namespace Internal {
+
+ScriptEditorEditable::ScriptEditorEditable(ScriptEditor *editor, const QList<int>& context)
+ : BaseTextEditorEditable(editor), m_context(context)
+{
+
+}
+
+ScriptEditor::ScriptEditor(const Context &context,
+ Core::ICore *core,
+ TextEditor::TextEditorActionHandler *ah,
+ QWidget *parent) :
+ TextEditor::BaseTextEditor(parent),
+ m_context(context),
+ m_core(core),
+ m_ah(ah)
+{
+ setParenthesesMatchingEnabled(true);
+ setMarksVisible(true);
+ setCodeFoldingVisible(true);
+ setMimeType(QtScriptEditor::Constants::C_QTSCRIPTEDITOR_MIMETYPE);
+
+ baseTextDocument()->setSyntaxHighlighter(new QtScriptHighlighter);
+}
+
+ScriptEditor::~ScriptEditor()
+{
+}
+
+Core::IEditor *ScriptEditorEditable::duplicate(QWidget *parent)
+{
+ return qobject_cast<ScriptEditor*>(editor())->duplicate(parent)->editableInterface();
+}
+
+ScriptEditor *ScriptEditor::duplicate(QWidget *parent)
+{
+ ScriptEditor *editor = new ScriptEditor(m_context, m_core, m_ah, parent);
+ editor->duplicateFrom(this);
+ QtScriptEditorPlugin::initializeEditor(editor);
+ return editor;
+}
+
+const char *ScriptEditorEditable::kind() const
+{
+ return QtScriptEditor::Constants::C_QTSCRIPTEDITOR;
+}
+
+ScriptEditor::Context ScriptEditorEditable::context() const
+{
+ return m_context;
+}
+
+void ScriptEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ TextEditor::BaseTextEditor::setFontSettings(fs);
+ QtScriptHighlighter *highlighter = qobject_cast<QtScriptHighlighter*>(baseTextDocument()->syntaxHighlighter());
+ if (!highlighter)
+ return;
+
+ static QVector<QString> categories;
+ if (categories.isEmpty()) {
+ categories << QLatin1String(TextEditor::Constants::C_NUMBER)
+ << QLatin1String(TextEditor::Constants::C_STRING)
+ << QLatin1String(TextEditor::Constants::C_TYPE)
+ << QLatin1String(TextEditor::Constants::C_KEYWORD)
+ << QLatin1String(TextEditor::Constants::C_PREPROCESSOR)
+ << QLatin1String(TextEditor::Constants::C_LABEL)
+ << QLatin1String(TextEditor::Constants::C_COMMENT);
+ }
+
+ highlighter->setFormats(fs.toTextCharFormats(categories));
+ highlighter->rehighlight();
+}
+
+bool ScriptEditor::isElectricCharacter(const QChar &ch) const
+{
+ if (ch == QLatin1Char('{') || ch == QLatin1Char('}'))
+ return true;
+ return false;
+}
+
+ // Indent a code line based on previous
+template <class Iterator>
+static void indentScriptBlock(const TextEditor::TabSettings &ts,
+ const QTextBlock &block,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedChar)
+{
+ typedef typename SharedTools::Indenter<Iterator> Indenter ;
+ Indenter &indenter = Indenter::instance();
+ indenter.setIndentSize(ts.m_tabSize);
+ const TextEditor::TextBlockIterator current(block);
+ const int indent = indenter.indentForBottomLine(current, programBegin,
+ programEnd, typedChar);
+ ts.indentLine(block, indent);
+}
+
+void ScriptEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+{
+ const TextEditor::TextBlockIterator begin(doc->begin());
+ const TextEditor::TextBlockIterator end(block.next());
+ indentScriptBlock(tabSettings(), block, begin, end, typedChar);
+}
+
+void ScriptEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+ QMenu *menu = createStandardContextMenu();
+
+ if (Core::IActionContainer *mcontext = m_core->actionManager()->actionContainer(QtScriptEditor::Constants::M_CONTEXT)) {
+ QMenu *contextMenu = mcontext->menu();
+ foreach(QAction *action, contextMenu->actions()) {
+ menu->addAction(action);
+ }
+ }
+
+ menu->exec(e->globalPos());
+ delete menu;
+
+}
+
+} // namespace Internal
+} // namespace QtScriptEditor
diff --git a/src/plugins/qtscripteditor/qtscripteditor.h b/src/plugins/qtscripteditor/qtscripteditor.h
new file mode 100644
index 0000000000..f005da2af7
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditor.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTSCRIPTDITORW_H
+#define QTSCRIPTDITORW_H
+
+#include <texteditor/basetexteditor.h>
+
+namespace Core {
+ class ICore;
+}
+
+namespace QtScriptEditor {
+namespace Internal {
+
+class QtScriptHighlighter;
+
+class ScriptEditor;
+
+class ScriptEditorEditable : public TextEditor::BaseTextEditorEditable
+{
+public:
+ ScriptEditorEditable(ScriptEditor *, const QList<int>&);
+ QList<int> context() const;
+
+ bool duplicateSupported() const { return true; }
+ Core::IEditor *duplicate(QWidget *parent);
+ const char *kind() const;
+ QToolBar *toolBar() { return 0; }
+
+private:
+ QList<int> m_context;
+};
+
+
+class ScriptEditor : public TextEditor::BaseTextEditor
+{
+ Q_OBJECT
+
+public:
+ typedef QList<int> Context;
+
+ ScriptEditor(const Context &context,
+ Core::ICore *core,
+ TextEditor::TextEditorActionHandler *ah,
+ QWidget *parent = 0);
+ ~ScriptEditor();
+
+ ScriptEditor *duplicate(QWidget *parent);
+
+public slots:
+ virtual void setFontSettings(const TextEditor::FontSettings &);
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *e);
+ TextEditor::BaseTextEditorEditable *createEditableInterface() { return new ScriptEditorEditable(this, m_context); }
+
+private:
+ virtual bool isElectricCharacter(const QChar &ch) const;
+ virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+
+ const Context m_context;
+ Core::ICore *m_core;
+ TextEditor::TextEditorActionHandler *m_ah;
+};
+
+} // namespace Internal
+} // namespace QtScriptEditor
+
+#endif // QTSCRIPTDITORW_H
diff --git a/src/plugins/qtscripteditor/qtscripteditor.pro b/src/plugins/qtscripteditor/qtscripteditor.pro
new file mode 100644
index 0000000000..1e93663ec4
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditor.pro
@@ -0,0 +1,22 @@
+TEMPLATE = lib
+TARGET = QtScriptEditor
+QT += script
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../../shared/qscripthighlighter/qscripthighlighter.pri)
+include(../../../shared/indenter/indenter.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+
+HEADERS += qtscripteditor.h \
+qtscripteditorfactory.h \
+qtscripteditorplugin.h \
+qtscripthighlighter.h \
+qtscripteditoractionhandler.h
+
+SOURCES += qtscripteditor.cpp \
+qtscripteditorfactory.cpp \
+qtscripteditorplugin.cpp \
+qtscripthighlighter.cpp \
+qtscripteditoractionhandler.cpp
+RESOURCES += qtscripteditor.qrc
diff --git a/src/plugins/qtscripteditor/qtscripteditor.qrc b/src/plugins/qtscripteditor/qtscripteditor.qrc
new file mode 100644
index 0000000000..1e987b5a4a
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditor.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/qtscripteditor" >
+ <file>QtScriptEditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/qtscripteditor/qtscripteditoractionhandler.cpp b/src/plugins/qtscripteditor/qtscripteditoractionhandler.cpp
new file mode 100644
index 0000000000..9fd78777c1
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditoractionhandler.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtscripteditoractionhandler.h"
+#include "qtscripteditorconstants.h"
+#include "qtscripteditor.h"
+
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/scriptmanager/scriptmanagerinterface.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtCore/QDebug>
+
+static QAction *actionFromId(Core::ICore *core, const QString &id)
+{
+ Core::ICommand *cmd = core->actionManager()->command(id);
+ if (!cmd)
+ return 0;
+ return cmd->action();
+}
+
+namespace QtScriptEditor {
+namespace Internal {
+
+QtScriptEditorActionHandler::QtScriptEditorActionHandler(Core::ICore *core) :
+ TextEditor::TextEditorActionHandler(core,
+ QLatin1String(QtScriptEditor::Constants::C_QTSCRIPTEDITOR),
+ Format),
+ m_runAction(0)
+{
+}
+
+void QtScriptEditorActionHandler::createActions()
+{
+ TextEditor::TextEditorActionHandler::createActions();
+ m_runAction = actionFromId(core(), QLatin1String(QtScriptEditor::Constants::RUN));
+ connect(m_runAction, SIGNAL(triggered()), this, SLOT(run()));
+}
+
+
+void QtScriptEditorActionHandler::updateActions(UpdateMode um)
+{
+ TextEditor::TextEditorActionHandler::updateActions(um);
+ if (m_runAction)
+ m_runAction->setEnabled(um != NoEditor);
+}
+
+void QtScriptEditorActionHandler::run()
+{
+ typedef Core::ScriptManagerInterface::Stack Stack;
+ if (!currentEditor())
+ return;
+
+ const QString script = currentEditor()->toPlainText();
+
+ // run
+ Stack errorStack;
+ QString errorMessage;
+ if (core()->scriptManager()->runScript(script, &errorMessage, &errorStack))
+ return;
+
+ // try to find a suitable error line in the stack
+ // ignoring 0 and other files (todo: open other files?)
+ int errorLineNumber = 0;
+ if (const int numFrames = errorStack.size()) {
+ for (int f = 0; f < numFrames; f++) {
+ if (errorStack[f].lineNumber && errorStack[f].fileName.isEmpty()) {
+ errorLineNumber = errorStack[f].lineNumber;
+ break;
+ }
+ }
+ }
+ if (errorLineNumber)
+ currentEditor()->gotoLine(errorLineNumber);
+ QMessageBox::critical(core()->mainWindow(), tr("Qt Script Error"), errorMessage);
+}
+
+} // namespace Internal
+} // namespace QtScriptEditor
diff --git a/src/plugins/qtscripteditor/qtscripteditoractionhandler.h b/src/plugins/qtscripteditor/qtscripteditoractionhandler.h
new file mode 100644
index 0000000000..65073540d8
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditoractionhandler.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTSCRIPTDITORACTIONHANDLER_H
+#define QTSCRIPTDITORACTIONHANDLER_H
+
+#include <texteditor/texteditoractionhandler.h>
+
+namespace QtScriptEditor {
+namespace Internal {
+
+class QtScriptEditorActionHandler : public TextEditor::TextEditorActionHandler
+{
+ Q_OBJECT
+
+public:
+ QtScriptEditorActionHandler(Core::ICore *core);
+
+private:
+ virtual void createActions();
+ virtual void updateActions(UpdateMode um);
+
+private slots:
+ void run();
+
+private:
+ QAction *m_runAction;
+};
+
+} // namespace Internal
+} // namespace QtScriptEditor
+
+#endif // QTSCRIPTDITORACTIONHANDLER_H
diff --git a/src/plugins/qtscripteditor/qtscripteditorconstants.h b/src/plugins/qtscripteditor/qtscripteditorconstants.h
new file mode 100644
index 0000000000..c26384cf46
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditorconstants.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTSCRIPTEDITOR_CONSTANTS_H
+#define QTSCRIPTEDITOR_CONSTANTS_H
+
+namespace QtScriptEditor {
+namespace Constants {
+const char * const M_CONTEXT = "Qt Script Editor.ContextMenu";
+const char * const RUN = "Qt Script Editor.Run";
+const char * const RUN_SEP = "Qt Script Editor.Run.Separator";
+const char * const C_QTSCRIPTEDITOR = "Qt Script Editor";
+const char * const C_QTSCRIPTEDITOR_MIMETYPE = "application/javascript";
+}
+}
+
+#endif //QTSCRIPTEDITOR_CONSTANTS_H
diff --git a/src/plugins/qtscripteditor/qtscripteditorfactory.cpp b/src/plugins/qtscripteditor/qtscripteditorfactory.cpp
new file mode 100644
index 0000000000..bf5c12dcfe
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditorfactory.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtscripteditorfactory.h"
+#include "qtscripteditor.h"
+#include "qtscripteditoractionhandler.h"
+#include "qtscripteditorconstants.h"
+#include "qtscripteditorplugin.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/qdebug.h>
+
+using namespace QtScriptEditor::Internal;
+using namespace QtScriptEditor::Constants;
+
+QtScriptEditorFactory::QtScriptEditorFactory(Core::ICore *core,
+ const Context &context,
+ QObject *parent) :
+ Core::IEditorFactory(parent),
+ m_kind(QLatin1String(C_QTSCRIPTEDITOR)),
+ m_mimeTypes(QLatin1String(QtScriptEditor::Constants::C_QTSCRIPTEDITOR_MIMETYPE)),
+ m_context(context),
+ m_core(core),
+ m_actionHandler(new QtScriptEditorActionHandler(core))
+{
+}
+
+QtScriptEditorFactory::~QtScriptEditorFactory()
+{
+ delete m_actionHandler;
+}
+
+QString QtScriptEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *QtScriptEditorFactory::open(const QString &fileName)
+{
+ Core::IEditor *iface = m_core->editorManager()->openEditor(fileName, kind());
+ if (!iface) {
+ qWarning() << "QtScriptEditorFactory::open: openEditor failed for " << fileName;
+ return 0;
+ }
+ return iface->file();
+}
+
+Core::IEditor *QtScriptEditorFactory::createEditor(QWidget *parent)
+{
+ ScriptEditor *rc = new ScriptEditor(m_context, m_core, m_actionHandler, parent);
+ QtScriptEditorPlugin::initializeEditor(rc);
+ return rc->editableInterface();
+}
+
+QStringList QtScriptEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
diff --git a/src/plugins/qtscripteditor/qtscripteditorfactory.h b/src/plugins/qtscripteditor/qtscripteditorfactory.h
new file mode 100644
index 0000000000..600277d2c0
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditorfactory.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RQTSCRIPTEDITORFACTORY_H
+#define RQTSCRIPTEDITORFACTORY_H
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+#include <QtCore/QStringList>
+
+namespace Core {
+class ICore;
+}
+
+namespace TextEditor {
+class TextEditorActionHandler;
+}
+
+namespace QtScriptEditor {
+namespace Internal {
+
+class QtScriptEditorActionHandler;
+
+class QtScriptEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ typedef QList<int> Context;
+
+ QtScriptEditorFactory(Core::ICore *core,
+ const Context &context,
+ QObject *parent);
+ ~QtScriptEditorFactory();
+
+ virtual QStringList mimeTypes() const;
+ //EditorFactory
+ QString kind() const;
+ Core::IFile *open(const QString &fileName);
+ Core::IEditor *createEditor(QWidget *parent);
+
+private:
+ const QString m_kind;
+ const QStringList m_mimeTypes;
+ const Context m_context;
+
+ Core::ICore *m_core;
+ TextEditor::TextEditorActionHandler *m_actionHandler;
+};
+
+} // namespace Internal
+} // namespace QtScriptEditor
+
+#endif // RQTSCRIPTEDITORFACTORY_H
diff --git a/src/plugins/qtscripteditor/qtscripteditorplugin.cpp b/src/plugins/qtscripteditor/qtscripteditorplugin.cpp
new file mode 100644
index 0000000000..7216a77f35
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditorplugin.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtscripteditorplugin.h"
+#include "qtscripteditorconstants.h"
+#include "qtscripteditorfactory.h"
+#include "qtscripteditor.h"
+#include "qscripthighlighter.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/storagesettings.h>
+#include <texteditor/texteditorconstants.h>
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/textfilewizard.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtGui/QAction>
+
+using namespace QtScriptEditor::Internal;
+using namespace QtScriptEditor::Constants;
+
+QtScriptEditorPlugin *QtScriptEditorPlugin::m_instance = 0;
+
+QtScriptEditorPlugin::QtScriptEditorPlugin() :
+ m_wizard(0),
+ m_editor(0)
+{
+ m_instance = this;
+}
+
+QtScriptEditorPlugin::~QtScriptEditorPlugin()
+{
+ removeObject(m_editor);
+ removeObject(m_wizard);
+ m_instance = 0;
+}
+
+bool QtScriptEditorPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+ typedef SharedTools::QScriptHighlighter QScriptHighlighter;
+
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/qtscripteditor/QtScriptEditor.mimetypes.xml"), error_message))
+ return false;
+ m_scriptcontext << core->uniqueIDManager()->uniqueIdentifier(QtScriptEditor::Constants::C_QTSCRIPTEDITOR);
+ m_context = m_scriptcontext;
+ m_context << core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+
+ registerActions(core);
+
+ m_editor = new QtScriptEditorFactory(core, m_context, this);
+ addObject(m_editor);
+
+ Core::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+ wizardParameters.setDescription(tr("Qt Script file"));
+ wizardParameters.setName(tr("Qt Script file"));
+ wizardParameters.setCategory(QLatin1String("Qt"));
+ wizardParameters.setTrCategory(tr("Qt"));
+ m_wizard = new TextEditor::TextFileWizard(QLatin1String(QtScriptEditor::Constants::C_QTSCRIPTEDITOR_MIMETYPE),
+ QLatin1String(QtScriptEditor::Constants::C_QTSCRIPTEDITOR),
+ QLatin1String("qtscript$"),
+ wizardParameters, core, this);
+ addObject(m_wizard);
+
+ error_message->clear();
+ return true;
+}
+
+void QtScriptEditorPlugin::extensionsInitialized()
+{
+}
+
+void QtScriptEditorPlugin::initializeEditor(QtScriptEditor::Internal::ScriptEditor *editor)
+{
+ Q_ASSERT(m_instance);
+
+ TextEditor::TextEditorSettings *settings = TextEditor::TextEditorSettings::instance();
+ connect(settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
+ editor, SLOT(setFontSettings(TextEditor::FontSettings)));
+ connect(settings, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
+ editor, SLOT(setTabSettings(TextEditor::TabSettings)));
+ connect(settings, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)),
+ editor, SLOT(setStorageSettings(TextEditor::StorageSettings)));
+ connect(settings, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)),
+ editor, SLOT(setDisplaySettings(TextEditor::DisplaySettings)));
+
+ // tab settings rely on font settings
+ editor->setFontSettings(settings->fontSettings());
+ editor->setTabSettings(settings->tabSettings());
+ editor->setStorageSettings(settings->storageSettings());
+ editor->setDisplaySettings(settings->displaySettings());
+}
+
+void QtScriptEditorPlugin::registerActions(Core::ICore *core)
+{
+ Core::ActionManagerInterface *am = core->actionManager();
+ Core::IActionContainer *mcontext = am->createMenu(QtScriptEditor::Constants::M_CONTEXT);
+
+ QAction *action = new QAction(this);
+ action->setSeparator(true);
+ Core::ICommand *cmd = am->registerAction(action, QtScriptEditor::Constants::RUN_SEP, m_scriptcontext);
+ mcontext->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+
+ action = new QAction(tr("Run"), this);
+ cmd = am->registerAction(action, QtScriptEditor::Constants::RUN, m_scriptcontext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+R")));
+ mcontext->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+}
+
+Q_EXPORT_PLUGIN(QtScriptEditorPlugin)
diff --git a/src/plugins/qtscripteditor/qtscripteditorplugin.h b/src/plugins/qtscripteditor/qtscripteditorplugin.h
new file mode 100644
index 0000000000..449f8263f1
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripteditorplugin.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTSCRIPTEDITORPLUGIN_H
+#define QTSCRIPTEDITORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+namespace Core {
+class ICore;
+}
+
+namespace TextEditor {
+class FontSettingsPage;
+class TextFileWizard;
+}
+
+namespace QtScriptEditor {
+namespace Internal {
+
+class QtScriptWizard;
+class QtScriptEditorFactory;
+class ScriptEditor;
+
+class QtScriptEditorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ QtScriptEditorPlugin();
+ virtual ~QtScriptEditorPlugin();
+
+ //Plugin
+ bool initialize(const QStringList &arguments, QString *error_message = 0);
+ void extensionsInitialized();
+
+ static void initializeEditor(ScriptEditor *editor);
+
+private:
+ void registerActions(Core::ICore *core);
+
+ static QtScriptEditorPlugin *m_instance;
+
+ typedef QList<int> Context;
+ Context m_context;
+ Context m_scriptcontext;
+
+ TextEditor::TextFileWizard *m_wizard;
+ QtScriptEditorFactory *m_editor;
+};
+
+} // namespace Internal
+} // namespace QtScriptEditor
+
+#endif // QTSCRIPTEDITORPLUGIN_H
diff --git a/src/plugins/qtscripteditor/qtscripthighlighter.cpp b/src/plugins/qtscripteditor/qtscripthighlighter.cpp
new file mode 100644
index 0000000000..16d8f11472
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripthighlighter.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "qtscripthighlighter.h"
+
+namespace QtScriptEditor {
+namespace Internal {
+
+QtScriptHighlighter::QtScriptHighlighter(QTextDocument *parent) :
+ SharedTools::QScriptHighlighter(parent)
+{
+ m_currentBlockParentheses.reserve(20);
+ m_braceDepth = 0;
+}
+
+int QtScriptHighlighter::onBlockStart()
+{
+ m_currentBlockParentheses.clear();
+ m_braceDepth = 0;
+
+ int state = 0;
+ int previousState = previousBlockState();
+ if (previousState != -1) {
+ state = previousState & 0xff;
+ m_braceDepth = previousState >> 8;
+ }
+
+ return state;
+}
+
+void QtScriptHighlighter::onOpeningParenthesis(QChar parenthesis, int pos)
+{
+ if (parenthesis == QLatin1Char('{'))
+ ++m_braceDepth;
+ m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Opened, parenthesis, pos));
+}
+
+void QtScriptHighlighter::onClosingParenthesis(QChar parenthesis, int pos)
+{
+ if (parenthesis == QLatin1Char('}'))
+ --m_braceDepth;
+ m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Closed, parenthesis, pos));
+}
+
+void QtScriptHighlighter::onBlockEnd(int state, int firstNonSpace)
+{
+ 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()) {
+ Q_ASSERT(blockData);
+ 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);
+ }
+}
+
+} // namespace Internal
+} // namespace QtScriptEditor
diff --git a/src/plugins/qtscripteditor/qtscripthighlighter.h b/src/plugins/qtscripteditor/qtscripthighlighter.h
new file mode 100644
index 0000000000..2e9f23d144
--- /dev/null
+++ b/src/plugins/qtscripteditor/qtscripthighlighter.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTSCRIPTSYNTAXHIGHLIGHTER_H
+#define QTSCRIPTSYNTAXHIGHLIGHTER_H
+
+#include "qscripthighlighter.h"
+#include <texteditor/basetexteditor.h>
+
+namespace QtScriptEditor {
+namespace Internal {
+
+// Highlighter for Scripts that stores
+// the parentheses encountered in the block data
+// for parentheses matching to work.
+
+class QtScriptHighlighter : public SharedTools::QScriptHighlighter
+{
+ Q_OBJECT
+public:
+ QtScriptHighlighter(QTextDocument *parent = 0);
+
+private:
+ virtual int onBlockStart();
+ virtual void onOpeningParenthesis(QChar parenthesis, int pos);
+ virtual void onClosingParenthesis(QChar parenthesis, int pos);
+ virtual void onBlockEnd(int state, int firstNonSpace);
+
+ typedef TextEditor::Parenthesis Parenthesis;
+ typedef TextEditor::Parentheses Parentheses;
+ Parentheses m_currentBlockParentheses;
+ int m_braceDepth;
+};
+
+} // namespace Internal
+} // namespace QtScriptEditor
+
+#endif // QTSCRIPTSYNTAXHIGHLIGHTER_H
diff --git a/src/plugins/quickopen/QuickOpen.pluginspec b/src/plugins/quickopen/QuickOpen.pluginspec
new file mode 100644
index 0000000000..3c92b9cbf8
--- /dev/null
+++ b/src/plugins/quickopen/QuickOpen.pluginspec
@@ -0,0 +1,10 @@
+<plugin name="QuickOpen" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Provides the QuickOpen widget and the hooks for QuickOpen filter implementations.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/quickopen/basefilefilter.cpp b/src/plugins/quickopen/basefilefilter.cpp
new file mode 100644
index 0000000000..7fc4814cf4
--- /dev/null
+++ b/src/plugins/quickopen/basefilefilter.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basefilefilter.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QDir>
+
+using namespace Core;
+using namespace QuickOpen;
+
+BaseFileFilter::BaseFileFilter(ICore *core)
+ : m_core(core),
+ m_files(QStringList()),
+ m_fileNames(QStringList()),
+ m_forceNewSearchList(false)
+{
+}
+
+QList<FilterEntry> BaseFileFilter::matchesFor(const QString &origEntry)
+{
+ QList<FilterEntry> value;
+ QString entry = trimWildcards(origEntry);
+ QStringMatcher matcher(entry, Qt::CaseInsensitive);
+ const QRegExp regexp("*"+entry+"*", Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (!regexp.isValid())
+ return value;
+ bool hasWildcard = (entry.contains('*') || entry.contains('?'));
+ QStringList searchListPaths;
+ QStringList searchListNames;
+ if (!m_previousEntry.isEmpty() && !m_forceNewSearchList && entry.contains(m_previousEntry)) {
+ searchListPaths = m_previousResultPaths;
+ searchListNames = m_previousResultNames;
+ } else {
+ searchListPaths = m_files;
+ searchListNames = m_fileNames;
+ }
+ m_previousResultPaths.clear();
+ m_previousResultNames.clear();
+ m_forceNewSearchList = false;
+ m_previousEntry = entry;
+ QStringListIterator paths(searchListPaths);
+ QStringListIterator names(searchListNames);
+ while (paths.hasNext() && names.hasNext()) {
+ QString path = paths.next();
+ QString name = names.next();
+ if ((hasWildcard && regexp.exactMatch(name))
+ || (!hasWildcard && matcher.indexIn(name) != -1)) {
+ QFileInfo fi(path);
+ FilterEntry entry(this, fi.fileName(), path);
+ entry.extraInfo = QDir::toNativeSeparators(fi.path());
+ entry.resolveFileIcon = true;
+ value.append(entry);
+ m_previousResultPaths.append(path);
+ m_previousResultNames.append(name);
+ }
+ }
+ return value;
+}
+
+void BaseFileFilter::accept(QuickOpen::FilterEntry selection) const
+{
+ m_core->editorManager()->openEditor(selection.internalData.toString());
+ m_core->editorManager()->ensureEditorManagerVisible();
+}
+
+void BaseFileFilter::generateFileNames()
+{
+ m_fileNames.clear();
+ foreach (const QString &fileName, m_files) {
+ QFileInfo fi(fileName);
+ m_fileNames.append(fi.fileName());
+ }
+ m_forceNewSearchList = true;
+}
diff --git a/src/plugins/quickopen/basefilefilter.h b/src/plugins/quickopen/basefilefilter.h
new file mode 100644
index 0000000000..e0f780dc14
--- /dev/null
+++ b/src/plugins/quickopen/basefilefilter.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEFILEFILTER_H
+#define BASEFILEFILTER_H
+
+#include "quickopen_global.h"
+#include "iquickopenfilter.h"
+
+#include <coreplugin/icore.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtGui/QWidget>
+
+namespace QuickOpen {
+
+class QUICKOPEN_EXPORT BaseFileFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ BaseFileFilter(Core::ICore *core);
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+
+protected:
+ void generateFileNames();
+
+ Core::ICore *m_core;
+ QStringList m_files;
+ QStringList m_fileNames;
+ QStringList m_previousResultPaths;
+ QStringList m_previousResultNames;
+ bool m_forceNewSearchList;
+ QString m_previousEntry;
+};
+
+} // namespace QuickOpen
+
+#endif // BASEFILEFILTER_H
diff --git a/src/plugins/quickopen/directoryfilter.cpp b/src/plugins/quickopen/directoryfilter.cpp
new file mode 100644
index 0000000000..0b1564d3d6
--- /dev/null
+++ b/src/plugins/quickopen/directoryfilter.cpp
@@ -0,0 +1,258 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "directoryfilter.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QStack>
+#include <QtGui/QDirModel>
+#include <QtGui/QCompleter>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+DirectoryFilter::DirectoryFilter(ICore *core)
+ : BaseFileFilter(core),
+ m_name(tr("Generic Directory Filter")),
+ m_directories(QStringList()),
+ m_filters(QStringList() << "*.h" << "*.cpp" << "*.ui" << "*.qrc")
+{
+ setIncludedByDefault(true);
+}
+
+QByteArray DirectoryFilter::saveState() const
+{
+ QMutexLocker locker(&m_lock);
+ QByteArray value;
+ QDataStream out(&value, QIODevice::WriteOnly);
+ out << m_name;
+ out << m_directories;
+ out << m_filters;
+ out << shortcutString();
+ out << defaultActiveState();
+ out << m_files;
+ return value;
+}
+
+bool DirectoryFilter::restoreState(const QByteArray &state)
+{
+ QMutexLocker locker(&m_lock);
+
+ QStringList dirEntries;
+ QString shortcut;
+ bool defaultFilter;
+
+ QDataStream in(state);
+ in >> m_name;
+ in >> dirEntries;
+ in >> m_filters;
+ in >> shortcut;
+ in >> defaultFilter;
+ in >> m_files;
+
+ setShortcutString(shortcut);
+ setIncludedByDefault(defaultFilter);
+
+ // ### TODO throw that out again:
+ // clear the list of directories of empty entries (which might at least happen at a format change)
+ m_directories.clear();
+ foreach (const QString &dir, dirEntries) {
+ if (dir.isEmpty())
+ continue;
+ m_directories.append(dir);
+ }
+
+ generateFileNames();
+ return true;
+}
+
+bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
+{
+ bool success = false;
+ QDialog dialog(parent);
+ m_dialog = &dialog;
+ m_ui.setupUi(&dialog);
+ dialog.setWindowTitle(tr("Filter Configuration"));
+ connect(m_ui.addButton, SIGNAL(clicked()),
+ this, SLOT(addDirectory()), Qt::DirectConnection);
+ connect(m_ui.editButton, SIGNAL(clicked()),
+ this, SLOT(editDirectory()), Qt::DirectConnection);
+ connect(m_ui.removeButton, SIGNAL(clicked()),
+ this, SLOT(removeDirectory()), Qt::DirectConnection);
+ connect(m_ui.directoryList, SIGNAL(itemSelectionChanged()),
+ this, SLOT(updateOptionButtons()), Qt::DirectConnection);
+ m_ui.nameEdit->setText(m_name);
+ m_ui.nameEdit->selectAll();
+ m_ui.directoryList->clear();
+ m_ui.directoryList->addItems(m_directories);
+ m_ui.fileTypeEdit->setText(m_filters.join(tr(",")));
+ m_ui.shortcutEdit->setText(shortcutString());
+ m_ui.defaultFlag->setChecked(!defaultActiveState());
+ updateOptionButtons();
+ if (dialog.exec() == QDialog::Accepted) {
+ QMutexLocker locker(&m_lock);
+ bool directoriesChanged = false;
+ QStringList oldDirectories = m_directories;
+ QStringList oldFilters = m_filters;
+ m_name = m_ui.nameEdit->text().trimmed();
+ m_directories.clear();
+ int oldCount = oldDirectories.count();
+ int newCount = m_ui.directoryList->count();
+ if (oldCount != newCount)
+ directoriesChanged = true;
+ for (int i = 0; i < newCount; ++i) {
+ m_directories.append(m_ui.directoryList->item(i)->text());
+ if (!directoriesChanged && m_directories.at(i) != oldDirectories.at(i))
+ directoriesChanged = true;
+ }
+ m_filters = m_ui.fileTypeEdit->text().trimmed().split(tr(","));
+ setShortcutString(m_ui.shortcutEdit->text().trimmed());
+ setIncludedByDefault(!m_ui.defaultFlag->isChecked());
+ if (directoriesChanged || oldFilters != m_filters)
+ needsRefresh = true;
+ success = true;
+ }
+ return success;
+}
+
+void DirectoryFilter::addDirectory()
+{
+ QString dir = QFileDialog::getExistingDirectory(m_dialog, tr("Choose a directory to add"));
+ if (!dir.isEmpty()) {
+ m_ui.directoryList->addItem(dir);
+ }
+}
+
+void DirectoryFilter::editDirectory()
+{
+ if (m_ui.directoryList->selectedItems().count() < 1)
+ return;
+ QListWidgetItem *currentItem = m_ui.directoryList->selectedItems().at(0);
+ QString dir = QFileDialog::getExistingDirectory(m_dialog, tr("Choose a directory to add"),
+ currentItem->text());
+ if (!dir.isEmpty()) {
+ currentItem->setText(dir);
+ }
+}
+
+void DirectoryFilter::removeDirectory()
+{
+ if (m_ui.directoryList->selectedItems().count() < 1)
+ return;
+ QListWidgetItem *currentItem = m_ui.directoryList->selectedItems().at(0);
+ delete m_ui.directoryList->takeItem(m_ui.directoryList->row(currentItem));
+}
+
+void DirectoryFilter::updateOptionButtons()
+{
+ bool haveSelectedItem = (m_ui.directoryList->selectedItems().count() > 0);
+ m_ui.editButton->setEnabled(haveSelectedItem);
+ m_ui.removeButton->setEnabled(haveSelectedItem);
+}
+
+void DirectoryFilter::refresh(QFutureInterface<void> &future)
+{
+ const int MAX = 360;
+ future.setProgressRange(0, MAX);
+ if (m_directories.count() < 1) {
+ QMutexLocker locker(&m_lock);
+ m_files.clear();
+ generateFileNames();
+ future.setProgressValueAndText(MAX, tr("%1 filter update: 0 files").arg(m_name));
+ return;
+ }
+ int progress = 0;
+ int MAX_PER = MAX;
+ QStringList files;
+ QStack<QDir> dirs;
+ QStack<int> progressValues;
+ QStack<bool> processedValues;
+ { // initialize
+ QMutexLocker locker(&m_lock);
+ MAX_PER = MAX/m_directories.count();
+ foreach (const QString &directoryEntry, m_directories) {
+ if (!directoryEntry.isEmpty()) {
+ dirs.push(QDir(directoryEntry));
+ progressValues.push(MAX_PER);
+ processedValues.push(false);
+ }
+ }
+ }
+ while (!dirs.isEmpty() && !future.isCanceled()) {
+ if (future.isProgressUpdateNeeded()) {
+ future.setProgressValueAndText(progress, tr("%1 filter update: %2 files").arg(m_name).arg(files.size()));
+ }
+ QDir dir = dirs.pop();
+ int dirProgressMax = progressValues.pop();
+ bool processed = processedValues.pop();
+ if (dir.exists()) {
+ QStringList subDirs;
+ if (!processed) {
+ subDirs = dir.entryList(QDir::Dirs|QDir::Hidden|QDir::NoDotAndDotDot,
+ QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
+ }
+ if (subDirs.isEmpty()) {
+ QStringList fileEntries = dir.entryList(m_filters,
+ QDir::Files|QDir::Hidden,
+ QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
+ foreach (const QString &file, fileEntries)
+ files.append(dir.path()+"/"+file);
+ progress += dirProgressMax;
+ } else {
+ int subProgress = dirProgressMax/(subDirs.size()+1);
+ int selfProgress = subProgress + dirProgressMax%(subDirs.size()+1);
+ dirs.push(dir);
+ progressValues.push(selfProgress);
+ processedValues.push(true);
+ foreach (const QString &directory, subDirs) {
+ dirs.push(QDir(dir.path()+"/"+directory));
+ progressValues.push(subProgress);
+ processedValues.push(false);
+ }
+ }
+ } else {
+ progress += dirProgressMax;
+ }
+ }
+
+ if (!future.isCanceled()) {
+ QMutexLocker locker(&m_lock);
+ m_files = files;
+ generateFileNames();
+ future.setProgressValue(MAX);
+ } else {
+ future.setProgressValueAndText(progress, tr("%1 filter update: canceled").arg(m_name));
+ }
+}
diff --git a/src/plugins/quickopen/directoryfilter.h b/src/plugins/quickopen/directoryfilter.h
new file mode 100644
index 0000000000..e228bde4f0
--- /dev/null
+++ b/src/plugins/quickopen/directoryfilter.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DIRECTORYFILTER_H
+#define DIRECTORYFILTER_H
+
+#include "ui_directoryfilter.h"
+#include "basefilefilter.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QMutex>
+#include <QtGui/QWidget>
+#include <QtGui/QDialog>
+
+#include <coreplugin/icore.h>
+#include <qtconcurrent/QtConcurrentTools>
+
+namespace QuickOpen {
+namespace Internal {
+
+class DirectoryFilter : public BaseFileFilter
+{
+ Q_OBJECT
+
+public:
+ DirectoryFilter(Core::ICore *core);
+ QString trName() const { return m_name; }
+ QString name() const { return m_name; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::Medium; }
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+ bool openConfigDialog(QWidget *parent, bool &needsRefresh);
+ void refresh(QFutureInterface<void> &future);
+
+private slots:
+ void addDirectory();
+ void editDirectory();
+ void removeDirectory();
+ void updateOptionButtons();
+
+private:
+ QString m_name;
+ QStringList m_directories;
+ QStringList m_filters;
+ // Our config dialog, uses in addDirectory and editDirectory
+ // to give their dialogs the right parent
+ QDialog *m_dialog;
+ Ui::DirectoryFilterOptions m_ui;
+ mutable QMutex m_lock;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // DIRECTORYFILTER_H
diff --git a/src/plugins/quickopen/directoryfilter.ui b/src/plugins/quickopen/directoryfilter.ui
new file mode 100644
index 0000000000..41fa3d5bde
--- /dev/null
+++ b/src/plugins/quickopen/directoryfilter.ui
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QuickOpen::Internal::DirectoryFilterOptions</class>
+ <widget class="QDialog" name="QuickOpen::Internal::DirectoryFilterOptions">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>393</width>
+ <height>271</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3">
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>File Types:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="3">
+ <widget class="QLineEdit" name="fileTypeEdit">
+ <property name="toolTip">
+ <string>Specify file name filters, separated by comma. Filters may contain wildcards.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Prefix:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="shortcutEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Specify a short word/abbreviation that can be used to restrict completions to files from this directory tree.
+To do this you type this shortcut and a space in the QuickOpen entry field, and then the word to search for.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2" colspan="2">
+ <widget class="QCheckBox" name="defaultFlag">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Limit to prefix</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="text">
+ <string>Add...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editButton">
+ <property name="text">
+ <string>Edit...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Directories:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QListWidget" name="directoryList"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>369</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QuickOpen::Internal::DirectoryFilterOptions</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>353</x>
+ <y>174</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>390</x>
+ <y>152</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QuickOpen::Internal::DirectoryFilterOptions</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>280</x>
+ <y>176</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>391</x>
+ <y>141</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/quickopen/directoryparser.cpp b/src/plugins/quickopen/directoryparser.cpp
new file mode 100644
index 0000000000..09b8c22016
--- /dev/null
+++ b/src/plugins/quickopen/directoryparser.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "directoryparser.h"
+#include "quickopenplugin.h"
+
+using namespace QuickOpen::Internal;
+
+DirectoryParser::DirectoryParser(QObject *parent)
+ : QThread(parent)
+{
+}
+
+DirectoryParser::~DirectoryParser()
+{
+ if (isRunning())
+ terminate();
+}
+
+void DirectoryParser::parse(Filter filter)
+{
+ m_dirs = filter.directories();
+ m_filters = filter.acceptedFileExtensions().split(';');
+ m_blackList.clear();
+ foreach (QString s, filter.skipDirectories()) {
+ if (!s.trimmed().isEmpty() && !m_blackList.contains(s))
+ m_blackList.insert(s);
+ }
+ if (!isRunning())
+ start(QThread::NormalPriority);
+}
+
+void DirectoryParser::setDirectoryNameBlackList(const QStringList &lst)
+{
+ m_blackList.clear();
+ foreach (QString s, lst) {
+ if (!m_blackList.contains(s))
+ m_blackList.insert(s);
+ }
+}
+
+QSet<QString> DirectoryParser::files() const
+{
+ return m_files;
+}
+
+void DirectoryParser::run()
+{
+ m_files.clear();
+ m_runFiles.clear();
+ foreach (QString s, m_dirs) {
+ if (s.isEmpty())
+ continue;
+ QDir dir(s);
+ if (dir.exists()) {
+ m_runFilters = m_filters;
+ m_runBlackList = m_blackList;
+ collectFiles(dir);
+ }
+ }
+ m_files = m_runFiles;
+ emit directoriesParsed();
+}
+
+void DirectoryParser::collectFiles(const QDir &dir)
+{
+ QString dirName = dir.absolutePath() + QLatin1String("/");
+ foreach (QString f, dir.entryList(m_runFilters, QDir::Files)) {
+ m_runFiles.insert(dirName + f);
+ }
+ foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
+ if (!m_runBlackList.contains(d))
+ collectFiles(dir.absolutePath() + QDir::separator() + d);
+ }
+}
diff --git a/src/plugins/quickopen/directoryparser.h b/src/plugins/quickopen/directoryparser.h
new file mode 100644
index 0000000000..af317a0fe4
--- /dev/null
+++ b/src/plugins/quickopen/directoryparser.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DIRECTORYPARSER_H
+#define DIRECTORYPARSER_H
+
+#include <QtCore/QThread>
+#include <QtCore/QDir>
+#include <QtCore/QSet>
+
+namespace QuickOpen {
+namespace Internal {
+
+class Filter;
+
+class DirectoryParser : public QThread
+{
+ Q_OBJECT
+
+public:
+ DirectoryParser(QObject *parent);
+ ~DirectoryParser();
+ void parse(Filter filter);
+
+ void setDirectoryNameBlackList(const QStringList &lst);
+ QSet<QString> files() const;
+
+signals:
+ void directoriesParsed();
+
+private:
+ void run();
+ void collectFiles(const QDir &dir);
+
+ QStringList m_dirs;
+ QSet<QString> m_files;
+
+ QSet<QString> m_runFiles;
+ QStringList m_filters;
+ QStringList m_runFilters;
+ QSet<QString> m_blackList;
+ QSet<QString> m_runBlackList;
+};
+
+} //namespace Internal
+} //namespace QuickOpen
+
+#endif // DIRECTORYPARSER_H
diff --git a/src/plugins/quickopen/filesystemfilter.cpp b/src/plugins/quickopen/filesystemfilter.cpp
new file mode 100644
index 0000000000..17fcd060ad
--- /dev/null
+++ b/src/plugins/quickopen/filesystemfilter.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "filesystemfilter.h"
+#include "quickopentoolwindow.h"
+
+#include <QtCore/QDir>
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+FileSystemFilter::FileSystemFilter(EditorManager *editorManager, QuickOpenToolWindow *toolWindow)
+ : m_editorManager(editorManager), m_toolWindow(toolWindow), m_includeHidden(true)
+{
+ setShortcutString("f");
+ setIncludedByDefault(false);
+}
+
+QList<FilterEntry> FileSystemFilter::matchesFor(const QString &entry)
+{
+ QList<FilterEntry> value;
+ QFileInfo entryInfo(entry);
+ QString name = entryInfo.fileName();
+ QString directory = entryInfo.path();
+ QString filePath = entryInfo.filePath();
+ bool isDrive = false;
+ foreach (const QFileInfo &drive, QDir::drives()) {
+ if (filePath.startsWith(drive.path())) {
+ isDrive = true;
+ break;
+ }
+ }
+ if (!isDrive) {
+ if (filePath.startsWith("~/")) {
+ directory.replace(0, 1, QDir::homePath());
+ } else {
+ IEditor *editor = m_editorManager->currentEditor();
+ if (editor && !editor->file()->fileName().isEmpty()) {
+ QFileInfo info(editor->file()->fileName());
+ directory.prepend(info.absolutePath()+"/");
+ }
+ }
+ }
+ QDir dirInfo(directory);
+ QDir::Filters dirFilter = QDir::Dirs|QDir::Drives;
+ QDir::Filters fileFilter = QDir::Files;
+ if (m_includeHidden) {
+ dirFilter |= QDir::Hidden;
+ fileFilter |= QDir::Hidden;
+ }
+ QStringList dirs = dirInfo.entryList(dirFilter,
+ QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
+ QStringList files = dirInfo.entryList(fileFilter,
+ QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
+ foreach (const QString &dir, dirs) {
+ if (dir != "." && (name.isEmpty() || dir.startsWith(name, Qt::CaseInsensitive))) {
+ FilterEntry entry(this, dir, directory + "/" + dir);
+ entry.resolveFileIcon = true;
+ value.append(entry);
+ }
+ }
+ foreach (const QString &file, files) {
+ if (name.isEmpty() || file.startsWith(name, Qt::CaseInsensitive)) {
+ const QString fullPath = directory + "/" + file;
+ FilterEntry entry(this, file, fullPath);
+ entry.resolveFileIcon = true;
+ value.append(entry);
+ }
+ }
+ return value;
+}
+
+void FileSystemFilter::accept(FilterEntry selection) const
+{
+ QFileInfo info(selection.internalData.toString());
+ if (info.isDir()) {
+ m_toolWindow->show(shortcutString()+" "
+ +QDir::toNativeSeparators(info.absoluteFilePath()+"/"));
+ return;
+ }
+ m_editorManager->openEditor(selection.internalData.toString());
+ m_editorManager->ensureEditorManagerVisible();
+}
+
+bool FileSystemFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
+{
+ Q_UNUSED(needsRefresh);
+ Ui::FileSystemFilterOptions ui;
+ QDialog dialog(parent);
+ ui.setupUi(&dialog);
+
+ ui.hiddenFilesFlag->setChecked(m_includeHidden);
+ ui.limitCheck->setChecked(!defaultActiveState());
+ ui.shortcutEdit->setText(shortcutString());
+
+ if (dialog.exec() == QDialog::Accepted) {
+ m_includeHidden = ui.hiddenFilesFlag->isChecked();
+ setShortcutString(ui.shortcutEdit->text().trimmed());
+ setIncludedByDefault(!ui.limitCheck->isChecked());
+ return true;
+ }
+ return false;
+}
+
+QByteArray FileSystemFilter::saveState() const
+{
+ QByteArray value;
+ QDataStream out(&value, QIODevice::WriteOnly);
+ out << m_includeHidden;
+ out << shortcutString();
+ out << defaultActiveState();
+ return value;
+}
+
+bool FileSystemFilter::restoreState(const QByteArray &state)
+{
+ QDataStream in(state);
+ in >> m_includeHidden;
+
+ // An attempt to prevent setting this on old configuration
+ if (!in.atEnd()) {
+ QString shortcut;
+ bool defaultFilter;
+ in >> shortcut;
+ in >> defaultFilter;
+ setShortcutString(shortcut);
+ setIncludedByDefault(defaultFilter);
+ }
+
+ return true;
+}
diff --git a/src/plugins/quickopen/filesystemfilter.h b/src/plugins/quickopen/filesystemfilter.h
new file mode 100644
index 0000000000..3ea20b6059
--- /dev/null
+++ b/src/plugins/quickopen/filesystemfilter.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FILESYSTEMFILTER_H
+#define FILESYSTEMFILTER_H
+
+#include "iquickopenfilter.h"
+#include "ui_filesystemfilter.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace QuickOpen {
+namespace Internal {
+
+class QuickOpenToolWindow;
+
+class FileSystemFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ FileSystemFilter(Core::EditorManager *editorManager, QuickOpenToolWindow *toolWindow);
+ QString trName() const { return tr("File in file system"); }
+ QString name() const { return "File in file system"; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::Medium; }
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+ bool openConfigDialog(QWidget *parent, bool &needsRefresh);
+ void refresh(QFutureInterface<void> &) {}
+
+private:
+ Core::EditorManager *m_editorManager;
+ QuickOpenToolWindow *m_toolWindow;
+ bool m_includeHidden;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // FILESYSTEMFILTER_H
diff --git a/src/plugins/quickopen/filesystemfilter.ui b/src/plugins/quickopen/filesystemfilter.ui
new file mode 100644
index 0000000000..c9a3ed3a51
--- /dev/null
+++ b/src/plugins/quickopen/filesystemfilter.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QuickOpen::Internal::FileSystemFilterOptions</class>
+ <widget class="QDialog" name="QuickOpen::Internal::FileSystemFilterOptions">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>327</width>
+ <height>131</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Filter configuration</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Prefix:</string>
+ </property>
+ <property name="buddy">
+ <cstring>shortcutEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="shortcutEdit"/>
+ </item>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="limitCheck">
+ <property name="text">
+ <string>Limit to prefix</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2">
+ <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>
+ <item row="3" column="1">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="hiddenFilesFlag">
+ <property name="text">
+ <string>Include hidden files</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QuickOpen::Internal::FileSystemFilterOptions</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QuickOpen::Internal::FileSystemFilterOptions</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/quickopen/images/quickopen.png b/src/plugins/quickopen/images/quickopen.png
new file mode 100644
index 0000000000..000ee1c018
--- /dev/null
+++ b/src/plugins/quickopen/images/quickopen.png
Binary files differ
diff --git a/src/plugins/quickopen/images/reload.png b/src/plugins/quickopen/images/reload.png
new file mode 100644
index 0000000000..b5afefb32b
--- /dev/null
+++ b/src/plugins/quickopen/images/reload.png
Binary files differ
diff --git a/src/plugins/quickopen/iquickopenfilter.cpp b/src/plugins/quickopen/iquickopenfilter.cpp
new file mode 100644
index 0000000000..c0af2f26a1
--- /dev/null
+++ b/src/plugins/quickopen/iquickopenfilter.cpp
@@ -0,0 +1,130 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "iquickopenfilter.h"
+
+#include <QtGui/QBoxLayout>
+#include <QtGui/QCheckBox>
+#include <QtGui/QDialog>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+
+using namespace QuickOpen;
+
+IQuickOpenFilter::IQuickOpenFilter(QObject *parent):
+ QObject(parent)
+{
+}
+
+QString IQuickOpenFilter::shortcutString() const
+{
+ return m_shortcut;
+}
+
+void IQuickOpenFilter::setShortcutString(const QString &shortcut)
+{
+ m_shortcut = shortcut;
+}
+
+QByteArray IQuickOpenFilter::saveState() const
+{
+ QByteArray value;
+ QDataStream out(&value, QIODevice::WriteOnly);
+ out << shortcutString();
+ out << defaultActiveState();
+ return value;
+}
+
+bool IQuickOpenFilter::restoreState(const QByteArray &state)
+{
+ QString shortcut;
+ bool defaultFilter;
+
+ QDataStream in(state);
+ in >> shortcut;
+ in >> defaultFilter;
+
+ setShortcutString(shortcut);
+ setIncludedByDefault(defaultFilter);
+ return true;
+}
+
+bool IQuickOpenFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
+{
+ Q_UNUSED(needsRefresh);
+
+ QDialog dialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+ dialog.setWindowTitle(tr("Filter Configuration"));
+
+ QVBoxLayout *vlayout = new QVBoxLayout(&dialog);
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ QLineEdit *shortcutEdit = new QLineEdit(shortcutString());
+ QCheckBox *limitCheck = new QCheckBox(tr("Limit to prefix"));
+ limitCheck->setChecked(!defaultActiveState());
+
+ hlayout->addWidget(new QLabel(tr("Prefix:")));
+ hlayout->addWidget(shortcutEdit);
+ hlayout->addWidget(limitCheck);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok |
+ QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+
+ vlayout->addLayout(hlayout);
+ vlayout->addStretch();
+ vlayout->addWidget(buttonBox);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ setShortcutString(shortcutEdit->text().trimmed());
+ setIncludedByDefault(!limitCheck->isChecked());
+ return true;
+ }
+
+ return false;
+}
+
+bool IQuickOpenFilter::isConfigurable() const
+{
+ return true;
+}
+
+bool IQuickOpenFilter::defaultActiveState() const
+{
+ return m_default;
+}
+
+void IQuickOpenFilter::setIncludedByDefault(bool includedByDefault)
+{
+ m_default = includedByDefault;
+}
diff --git a/src/plugins/quickopen/iquickopenfilter.h b/src/plugins/quickopen/iquickopenfilter.h
new file mode 100644
index 0000000000..9184db4915
--- /dev/null
+++ b/src/plugins/quickopen/iquickopenfilter.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef IQUICKOPENFILTER_H
+#define IQUICKOPENFILTER_H
+
+#include "quickopen_global.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QVariant>
+#include <QtCore/QFutureInterface>
+#include <QtGui/QIcon>
+
+namespace QuickOpen {
+
+class IQuickOpenFilter;
+
+struct FilterEntry
+{
+ FilterEntry() {}
+ FilterEntry(IQuickOpenFilter *fromFilter, const QString &name, const QVariant &data,
+ const QIcon &icon = QIcon())
+ : filter(fromFilter)
+ , displayName(name)
+ , internalData(data)
+ , displayIcon(icon)
+ , resolveFileIcon(false)
+ {}
+
+ bool operator==(const FilterEntry &other) const {
+ if (internalData.canConvert(QVariant::String))
+ return (internalData.toString() == other.internalData.toString());
+ return internalData.constData() == other.internalData.constData();
+ }
+
+ /* backpointer to creating filter */
+ IQuickOpenFilter *filter;
+ /* displayed string */
+ QString displayName;
+ /* extra information displayed in light-gray in a second column (optional) */
+ QString extraInfo;
+ /* can be used by the filter to save more information about the entry */
+ QVariant internalData;
+ /* icon to display along with the entry */
+ QIcon displayIcon;
+ /* internal data is interpreted as file name and icon is retrieved from the file system if true */
+ bool resolveFileIcon;
+};
+
+class QUICKOPEN_EXPORT IQuickOpenFilter : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Priority {High = 0, Medium = 1, Low = 2};
+
+ IQuickOpenFilter(QObject *parent = 0);
+ virtual ~IQuickOpenFilter() {}
+
+ /* visible name */
+ virtual QString trName() const = 0;
+
+ /* internal name */
+ virtual QString name() const = 0;
+
+ /* selection list order in case of multiple active filters (high goes on top) */
+ virtual Priority priority() const = 0;
+
+ /* string to type to use this filter exclusively */
+ virtual QString shortcutString() const;
+ void setShortcutString(const QString &shortcut);
+
+ /* list of matches for the given user entry */
+ virtual QList<FilterEntry> matchesFor(const QString &entry) = 0;
+
+ /* user has selected the given entry that belongs to this filter */
+ virtual void accept(FilterEntry selection) const = 0;
+
+ /* implement to update caches on user request, if that's a long operation */
+ virtual void refresh(QFutureInterface<void> &future) = 0;
+
+ /* Saved state is used to restore the filter at start up. */
+ virtual QByteArray saveState() const;
+
+ /* Used to restore the filter at start up. */
+ virtual bool restoreState(const QByteArray &state);
+
+ /* User wants to configure this filter (if supported). Use it to pop up a dialog.
+ * needsRefresh is used as a hint to indicate that refresh should be called.
+ * The default implementation allows changing the shortcut and whether the filter
+ * is enabled by default.
+ */
+ virtual bool openConfigDialog(QWidget *parent, bool &needsRefresh);
+
+ /* If there is a configure dialog available for this filter. The default
+ * implementation returns true. */
+ virtual bool isConfigurable() const;
+
+ /* is this filter used also when the shortcutString is not used? */
+ virtual bool defaultActiveState() const;
+ void setIncludedByDefault(bool includedByDefault);
+
+ static QString trimWildcards(const QString &str) {
+ if (str.isEmpty())
+ return str;
+ int first = 0, last = str.size()-1;
+ while (first < str.size() && (str.at(first) == '*' || str.at(first) == '?'))
+ ++first;
+ while (last >= 0 && (str.at(last) == '*' || str.at(last) == '?'))
+ --last;
+ if (first > last)
+ return QString();
+ return str.mid(first, last-first+1);
+ }
+
+private:
+ QString m_shortcut;
+ bool m_default;
+};
+
+} // namespace QuickOpen
+
+#endif // IQUICKOPENFILTER_H
diff --git a/src/plugins/quickopen/opendocumentsfilter.cpp b/src/plugins/quickopen/opendocumentsfilter.cpp
new file mode 100644
index 0000000000..9b9843002c
--- /dev/null
+++ b/src/plugins/quickopen/opendocumentsfilter.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "opendocumentsfilter.h"
+
+Q_DECLARE_METATYPE(Core::IEditor*);
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+OpenDocumentsFilter::OpenDocumentsFilter(EditorManager *editorManager) :
+ m_editorManager(editorManager)
+{
+ connect(m_editorManager, SIGNAL(editorOpened(Core::IEditor*)),
+ this, SLOT(refreshInternally()));
+ connect(m_editorManager, SIGNAL(editorsClosed(QList<Core::IEditor*>)),
+ this, SLOT(refreshInternally()));
+ setShortcutString("o");
+ setIncludedByDefault(true);
+}
+
+QList<FilterEntry> OpenDocumentsFilter::matchesFor(const QString &entry)
+{
+ QList<FilterEntry> value;
+ const QChar asterisk = QLatin1Char('*');
+ QString pattern = QString(asterisk);
+ pattern += entry;
+ pattern += asterisk;
+ const QRegExp regexp(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (!regexp.isValid())
+ return value;
+ foreach (IEditor *editor, m_editors) {
+ QString fileName = editor->file()->fileName();
+ if (regexp.exactMatch(editor->displayName())) {
+ QString visibleName;
+ QVariant data;
+ if (fileName.isEmpty()) {
+ value.append(FilterEntry(this, editor->displayName(), qVariantFromValue(editor)));
+ } else {
+ QFileInfo fi(fileName);
+ FilterEntry entry(this, fi.fileName(), fileName);
+ entry.extraInfo = QDir::toNativeSeparators(fi.path());
+ entry.resolveFileIcon = true;
+ value.append(entry);
+ }
+ }
+ }
+ return value;
+}
+
+void OpenDocumentsFilter::refreshInternally()
+{
+ m_editors = m_editorManager->openedEditors();
+}
+
+void OpenDocumentsFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+ // invokeAsyncronouslyOnGuiThread
+ connect(this, SIGNAL(invokeRefresh()), this, SLOT(refreshInternally()));
+ emit invokeRefresh();
+ disconnect(this, SIGNAL(invokeRefresh()), this, SLOT(refreshInternally()));
+}
+
+void OpenDocumentsFilter::accept(FilterEntry selection) const
+{
+ IEditor *editor = selection.internalData.value<IEditor *>();
+ if (editor) {
+ m_editorManager->setCurrentEditor(editor);
+ return;
+ }
+ m_editorManager->openEditor(selection.internalData.toString());
+ m_editorManager->ensureEditorManagerVisible();
+}
diff --git a/src/plugins/quickopen/opendocumentsfilter.h b/src/plugins/quickopen/opendocumentsfilter.h
new file mode 100644
index 0000000000..5854d1f486
--- /dev/null
+++ b/src/plugins/quickopen/opendocumentsfilter.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef OPENDOCUMENTSFILTER_H
+#define OPENDOCUMENTSFILTER_H
+
+#include "iquickopenfilter.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+#include <QtGui/QWidget>
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
+
+namespace QuickOpen {
+namespace Internal {
+
+class OpenDocumentsFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ OpenDocumentsFilter(Core::EditorManager *editorManager);
+ QString trName() const { return tr("Open document"); }
+ QString name() const { return "Open document"; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::Medium; }
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &future);
+
+public slots:
+ void refreshInternally();
+signals:
+ void invokeRefresh();
+private:
+ Core::EditorManager *m_editorManager;
+
+ QList<Core::IEditor *> m_editors;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // OPENDOCUMENTSFILTER_H
diff --git a/src/plugins/quickopen/quickopen.pri b/src/plugins/quickopen/quickopen.pri
new file mode 100644
index 0000000000..a5645e529e
--- /dev/null
+++ b/src/plugins/quickopen/quickopen.pri
@@ -0,0 +1,3 @@
+include(quickopen_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(QuickOpen)
diff --git a/src/plugins/quickopen/quickopen.pro b/src/plugins/quickopen/quickopen.pro
new file mode 100644
index 0000000000..dbacef6df5
--- /dev/null
+++ b/src/plugins/quickopen/quickopen.pro
@@ -0,0 +1,31 @@
+TEMPLATE = lib
+TARGET = QuickOpen
+DEFINES += QUICKOPEN_LIBRARY
+include(../../qworkbenchplugin.pri)
+include(quickopen_dependencies.pri)
+HEADERS += quickopenplugin.h \
+ quickopentoolwindow.h \
+ quickopenfiltersfilter.h \
+ settingspage.h \
+ iquickopenfilter.h \
+ opendocumentsfilter.h \
+ filesystemfilter.h \
+ quickopenconstants.h \
+ directoryfilter.h \
+ quickopenmanager.h \
+ basefilefilter.h \
+ quickopen_global.h
+SOURCES += quickopenplugin.cpp \
+ quickopentoolwindow.cpp \
+ quickopenfiltersfilter.cpp \
+ opendocumentsfilter.cpp \
+ filesystemfilter.cpp \
+ settingspage.cpp \
+ directoryfilter.cpp \
+ quickopenmanager.cpp \
+ basefilefilter.cpp \
+ iquickopenfilter.cpp
+FORMS += settingspage.ui \
+ filesystemfilter.ui \
+ directoryfilter.ui
+RESOURCES += quickopen.qrc
diff --git a/src/plugins/quickopen/quickopen.qrc b/src/plugins/quickopen/quickopen.qrc
new file mode 100644
index 0000000000..0ab0ff14fc
--- /dev/null
+++ b/src/plugins/quickopen/quickopen.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/quickopen" >
+ <file>images/quickopen.png</file>
+ <file>images/reload.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/quickopen/quickopen_dependencies.pri b/src/plugins/quickopen/quickopen_dependencies.pri
new file mode 100644
index 0000000000..96d71e68c8
--- /dev/null
+++ b/src/plugins/quickopen/quickopen_dependencies.pri
@@ -0,0 +1,2 @@
+include(../../libs/qtconcurrent/qtconcurrent.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/quickopen/quickopen_global.h b/src/plugins/quickopen/quickopen_global.h
new file mode 100644
index 0000000000..a16e134c8e
--- /dev/null
+++ b/src/plugins/quickopen/quickopen_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef QUICKOPEN_GLOBAL_H
+#define QUICKOPEN_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(QUICKOPEN_LIBRARY)
+# define QUICKOPEN_EXPORT Q_DECL_EXPORT
+#else
+# define QUICKOPEN_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // QUICKOPEN_GLOBAL_H
diff --git a/src/plugins/quickopen/quickopenconstants.h b/src/plugins/quickopen/quickopenconstants.h
new file mode 100644
index 0000000000..174d14475f
--- /dev/null
+++ b/src/plugins/quickopen/quickopenconstants.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QUICKOPENCONSTANTS_H
+#define QUICKOPENCONSTANTS_H
+
+namespace QuickOpen {
+namespace Constants {
+ const char * const FILTER_OPTIONS_PAGE = "Filters";
+ const char * const QUICKOPEN_CATEGORY = "QuickOpen";
+ const char * const TASK_INDEX = "QuickOpen.Task.Index";
+}
+}
+
+#endif // QUICKOPENCONSTANTS_H
diff --git a/src/plugins/quickopen/quickopenfiltersfilter.cpp b/src/plugins/quickopen/quickopenfiltersfilter.cpp
new file mode 100644
index 0000000000..18cabe45ba
--- /dev/null
+++ b/src/plugins/quickopen/quickopenfiltersfilter.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "quickopenfiltersfilter.h"
+#include "quickopenplugin.h"
+#include "quickopentoolwindow.h"
+
+#include <coreplugin/coreconstants.h>
+
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+Q_DECLARE_METATYPE(IQuickOpenFilter*);
+
+QuickOpenFiltersFilter::QuickOpenFiltersFilter(QuickOpenPlugin *plugin,
+ QuickOpenToolWindow *toolWindow):
+ m_plugin(plugin),
+ m_toolWindow(toolWindow),
+ m_icon(QIcon(Core::Constants::ICON_NEXT))
+{
+ setIncludedByDefault(true);
+ setShortcutString(QString());
+}
+
+QString QuickOpenFiltersFilter::trName() const
+{
+ return tr("Available filters");
+}
+
+QString QuickOpenFiltersFilter::name() const
+{
+ return QLatin1String("FiltersFilter");
+}
+
+IQuickOpenFilter::Priority QuickOpenFiltersFilter::priority() const
+{
+ return High;
+}
+
+QList<FilterEntry> QuickOpenFiltersFilter::matchesFor(const QString &entry)
+{
+ QList<FilterEntry> entries;
+ if (entry.isEmpty()) {
+ foreach (IQuickOpenFilter* filter, m_plugin->filter()) {
+ if (!filter->shortcutString().isEmpty()) {
+ FilterEntry entry(this,
+ filter->shortcutString(),
+ QVariant::fromValue(filter),
+ m_icon);
+ entry.extraInfo = filter->trName();
+ entries.append(entry);
+ }
+ }
+ }
+ return entries;
+}
+
+void QuickOpenFiltersFilter::accept(FilterEntry selection) const
+{
+ IQuickOpenFilter *filter = selection.internalData.value<IQuickOpenFilter*>();
+ if (filter)
+ m_toolWindow->show(filter->shortcutString() + " ",
+ filter->shortcutString().length() + 1);
+}
+
+void QuickOpenFiltersFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+ // Nothing to refresh
+}
+
+bool QuickOpenFiltersFilter::isConfigurable() const
+{
+ return false;
+}
diff --git a/src/plugins/quickopen/quickopenfiltersfilter.h b/src/plugins/quickopen/quickopenfiltersfilter.h
new file mode 100644
index 0000000000..d501d8db15
--- /dev/null
+++ b/src/plugins/quickopen/quickopenfiltersfilter.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QUICKOPENFILTERSFILTER_H
+#define QUICKOPENFILTERSFILTER_H
+
+#include "iquickopenfilter.h"
+
+#include <QtGui/QIcon>
+
+namespace QuickOpen {
+namespace Internal {
+
+class QuickOpenPlugin;
+class QuickOpenToolWindow;
+
+/*!
+ This filter provides the user with the list of available QuickOpen filters.
+ The list is only shown when nothing has been typed yet.
+ */
+class QuickOpenFiltersFilter : public IQuickOpenFilter
+{
+public:
+ QuickOpenFiltersFilter(QuickOpenPlugin *plugin,
+ QuickOpenToolWindow *toolWindow);
+
+ // IQuickOpenFilter
+ QString trName() const;
+ QString name() const;
+ Priority priority() const;
+ QList<FilterEntry> matchesFor(const QString &entry);
+ void accept(FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &future);
+ bool isConfigurable() const;
+
+private:
+ QuickOpenPlugin *m_plugin;
+ QuickOpenToolWindow *m_toolWindow;
+ QIcon m_icon;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // QUICKOPENFILTERSFILTER_H
diff --git a/src/plugins/quickopen/quickopenmanager.cpp b/src/plugins/quickopen/quickopenmanager.cpp
new file mode 100644
index 0000000000..91a8619582
--- /dev/null
+++ b/src/plugins/quickopen/quickopenmanager.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "quickopenmanager.h"
+#include "quickopentoolwindow.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+QuickOpenManager *QuickOpenManager::m_instance = 0;
+
+QuickOpenManager::QuickOpenManager(QuickOpenToolWindow *toolWindow)
+ : QObject(toolWindow),
+ m_toolWindow(toolWindow)
+{
+ m_instance = this;
+}
+
+QuickOpenManager::~QuickOpenManager()
+{
+ ExtensionSystem::PluginManager::instance()->removeObject(this);
+ m_instance = 0;
+}
+
+void QuickOpenManager::show(const QString &text,
+ int selectionStart, int selectionLength)
+{
+ Q_ASSERT(m_toolWindow);
+ m_toolWindow->show(text, selectionStart, selectionLength);
+}
diff --git a/src/plugins/quickopen/quickopenmanager.h b/src/plugins/quickopen/quickopenmanager.h
new file mode 100644
index 0000000000..850ce6cfa1
--- /dev/null
+++ b/src/plugins/quickopen/quickopenmanager.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QUICKOPENMANAGER_H
+#define QUICKOPENMANAGER_H
+
+#include "quickopen_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace QuickOpen {
+
+namespace Internal {
+class QuickOpenToolWindow;
+}
+
+class QUICKOPEN_EXPORT QuickOpenManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ QuickOpenManager(Internal::QuickOpenToolWindow *toolWindow);
+ ~QuickOpenManager();
+
+ static QuickOpenManager* instance() { return m_instance; }
+
+ void show(const QString &text, int selectionStart = -1, int selectionLength = 0);
+
+private:
+ Internal::QuickOpenToolWindow *m_toolWindow;
+ static QuickOpenManager *m_instance;
+};
+
+} // namespace QuickOpen
+
+#endif // QUICKOPENMANAGER_H
diff --git a/src/plugins/quickopen/quickopenplugin.cpp b/src/plugins/quickopen/quickopenplugin.cpp
new file mode 100644
index 0000000000..c6a6b00602
--- /dev/null
+++ b/src/plugins/quickopen/quickopenplugin.cpp
@@ -0,0 +1,252 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "quickopenplugin.h"
+#include "quickopenfiltersfilter.h"
+#include "quickopenmanager.h"
+#include "quickopentoolwindow.h"
+#include "opendocumentsfilter.h"
+#include "filesystemfilter.h"
+#include "directoryfilter.h"
+#include "settingspage.h"
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QSettings>
+#include <QtCore/QFuture>
+#include <QtCore/QFutureWatcher>
+
+#include <coreplugin/baseview.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <qtconcurrent/QtConcurrentTools>
+
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+namespace {
+ static bool filterLessThan(const IQuickOpenFilter *first, const IQuickOpenFilter *second)
+ {
+ return first->priority() < second->priority();
+ }
+}
+
+QuickOpenPlugin::QuickOpenPlugin()
+{
+ m_refreshTimer.setSingleShot(false);
+ connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
+}
+
+QuickOpenPlugin::~QuickOpenPlugin()
+{
+ removeObject(m_openDocumentsFilter);
+ removeObject(m_fileSystemFilter);
+ removeObject(m_settingsPage);
+ delete m_openDocumentsFilter;
+ delete m_fileSystemFilter;
+ delete m_settingsPage;
+ foreach (IQuickOpenFilter *filter, m_customFilter)
+ delete filter;
+}
+
+bool QuickOpenPlugin::initialize(const QStringList &, QString *)
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ m_settingsPage = new SettingsPage(core, this);
+ addObject(m_settingsPage);
+
+ m_quickOpenToolWindow = new QuickOpenToolWindow(this);
+ m_quickOpenToolWindow->setEnabled(false);
+ Core::BaseView *view = new Core::BaseView("QuickOpen.ToolWindow",
+ m_quickOpenToolWindow,
+ QList<int>() << core->uniqueIDManager()->uniqueIdentifier(QLatin1String("QuickOpenToolWindow")),
+ Core::IView::First);
+ addAutoReleasedObject(view);
+
+ const QString actionId = QLatin1String("QtCreator.View.QuickOpen.ToolWindow");
+ QAction *action = new QAction(m_quickOpenToolWindow->windowIcon(), m_quickOpenToolWindow->windowTitle(), this);
+ Core::ICommand *cmd = core->actionManager()->registerAction(action, actionId, QList<int>() << Core::Constants::C_GLOBAL_ID);
+ cmd->setDefaultKeySequence(QKeySequence("Ctrl+K"));
+ connect(action, SIGNAL(triggered()), this, SLOT(openQuickOpen()));
+
+ Core::IActionContainer *mtools = core->actionManager()->actionContainer(Core::Constants::M_TOOLS);
+ mtools->addAction(cmd);
+
+ addObject(new QuickOpenManager(m_quickOpenToolWindow));
+
+ m_openDocumentsFilter = new OpenDocumentsFilter(core->editorManager());
+ addObject(m_openDocumentsFilter);
+
+ m_fileSystemFilter = new FileSystemFilter(core->editorManager(), m_quickOpenToolWindow);
+ addObject(m_fileSystemFilter);
+
+ addAutoReleasedObject(new QuickOpenFiltersFilter(this, m_quickOpenToolWindow));
+
+ connect(core, SIGNAL(coreOpened()), this, SLOT(startSettingsLoad()));
+ return true;
+}
+
+void QuickOpenPlugin::openQuickOpen()
+{
+ m_quickOpenToolWindow->setFocus();
+}
+
+void QuickOpenPlugin::extensionsInitialized()
+{
+ m_filter = ExtensionSystem::PluginManager::instance()->getObjects<IQuickOpenFilter>();
+ qSort(m_filter.begin(), m_filter.end(), filterLessThan);
+}
+
+void QuickOpenPlugin::startSettingsLoad()
+{
+ m_loadWatcher.setFuture(QtConcurrent::run(this, &QuickOpenPlugin::loadSettings));
+ connect(&m_loadWatcher, SIGNAL(finished()), this, SLOT(settingsLoaded()));
+}
+
+void QuickOpenPlugin::loadSettings()
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ QSettings settings;
+ settings.beginGroup("QuickOpen");
+ m_refreshTimer.setInterval(settings.value("RefreshInterval", 60).toInt()*60000);
+ foreach (IQuickOpenFilter *filter, m_filter) {
+ if (settings.contains(filter->name())) {
+ const QByteArray state = settings.value(filter->name()).toByteArray();
+ if (!state.isEmpty())
+ filter->restoreState(state);
+ }
+ }
+ settings.beginGroup("CustomFilters");
+ QList<IQuickOpenFilter *> customFilters;
+ foreach (const QString &key, settings.childKeys()) {
+ IQuickOpenFilter *filter = new DirectoryFilter(core);
+ filter->restoreState(settings.value(key).toByteArray());
+ m_filter.append(filter);
+ customFilters.append(filter);
+ }
+ setCustomFilter(customFilters);
+ settings.endGroup();
+ settings.endGroup();
+}
+
+void QuickOpenPlugin::settingsLoaded()
+{
+ m_quickOpenToolWindow->updateFilterList();
+ m_quickOpenToolWindow->setEnabled(true);
+ m_refreshTimer.start();
+}
+
+void QuickOpenPlugin::saveSettings()
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (core && core->settings()) {
+ QSettings *s = core->settings();
+ s->beginGroup("QuickOpen");
+ s->setValue("Interval", m_refreshTimer.interval()/60000);
+ s->remove("");
+ foreach (IQuickOpenFilter *filter, m_filter) {
+ if (!m_customFilter.contains(filter)) {
+ s->setValue(filter->name(), filter->saveState());
+ }
+ }
+ s->beginGroup("CustomFilters");
+ int i = 0;
+ foreach (IQuickOpenFilter *filter, m_customFilter) {
+ s->setValue(QString("directory%1").arg(i), filter->saveState());
+ ++i;
+ }
+ s->endGroup();
+ s->endGroup();
+ }
+}
+
+/*!
+ \fn QList<IQuickOpenFilter*> QuickOpenPlugin::filter()
+
+ Return all filters, including the ones created by the user.
+*/
+QList<IQuickOpenFilter*> QuickOpenPlugin::filter()
+{
+ return m_filter;
+}
+
+/*!
+ \fn QList<IQuickOpenFilter*> QuickOpenPlugin::customFilter()
+
+ This returns a subset of all the filters, that contains only the filters that
+ have been created by the user at some point (maybe in a previous session).
+ */
+QList<IQuickOpenFilter*> QuickOpenPlugin::customFilter()
+{
+ return m_customFilter;
+}
+
+void QuickOpenPlugin::setFilter(QList<IQuickOpenFilter*> f)
+{
+ m_filter = f;
+ m_quickOpenToolWindow->updateFilterList();
+}
+
+void QuickOpenPlugin::setCustomFilter(QList<IQuickOpenFilter *> filter)
+{
+ m_customFilter = filter;
+}
+
+int QuickOpenPlugin::refreshInterval()
+{
+ return m_refreshTimer.interval()/60000;
+}
+
+void QuickOpenPlugin::setRefreshInterval(int interval)
+{
+ if (interval < 1) {
+ m_refreshTimer.stop();
+ m_refreshTimer.setInterval(0);
+ return;
+ }
+ m_refreshTimer.setInterval(interval*60000);
+ m_refreshTimer.start();
+}
+
+void QuickOpenPlugin::refresh(QList<IQuickOpenFilter*> filters)
+{
+ if (filters.isEmpty())
+ filters = m_filter;
+ QFuture<void> task = QtConcurrent::run(&IQuickOpenFilter::refresh, filters);
+ Core::FutureProgress *progress = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()
+ ->progressManager()->addTask(task, tr("Indexing"), Constants::TASK_INDEX, Core::ProgressManagerInterface::CloseOnSuccess);
+ connect(progress, SIGNAL(finished()), this, SLOT(saveSettings()));
+}
+
+Q_EXPORT_PLUGIN(QuickOpenPlugin)
diff --git a/src/plugins/quickopen/quickopenplugin.h b/src/plugins/quickopen/quickopenplugin.h
new file mode 100644
index 0000000000..5400154cb8
--- /dev/null
+++ b/src/plugins/quickopen/quickopenplugin.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QUICKOPENPLUGIN_H
+#define QUICKOPENPLUGIN_H
+
+#include "iquickopenfilter.h"
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QTimer>
+#include <QtCore/QFutureWatcher>
+
+namespace QuickOpen {
+namespace Internal {
+
+class QuickOpenToolWindow;
+class OpenDocumentsFilter;
+class FileSystemFilter;
+class SettingsPage;
+
+class QuickOpenPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ QuickOpenPlugin();
+ ~QuickOpenPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+ QList<IQuickOpenFilter*> filter();
+ QList<IQuickOpenFilter*> customFilter();
+ void setFilter(QList<IQuickOpenFilter*> f);
+ void setCustomFilter(QList<IQuickOpenFilter*> f);
+ int refreshInterval();
+ void setRefreshInterval(int interval);
+
+public slots:
+ void refresh(QList<IQuickOpenFilter*> filters = QList<IQuickOpenFilter*>());
+ void saveSettings();
+ void openQuickOpen();
+
+private slots:
+ void startSettingsLoad();
+ void settingsLoaded();
+
+private:
+ void loadSettings();
+
+ QuickOpenToolWindow *m_quickOpenToolWindow;
+ SettingsPage *m_settingsPage;
+
+ QList<IQuickOpenFilter*> m_filter;
+ QList<IQuickOpenFilter*> m_customFilter;
+ int m_refreshInterval;
+ QTimer m_refreshTimer;
+ OpenDocumentsFilter *m_openDocumentsFilter;
+ FileSystemFilter *m_fileSystemFilter;
+ QFutureWatcher<void> m_loadWatcher;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // QUICKOPENPLUGIN_H
diff --git a/src/plugins/quickopen/quickopentoolwindow.cpp b/src/plugins/quickopen/quickopentoolwindow.cpp
new file mode 100644
index 0000000000..f6ca212c82
--- /dev/null
+++ b/src/plugins/quickopen/quickopentoolwindow.cpp
@@ -0,0 +1,484 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <qglobal.h>
+
+namespace QuickOpen {
+struct FilterEntry;
+}
+
+QT_BEGIN_NAMESPACE
+unsigned int qHash(const QuickOpen::FilterEntry &entry);
+QT_END_NAMESPACE
+
+#include "quickopentoolwindow.h"
+#include "quickopenplugin.h"
+#include "quickopenconstants.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/fileiconprovider.h>
+#include <utils/fancylineedit.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
+#include <QtCore/QTimer>
+#include <QtCore/QRegExp>
+#include <QtCore/QSettings>
+#include <QtCore/QDebug>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QHeaderView>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QPushButton>
+#include <QtGui/QScrollBar>
+#include <QtGui/QTreeView>
+
+Q_DECLARE_METATYPE(QuickOpen::IQuickOpenFilter*);
+Q_DECLARE_METATYPE(QuickOpen::FilterEntry);
+
+namespace QuickOpen {
+namespace Internal {
+
+/*! A model to represent the QuickOpen results. */
+class QuickOpenModel : public QAbstractListModel
+{
+public:
+ QuickOpenModel(QObject *parent = 0)
+ : QAbstractListModel(parent)
+// , mDisplayCount(64)
+ {}
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ void setEntries(const QList<FilterEntry> &entries);
+ //void setDisplayCount(int count);
+
+private:
+ mutable QList<FilterEntry> mEntries;
+ //int mDisplayCount;
+};
+
+class CompletionList : public QTreeView
+{
+public:
+ CompletionList(QWidget *parent = 0);
+
+ void updatePreferredSize();
+ QSize preferredSize() const { return m_preferredSize; }
+
+private:
+ QSize m_preferredSize;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+QT_BEGIN_NAMESPACE
+uint qHash(const FilterEntry &entry)
+{
+ if (entry.internalData.canConvert(QVariant::String))
+ return qHash(entry.internalData.toString());
+ return qHash(entry.internalData.constData());
+}
+QT_END_NAMESPACE
+
+
+// =========== QuickOpenModel ===========
+
+int QuickOpenModel::rowCount(const QModelIndex & /* parent */) const
+{
+ return mEntries.size();
+}
+
+int QuickOpenModel::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : 2;
+}
+
+/*!
+ * When asked for the icon via Qt::DecorationRole, the QuickOpenModel lazily
+ * resolves and caches the Greehouse-specific file icon when
+ * FilterEntry::resolveFileIcon is true. FilterEntry::internalData is assumed
+ * to be the filename.
+ */
+QVariant QuickOpenModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= mEntries.size())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ if (index.column() == 0) {
+ return mEntries.at(index.row()).displayName;
+ } else if (index.column() == 1) {
+ return mEntries.at(index.row()).extraInfo;
+ }
+ } else if (role == Qt::DecorationRole && index.column() == 0) {
+ FilterEntry &entry = mEntries[index.row()];
+ if (entry.resolveFileIcon && entry.displayIcon.isNull()) {
+ entry.resolveFileIcon = false;
+ entry.displayIcon =
+ Core::FileIconProvider::instance()->icon(QFileInfo(entry.internalData.toString()));
+ }
+ return entry.displayIcon;
+ } else if (role == Qt::ForegroundRole && index.column() == 1) {
+ return Qt::darkGray;
+ } else if (role == Qt::UserRole) {
+ return qVariantFromValue(mEntries.at(index.row()));
+ }
+
+ return QVariant();
+}
+
+void QuickOpenModel::setEntries(const QList<FilterEntry> &entries)
+{
+ mEntries = entries;
+ reset();
+}
+#if 0
+void QuickOpenModel::setDisplayCount(int count)
+{
+ // TODO: This method is meant to be used for increasing the number of items displayed at the
+ // user's request. There is however no way yet for the user to request this.
+ if (count == mDisplayCount)
+ return;
+
+ const int displayedOld = qMin(mDisplayCount, mEntries.size());
+ const int displayedNew = qMin(count, mEntries.size());
+
+ if (displayedNew < displayedOld)
+ beginRemoveRows(QModelIndex(), displayedNew - 1, displayedOld - 1);
+ else if (displayedNew > displayedOld)
+ beginInsertRows(QModelIndex(), displayedOld - 1, displayedNew - 1);
+
+ mDisplayCount = count;
+
+ if (displayedNew < displayedOld)
+ endRemoveRows();
+ else if (displayedNew > displayedOld)
+ endInsertRows();
+}
+#endif
+
+// =========== CompletionList ===========
+
+CompletionList::CompletionList(QWidget *parent)
+ : QTreeView(parent)
+{
+ setRootIsDecorated(false);
+ setUniformRowHeights(true);
+ setMaximumWidth(900);
+ header()->hide();
+ header()->setStretchLastSection(true);
+ // This is too slow when done on all results
+ //header()->setResizeMode(QHeaderView::ResizeToContents);
+ setWindowFlags(Qt::ToolTip);
+}
+
+void CompletionList::updatePreferredSize()
+{
+ //header()->setStretchLastSection(false);
+ //updateGeometries();
+
+ const QStyleOptionViewItem &option = viewOptions();
+ const QSize shint = itemDelegate()->sizeHint(option, model()->index(0, 0));
+#if 0
+ const int visibleItems = model()->rowCount();
+
+ // TODO: Look into enabling preferred height as well. Current problem is that this doesn't
+ // work nicely from the user perspective if the list is popping up instead of down.
+ //const int h = shint.height() * visibleItems;
+
+ const QScrollBar *vscroll = verticalScrollBar();
+ int preferredWidth = header()->length() + frameWidth() * 2
+ + (vscroll->isVisibleTo(this) ? vscroll->width() : 0);
+ const int diff = preferredWidth - width();
+
+ // Avoid resizing the list widget when there are no results or when the preferred size is
+ // only a little smaller than our current size
+ if (visibleItems == 0 || (diff > -100 && diff < 0))
+ preferredWidth = width();
+#endif
+
+ m_preferredSize = QSize(600, //qMax(600, preferredWidth),
+ shint.height() * 17 + frameWidth() * 2);
+ //header()->setStretchLastSection(true);
+}
+
+
+// =========== QuickOpenToolWindow ===========
+
+QuickOpenToolWindow::QuickOpenToolWindow(QuickOpenPlugin *qop) :
+ m_quickOpenPlugin(qop),
+ m_quickOpenModel(new QuickOpenModel(this)),
+ m_completionList(new CompletionList(this)),
+ m_filterMenu(new QMenu(this)),
+ m_refreshAction(new QAction(tr("Refresh"), this)),
+ m_configureAction(new QAction(tr("Configure..."), this)),
+ m_fileLineEdit(new Core::Utils::FancyLineEdit)
+{
+ // Explcitly hide the completion list popup.
+ m_completionList->hide();
+
+ setWindowTitle("Quick Open");
+ resize(200, 90);
+ QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ setSizePolicy(sizePolicy);
+ setMinimumSize(QSize(200, 0));
+
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ setLayout(layout);
+ layout->setMargin(0);
+ layout->addWidget(m_fileLineEdit);
+
+ setWindowIcon(QIcon(":/quickopen/images/quickopen.png"));
+ QPixmap image(Core::Constants::ICON_MAGNIFIER);
+ m_fileLineEdit->setPixmap(image);
+ m_fileLineEdit->setUseLayoutDirection(true);
+ m_fileLineEdit->setHintText(tr("Type to QuickOpen"));
+ m_fileLineEdit->setFocusPolicy(Qt::ClickFocus);
+
+ m_fileLineEdit->installEventFilter(this);
+ this->installEventFilter(this);
+
+ m_completionList->setModel(m_quickOpenModel);
+ m_completionList->header()->resizeSection(0, 300);
+ m_completionList->updatePreferredSize();
+ m_completionList->resize(m_completionList->preferredSize());
+
+ m_filterMenu->addAction(m_refreshAction);
+ m_filterMenu->addAction(m_configureAction);
+
+ m_fileLineEdit->setMenu( m_filterMenu);
+
+ connect(m_refreshAction, SIGNAL(triggered()), m_quickOpenPlugin, SLOT(refresh()));
+ connect(m_configureAction, SIGNAL(triggered()), this, SLOT(showConfigureDialog()));
+ connect(m_fileLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(textEdited(const QString&)));
+ connect(m_completionList, SIGNAL(activated(QModelIndex)),
+ this, SLOT(acceptCurrentEntry()));
+}
+
+bool QuickOpenToolWindow::isShowingTypeHereMessage() const
+{
+ return m_fileLineEdit->isShowingHintText();
+}
+
+void QuickOpenToolWindow::updateFilterList()
+{
+ m_filterMenu->clear();
+ foreach (IQuickOpenFilter *filter, m_quickOpenPlugin->filter()) {
+ if (!filter->shortcutString().isEmpty()) {
+ QAction *action = m_filterMenu->addAction(filter->trName(), this, SLOT(filterSelected()));
+ action->setData(qVariantFromValue(filter));
+ }
+ }
+ m_filterMenu->addSeparator();
+ m_filterMenu->addAction(m_refreshAction);
+ m_filterMenu->addAction(m_configureAction);
+}
+
+bool QuickOpenToolWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == m_fileLineEdit && event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ switch (keyEvent->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ showCompletionList();
+ QApplication::sendEvent(m_completionList, event);
+ return true;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ acceptCurrentEntry();
+ return true;
+ case Qt::Key_Escape:
+ m_completionList->hide();
+ return true;
+ default:
+ break;
+ }
+ } else if (obj == m_fileLineEdit && event->type() == QEvent::FocusOut) {
+ m_completionList->hide();
+ } else if (obj == m_fileLineEdit && event->type() == QEvent::FocusIn) {
+ updateCompletionList(m_fileLineEdit->typedText());
+ showCompletionList();
+ } else if (obj == this && event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
+ event->accept();
+ QTimer::singleShot(0, Core::ModeManager::instance(), SLOT(setFocusToCurrentMode()));
+ return true;
+ }
+ }
+ return QWidget::eventFilter(obj, event);
+}
+
+void QuickOpenToolWindow::showCompletionList()
+{
+ const int border = m_completionList->frameWidth();
+ const QSize size = m_completionList->preferredSize();
+ const QRect rect(mapToGlobal(QPoint(-border, -size.height() - border)), size);
+ m_completionList->setGeometry(rect);
+ m_completionList->show();
+}
+
+void QuickOpenToolWindow::textEdited(const QString &text)
+{
+ updateCompletionList(text);
+ showCompletionList();
+}
+
+QList<IQuickOpenFilter*> QuickOpenToolWindow::filtersFor(const QString &text, QString &searchText)
+{
+ QList<IQuickOpenFilter*> filters = m_quickOpenPlugin->filter();
+ int whiteSpace = text.indexOf(" ");
+ QString prefix;
+ if (whiteSpace >= 0)
+ prefix = text.left(whiteSpace);
+ if (!prefix.isEmpty()) {
+ prefix = prefix.toLower();
+ foreach (IQuickOpenFilter *filter, filters) {
+ if (prefix == filter->shortcutString()) {
+ searchText = text.mid(whiteSpace+1);
+ return QList<IQuickOpenFilter*>() << filter;
+ }
+ }
+ }
+ searchText = text;
+ QList<IQuickOpenFilter*> activeFilters;
+ foreach (IQuickOpenFilter *filter, filters)
+ if (filter->defaultActiveState())
+ activeFilters << filter;
+ return activeFilters;
+}
+
+void QuickOpenToolWindow::updateCompletionList(const QString &text)
+{
+ QString searchText;
+ const QList<IQuickOpenFilter*> filters = filtersFor(text, searchText);
+ QSet<FilterEntry> alreadyAdded;
+ const bool checkDuplicates = (filters.size() > 1);
+ QList<FilterEntry> entries;
+ foreach (IQuickOpenFilter *filter, filters) {
+ foreach (const FilterEntry &entry, filter->matchesFor(searchText)) {
+ if (checkDuplicates && alreadyAdded.contains(entry))
+ continue;
+ entries.append(entry);
+ if (checkDuplicates)
+ alreadyAdded.insert(entry);
+ }
+ }
+ m_quickOpenModel->setEntries(entries);
+ if (m_quickOpenModel->rowCount() > 0) {
+ m_completionList->setCurrentIndex(m_quickOpenModel->index(0, 0));
+ }
+#if 0
+ m_completionList->updatePreferredSize();
+#endif
+}
+
+void QuickOpenToolWindow::acceptCurrentEntry()
+{
+ if (!m_completionList->isVisible())
+ return;
+ const QModelIndex index = m_completionList->currentIndex();
+ if (!index.isValid())
+ return;
+ const FilterEntry entry = m_quickOpenModel->data(index, Qt::UserRole).value<FilterEntry>();
+ m_completionList->hide();
+ entry.filter->accept(entry);
+}
+
+void QuickOpenToolWindow::show(const QString &text, int selectionStart, int selectionLength)
+{
+ m_fileLineEdit->hideHintText();
+ m_fileLineEdit->setText(text);
+ setFocus();
+ if (selectionStart >= 0)
+ m_fileLineEdit->setSelection(selectionStart, selectionLength);
+ else
+ m_fileLineEdit->deselect();
+}
+
+void QuickOpenToolWindow::filterSelected()
+{
+ const char * const TEXT = "<type here>";
+ QAction *action = qobject_cast<QAction*>(sender());
+ Q_ASSERT(action);
+ IQuickOpenFilter *filter = action->data().value<IQuickOpenFilter*>();
+ Q_ASSERT(filter);
+ show(filter->shortcutString() + " " + TEXT,
+ filter->shortcutString().length() + 1,
+ QString(TEXT).length());
+ updateCompletionList(m_fileLineEdit->text());
+ m_fileLineEdit->setFocus();
+}
+
+void QuickOpenToolWindow::focusInEvent(QFocusEvent *e)
+{
+ m_fileLineEdit->setFocus(e->reason());
+ if (e->reason() != Qt::MouseFocusReason) {
+ m_fileLineEdit->selectAll();
+ }
+ QWidget::focusInEvent(e);
+}
+
+void QuickOpenToolWindow::showEvent(QShowEvent *event)
+{
+ QWidget::showEvent(event);
+}
+
+void QuickOpenToolWindow::showConfigureDialog()
+{
+ ExtensionSystem::PluginManager::instance()
+ ->getObject<Core::ICore>()->showOptionsDialog(Constants::QUICKOPEN_CATEGORY,
+ Constants::FILTER_OPTIONS_PAGE);
+}
diff --git a/src/plugins/quickopen/quickopentoolwindow.h b/src/plugins/quickopen/quickopentoolwindow.h
new file mode 100644
index 0000000000..e31280d1af
--- /dev/null
+++ b/src/plugins/quickopen/quickopentoolwindow.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QUICKOPENTOOLWINDOW_H
+#define QUICKOPENTOOLWINDOW_H
+
+#include <QtCore/QEvent>
+#include <QtGui/QWidget>
+
+#include "quickopenplugin.h"
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QLabel;
+class QLineEdit;
+class QMenu;
+class QTreeView;
+QT_END_NAMESPACE
+
+namespace Core {
+ namespace Utils {
+ class FancyLineEdit;
+ }
+}
+namespace QuickOpen {
+namespace Internal {
+
+class QuickOpenModel;
+class CompletionList;
+
+class QuickOpenToolWindow
+ : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QuickOpenToolWindow(QuickOpenPlugin *qop);
+
+ void updateFilterList();
+
+ void show(const QString &text, int selectionStart = -1, int selectionLength = 0);
+
+private slots:
+ void textEdited(const QString &text);
+ void acceptCurrentEntry();
+ void filterSelected();
+ void showConfigureDialog();
+
+private:
+ bool eventFilter(QObject *obj, QEvent *event);
+
+ void showEvent(QShowEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ bool isShowingTypeHereMessage() const;
+ void showCompletionList();
+ void updateCompletionList(const QString &text);
+ QList<IQuickOpenFilter*> filtersFor(const QString &text, QString &searchText);
+
+ QuickOpenPlugin *m_quickOpenPlugin;
+ QuickOpenModel *m_quickOpenModel;
+
+ CompletionList *m_completionList;
+ QMenu *m_filterMenu;
+ QAction *m_refreshAction;
+ QAction *m_configureAction;
+ Core::Utils::FancyLineEdit *m_fileLineEdit;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // QUICKOPENTOOLWINDOW_H
diff --git a/src/plugins/quickopen/settingspage.cpp b/src/plugins/quickopen/settingspage.cpp
new file mode 100644
index 0000000000..4b75aa1756
--- /dev/null
+++ b/src/plugins/quickopen/settingspage.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+#include "quickopenplugin.h"
+#include "iquickopenfilter.h"
+#include "directoryfilter.h"
+
+#include <QtGui/QMessageBox>
+
+#include <qtconcurrent/QtConcurrentTools>
+
+Q_DECLARE_METATYPE(QuickOpen::IQuickOpenFilter*)
+
+using namespace QuickOpen;
+using namespace QuickOpen::Internal;
+
+SettingsPage::SettingsPage(Core::ICore *core, QuickOpenPlugin *plugin)
+ : m_core(core), m_plugin(plugin), m_page(0)
+{
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ if (!m_page) {
+ m_page = new QWidget(parent);
+ m_ui.setupUi(m_page);
+ connect(m_ui.filterList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
+ this, SLOT(updateButtonStates()));
+ connect(m_ui.filterList, SIGNAL(itemActivated(QListWidgetItem *)),
+ this, SLOT(configureFilter(QListWidgetItem *)));
+ connect(m_ui.editButton, SIGNAL(clicked()),
+ this, SLOT(configureFilter()));
+ connect(m_ui.addButton, SIGNAL(clicked()),
+ this, SLOT(addCustomFilter()));
+ connect(m_ui.removeButton, SIGNAL(clicked()),
+ this, SLOT(removeCustomFilter()));
+ }
+ m_ui.refreshInterval->setValue(m_plugin->refreshInterval());
+ m_filters = m_plugin->filter();
+ m_customFilters = m_plugin->customFilter();
+ saveFilterStates();
+ updateFilterList();
+ return m_page;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted) {
+ restoreFilterStates();
+ foreach (IQuickOpenFilter *filter, m_addedFilters)
+ delete filter;
+ } else {
+ foreach (IQuickOpenFilter *filter, m_removedFilters)
+ delete filter;
+ m_plugin->setFilter(m_filters);
+ m_plugin->setCustomFilter(m_customFilters);
+ m_plugin->setRefreshInterval(m_ui.refreshInterval->value());
+ requestRefresh();
+ m_plugin->saveSettings();
+ }
+ m_addedFilters.clear();
+ m_removedFilters.clear();
+ m_filters.clear();
+ m_customFilters.clear();
+ m_refreshFilters.clear();
+}
+
+void SettingsPage::requestRefresh()
+{
+ if (!m_refreshFilters.isEmpty())
+ m_plugin->refresh(m_refreshFilters);
+}
+
+void SettingsPage::saveFilterStates()
+{
+ m_filterStates.clear();
+ foreach (IQuickOpenFilter *filter, m_filters)
+ m_filterStates.insert(filter, filter->saveState());
+}
+
+void SettingsPage::restoreFilterStates()
+{
+ foreach (IQuickOpenFilter *filter, m_filterStates.keys())
+ filter->restoreState(m_filterStates.value(filter));
+}
+
+void SettingsPage::updateFilterList()
+{
+ m_ui.filterList->clear();
+ foreach (IQuickOpenFilter *filter, m_filters) {
+ QString title;
+ if (filter->defaultActiveState())
+ title = filter->trName();
+ else
+ title = tr("%1 (Prefix: %2)").arg(filter->trName()).arg(filter->shortcutString());
+ QListWidgetItem *item = new QListWidgetItem(title);
+ item->setData(Qt::UserRole, qVariantFromValue(filter));
+ m_ui.filterList->addItem(item);
+ }
+ if (m_ui.filterList->count() > 0)
+ m_ui.filterList->setCurrentRow(0);
+}
+
+void SettingsPage::updateButtonStates()
+{
+ QListWidgetItem *item = m_ui.filterList->currentItem();
+ IQuickOpenFilter *filter = (item ? item->data(Qt::UserRole).value<IQuickOpenFilter *>() : 0);
+ m_ui.editButton->setEnabled(filter && filter->isConfigurable());
+ m_ui.removeButton->setEnabled(filter && m_customFilters.contains(filter));
+}
+
+void SettingsPage::configureFilter(QListWidgetItem *item)
+{
+ if (!item)
+ item = m_ui.filterList->currentItem();
+ Q_ASSERT(item);
+ IQuickOpenFilter *filter = item->data(Qt::UserRole).value<IQuickOpenFilter *>();
+ Q_ASSERT(filter);
+ if (!filter->isConfigurable())
+ return;
+ bool needsRefresh = false;
+ filter->openConfigDialog(m_page, needsRefresh);
+ if (needsRefresh && !m_refreshFilters.contains(filter))
+ m_refreshFilters.append(filter);
+ updateFilterList();
+}
+
+void SettingsPage::addCustomFilter()
+{
+ IQuickOpenFilter *filter = new DirectoryFilter(m_core);
+ bool needsRefresh = false;
+ if (filter->openConfigDialog(m_page, needsRefresh)) {
+ m_filters.append(filter);
+ m_addedFilters.append(filter);
+ m_customFilters.append(filter);
+ m_refreshFilters.append(filter);
+ updateFilterList();
+ }
+}
+
+void SettingsPage::removeCustomFilter()
+{
+ QListWidgetItem *item = m_ui.filterList->currentItem();
+ Q_ASSERT(item);
+ IQuickOpenFilter *filter = item->data(Qt::UserRole).value<IQuickOpenFilter *>();
+ Q_ASSERT(m_customFilters.contains(filter));
+ m_filters.removeAll(filter);
+ m_customFilters.removeAll(filter);
+ m_refreshFilters.removeAll(filter);
+ if (m_addedFilters.contains(filter)) {
+ m_addedFilters.removeAll(filter);
+ delete filter;
+ } else {
+ m_removedFilters.append(filter);
+ }
+ updateFilterList();
+}
diff --git a/src/plugins/quickopen/settingspage.h b/src/plugins/quickopen/settingspage.h
new file mode 100644
index 0000000000..2ad79be3cd
--- /dev/null
+++ b/src/plugins/quickopen/settingspage.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSPAGE_H
+#define SETTINGSPAGE_H
+
+#include "ui_settingspage.h"
+#include "quickopenconstants.h"
+
+#include <QtCore/QPointer>
+#include <QtCore/QHash>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <coreplugin/icore.h>
+
+QT_BEGIN_NAMESPACE
+class QListWidgetItem;
+QT_END_NAMESPACE
+
+namespace QuickOpen {
+
+class IQuickOpenFilter;
+
+namespace Internal {
+
+class QuickOpenPlugin;
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SettingsPage(Core::ICore *core, QuickOpenPlugin *plugin);
+ QString name() const { return tr(Constants::FILTER_OPTIONS_PAGE); }
+ QString category() const { return Constants::QUICKOPEN_CATEGORY; }
+ QString trCategory() const { return tr(Constants::QUICKOPEN_CATEGORY); }
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+private slots:
+ void updateButtonStates();
+ void configureFilter(QListWidgetItem *item = 0);
+ void addCustomFilter();
+ void removeCustomFilter();
+
+private:
+ void updateFilterList();
+ void saveFilterStates();
+ void restoreFilterStates();
+ void requestRefresh();
+
+ Ui::SettingsWidget m_ui;
+ Core::ICore *m_core;
+ QuickOpenPlugin *m_plugin;
+ QPointer<QWidget> m_page;
+ QList<IQuickOpenFilter *> m_filters;
+ QList<IQuickOpenFilter *> m_addedFilters;
+ QList<IQuickOpenFilter *> m_removedFilters;
+ QList<IQuickOpenFilter *> m_customFilters;
+ QList<IQuickOpenFilter *> m_refreshFilters;
+ QHash<IQuickOpenFilter *, QByteArray> m_filterStates;
+};
+
+} // namespace Internal
+} // namespace QuickOpen
+
+#endif // SETTINGSPAGE_H
diff --git a/src/plugins/quickopen/settingspage.ui b/src/plugins/quickopen/settingspage.ui
new file mode 100644
index 0000000000..f9145404d2
--- /dev/null
+++ b/src/plugins/quickopen/settingspage.ui
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QuickOpen::Internal::SettingsWidget</class>
+ <widget class="QWidget" name="QuickOpen::Internal::SettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>460</width>
+ <height>353</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Filters</string>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QListWidget" name="filterList">
+ <property name="font">
+ <font/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Refresh Interval:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="refreshInterval">
+ <property name="frame">
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::PlusMinus</enum>
+ </property>
+ <property name="value">
+ <number>60</number>
+ </property>
+ <property name="suffix">
+ <string> min</string>
+ </property>
+ <property name="maximum">
+ <number>320</number>
+ </property>
+ <property name="singleStep">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/quickopen/settingswidget.ui b/src/plugins/quickopen/settingswidget.ui
new file mode 100644
index 0000000000..bc01858c81
--- /dev/null
+++ b/src/plugins/quickopen/settingswidget.ui
@@ -0,0 +1,133 @@
+<ui version="4.0" >
+ <class>QuickOpen::Internal::SettingsDialog</class>
+ <widget class="QWidget" name="QuickOpen::Internal::SettingsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>460</width>
+ <height>353</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Configure Filters</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QListWidget" name="filterList" >
+ <property name="font" >
+ <font/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="addButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Refresh Intervall:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="refreshIntervall" >
+ <property name="frame" >
+ <bool>true</bool>
+ </property>
+ <property name="buttonSymbols" >
+ <enum>QAbstractSpinBox::PlusMinus</enum>
+ </property>
+ <property name="suffix" >
+ <string> min</string>
+ </property>
+ <property name="maximum" >
+ <number>320</number>
+ </property>
+ <property name="singleStep" >
+ <number>5</number>
+ </property>
+ <property name="value" >
+ <number>60</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="refreshButton" >
+ <property name="font" >
+ <font/>
+ </property>
+ <property name="text" >
+ <string>Refresh now!</string>
+ </property>
+ <property name="toolButtonStyle" >
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/regexp/RegExp.pluginspec b/src/plugins/regexp/RegExp.pluginspec
new file mode 100644
index 0000000000..03d0900967
--- /dev/null
+++ b/src/plugins/regexp/RegExp.pluginspec
@@ -0,0 +1,10 @@
+<plugin name="RegExp" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Regular Expression test widget.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/regexp/regexp.pro b/src/plugins/regexp/regexp.pro
new file mode 100644
index 0000000000..dfe52ef024
--- /dev/null
+++ b/src/plugins/regexp/regexp.pro
@@ -0,0 +1,10 @@
+TEMPLATE = lib
+TARGET = RegExp
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+
+QT += xml
+
+HEADERS += regexpwindow.h regexpplugin.h settings.h
+SOURCES += regexpwindow.cpp regexpplugin.cpp settings.cpp
diff --git a/src/plugins/regexp/regexpplugin.cpp b/src/plugins/regexp/regexpplugin.cpp
new file mode 100644
index 0000000000..48b3e3590e
--- /dev/null
+++ b/src/plugins/regexp/regexpplugin.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "regexpplugin.h"
+#include "settings.h"
+#include "regexpwindow.h"
+
+#include <coreplugin/baseview.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+
+#include <QtCore/qplugin.h>
+
+using namespace RegExp::Internal;
+
+RegExpPlugin::RegExpPlugin()
+{
+}
+
+RegExpPlugin::~RegExpPlugin()
+{
+ if (m_regexpWindow) {
+ m_regexpWindow->settings().toQSettings(m_core->settings());
+ }
+}
+
+void RegExpPlugin::extensionsInitialized()
+{
+}
+
+
+bool RegExpPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+ Q_UNUSED(error_message)
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ m_regexpWindow = new RegExpWindow;
+ Settings settings;
+ settings.fromQSettings(m_core->settings());
+ m_regexpWindow->setSettings(settings);
+ const int plugId = m_core->uniqueIDManager()->uniqueIdentifier(QLatin1String("RegExpPlugin"));
+ addAutoReleasedObject(new Core::BaseView("TextEditor.RegExpWindow",
+ m_regexpWindow,
+ QList<int>() << plugId,
+ Qt::RightDockWidgetArea));
+ return true;
+}
+
+Q_EXPORT_PLUGIN(RegExpPlugin)
diff --git a/src/plugins/regexp/regexpplugin.h b/src/plugins/regexp/regexpplugin.h
new file mode 100644
index 0000000000..3b5703305b
--- /dev/null
+++ b/src/plugins/regexp/regexpplugin.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef REGEXPPLUGIN_H
+#define REGEXPPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+namespace Core {
+class ICore;
+}
+
+namespace RegExp {
+namespace Internal {
+
+class RegExpWindow;
+
+class RegExpPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ RegExpPlugin();
+ virtual ~RegExpPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+private:
+ Core::ICore *m_core;
+ QPointer<RegExpWindow> m_regexpWindow;
+};
+
+} //namespace Internal
+} //namespace RegExp
+
+#endif
diff --git a/src/plugins/regexp/regexpwindow.cpp b/src/plugins/regexp/regexpwindow.cpp
new file mode 100644
index 0000000000..a00a9137a0
--- /dev/null
+++ b/src/plugins/regexp/regexpwindow.cpp
@@ -0,0 +1,294 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "regexpwindow.h"
+#include "settings.h"
+
+#include <QtGui/QCheckBox>
+#include <QtGui/QComboBox>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QLineEdit>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QInputDialog>
+
+using namespace RegExp::Internal;
+
+RegExpWindow::RegExpWindow(QWidget *parent) :
+ QWidget(parent),
+ patternLabel(new QLabel(tr("&Pattern:"))),
+ escapedPatternLabel(new QLabel(tr("&Escaped Pattern:"))),
+ syntaxLabel(new QLabel(tr("&Pattern Syntax:"))),
+ textLabel(new QLabel(tr("&Text:"))),
+ patternComboBox (new QComboBox),
+ escapedPatternLineEdit(new QLineEdit),
+ textComboBox(new QComboBox),
+ caseSensitiveCheckBox(new QCheckBox(tr("Case &Sensitive"))),
+ minimalCheckBox(new QCheckBox(tr("&Minimal"))),
+ syntaxComboBox(new QComboBox),
+ indexLabel(new QLabel(tr("Index of Match:"))),
+ matchedLengthLabel(new QLabel(tr("Matched Length:"))),
+ indexEdit(new QLineEdit),
+ matchedLengthEdit(new QLineEdit)
+{
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+ QGridLayout *mainLayout = new QGridLayout;
+
+ patternComboBox->setEditable(true);
+ patternComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ patternLabel->setBuddy(patternComboBox);
+
+ mainLayout->addWidget(patternLabel, 0, 0);
+ mainLayout->addWidget(patternComboBox, 0, 1);
+
+ escapedPatternLineEdit->setReadOnly(true);
+ QPalette palette = escapedPatternLineEdit->palette();
+ palette.setBrush(QPalette::Base, palette.brush(QPalette::Disabled, QPalette::Base));
+ escapedPatternLineEdit->setPalette(palette);
+
+ escapedPatternLabel->setBuddy(escapedPatternLineEdit);
+
+ mainLayout->addWidget(escapedPatternLabel, 1, 0);
+ mainLayout->addWidget(escapedPatternLineEdit, 1, 1);
+
+ syntaxComboBox->addItem(tr("Regular expression v1"), QRegExp::RegExp);
+ syntaxComboBox->addItem(tr("Regular expression v2"), QRegExp::RegExp2);
+ syntaxComboBox->addItem(tr("Wildcard"), QRegExp::Wildcard);
+ syntaxComboBox->addItem(tr("Fixed string"), QRegExp::FixedString);
+
+ syntaxLabel->setBuddy(syntaxComboBox);
+
+ mainLayout->addWidget(syntaxLabel, 2, 0);
+ mainLayout->addWidget(syntaxComboBox, 2, 1);
+
+ QHBoxLayout *checkBoxLayout = new QHBoxLayout;
+
+ caseSensitiveCheckBox->setChecked(true);
+
+ checkBoxLayout->addWidget(caseSensitiveCheckBox);
+ checkBoxLayout->addWidget(minimalCheckBox);
+ checkBoxLayout->addStretch(1);
+
+ mainLayout->addLayout(checkBoxLayout, 3, 0, 1, 2);
+
+ textComboBox->setEditable(true);
+ textComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ textLabel->setBuddy(textComboBox);
+
+ mainLayout->addWidget(textLabel, 4, 0);
+ mainLayout->addWidget(textComboBox, 4, 1);
+
+ indexEdit->setReadOnly(true);
+
+ mainLayout->addWidget(indexLabel, 5, 0);
+ mainLayout->addWidget(indexEdit, 5, 1);
+
+ matchedLengthEdit->setReadOnly(true);
+
+ mainLayout->addWidget(matchedLengthLabel, 6, 0);
+ mainLayout->addWidget(matchedLengthEdit, 6, 1);
+
+ vboxLayout->addLayout(mainLayout);
+ vboxLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
+
+ for (int i = 0; i < MaxCaptures; ++i) {
+ captureLabels[i] = new QLabel(tr("Capture %1:").arg(i));
+ captureEdits[i] = new QLineEdit;
+ captureEdits[i]->setReadOnly(true);
+ }
+ captureLabels[0]->setText(tr("Match:"));
+
+ for (int j = 0; j < MaxCaptures; ++j) {
+ mainLayout->addWidget(captureLabels[j], 7 + j, 0);
+ mainLayout->addWidget(captureEdits[j], 7 + j, 1);
+ }
+
+ connect(patternComboBox, SIGNAL(editTextChanged(const QString &)), this, SLOT(refresh()));
+ connect(textComboBox, SIGNAL(editTextChanged(const QString &)), this, SLOT(refresh()));
+ connect(caseSensitiveCheckBox, SIGNAL(toggled(bool)), this, SLOT(refresh()));
+ connect(minimalCheckBox, SIGNAL(toggled(bool)), this, SLOT(refresh()));
+ connect(syntaxComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(refresh()));
+
+ setWindowTitle(tr("Regular Expression"));
+ refresh();
+}
+
+static const char *escapedBackSlash = "\\\\";
+static const char *escapedDoubleQuote = "\\\"";
+
+static QString escapePattern(const QString &pattern)
+{
+ QString escaped = pattern;
+ escaped.replace(QString(QLatin1Char('\\')) , QLatin1String(escapedBackSlash));
+ const QChar doubleQuote(QLatin1Char('"'));
+ escaped.replace(doubleQuote, QString(QLatin1String(escapedDoubleQuote)));
+ escaped.prepend(doubleQuote);
+ escaped.append(doubleQuote);
+ return escaped;
+}
+
+static QString unescapePattern(QString escaped)
+{
+ // remove quotes
+ const QChar doubleQuote(QLatin1Char('"'));
+ if (escaped.endsWith(doubleQuote))
+ escaped.truncate(escaped.size() - 1);
+ if (escaped.startsWith(doubleQuote))
+ escaped.remove(0, 1);
+
+ const int size = escaped.size();
+ if (!size)
+ return QString();
+
+ // parse out escapes. Do not just replace.
+ QString pattern;
+ const QChar backSlash = QLatin1Char('\\');
+ bool escapeSeen = false;
+ for (int i = 0; i < size; i++) {
+ const QChar c = escaped.at(i);
+ if (c == backSlash && !escapeSeen)
+ escapeSeen = true;
+ else {
+ pattern.push_back(c);
+ escapeSeen = false;
+ }
+ }
+ return pattern;
+}
+
+void RegExpWindow::refresh()
+{
+ setUpdatesEnabled(false);
+
+ const QString pattern = patternComboBox->currentText();
+ const QString text = textComboBox->currentText();
+
+ escapedPatternLineEdit->setText(escapePattern(pattern));
+
+ QRegExp rx(pattern);
+ const Qt::CaseSensitivity cs = caseSensitiveCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ rx.setCaseSensitivity(cs);
+ rx.setMinimal(minimalCheckBox->isChecked());
+ const QRegExp::PatternSyntax syntax = QRegExp::PatternSyntax(
+ syntaxComboBox->itemData(syntaxComboBox->currentIndex()).toInt());
+ rx.setPatternSyntax(syntax);
+
+ QPalette palette = patternComboBox->palette();
+ if (rx.isValid()) {
+ palette.setColor(QPalette::Text,
+ textComboBox->palette().color(QPalette::Text));
+ } else {
+ palette.setColor(QPalette::Text, Qt::red);
+ }
+ patternComboBox->setPalette(palette);
+
+ indexEdit->setText(QString::number(rx.indexIn(text)));
+ matchedLengthEdit->setText(QString::number(rx.matchedLength()));
+ for (int i = 0; i < MaxCaptures; ++i) {
+ const bool enabled = i <= rx.numCaptures();
+ captureLabels[i]->setEnabled(enabled);
+ captureEdits[i]->setEnabled(enabled);
+ captureEdits[i]->setText(rx.cap(i));
+ }
+
+ setUpdatesEnabled(true);
+}
+
+static void saveTextCombo(const QComboBox *cb, QString &current, QStringList &items)
+{
+ current = cb->currentText();
+ items.clear();
+ if (const int count = cb->count())
+ for (int i = 0;i < count; i++) {
+ const QString text = cb->itemText(i);
+ if (items.indexOf(text) == -1)
+ items += text;
+ }
+}
+
+Settings RegExpWindow::settings() const
+{
+ Settings rc;
+ rc.m_patternSyntax = static_cast<QRegExp::PatternSyntax>(syntaxComboBox->itemData(syntaxComboBox->currentIndex()).toInt());
+ rc.m_minimal = minimalCheckBox->checkState() == Qt::Checked;
+ rc.m_caseSensitive = caseSensitiveCheckBox->checkState() == Qt::Checked;
+ saveTextCombo(patternComboBox, rc.m_currentPattern, rc.m_patterns);
+ saveTextCombo(textComboBox, rc.m_currentMatch, rc.m_matches);
+ return rc;
+}
+
+static void restoreTextCombo(const QString &current, const QStringList &items, QComboBox *cb)
+{
+ cb->clear();
+ cb->addItems(items);
+ cb->lineEdit()->setText(current);
+}
+
+void RegExpWindow::setSettings(const Settings &s)
+{
+ const int patternIndex = syntaxComboBox->findData(QVariant(s.m_patternSyntax));
+ syntaxComboBox->setCurrentIndex(patternIndex);
+ minimalCheckBox->setCheckState(s.m_minimal ? Qt::Checked : Qt::Unchecked);
+ caseSensitiveCheckBox->setCheckState(s.m_caseSensitive ? Qt::Checked : Qt::Unchecked);
+ restoreTextCombo(s.m_currentPattern, s.m_patterns, patternComboBox);
+ restoreTextCombo(s.m_currentMatch, s.m_matches, textComboBox);
+}
+
+void RegExpWindow::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu menu(this);
+
+ QAction *enterQuotedAction = menu.addAction(tr("Enter pattern from code..."));
+ connect(enterQuotedAction, SIGNAL(triggered()), this, SLOT(enterEscaped()));
+ menu.addSeparator();
+
+ QAction *clearPatternsAction = menu.addAction(tr("Clear patterns"));
+ connect(clearPatternsAction, SIGNAL(triggered()), patternComboBox, SLOT(clear()));
+
+ QAction *clearTextsAction = menu.addAction(tr("Clear texts"));
+ connect(clearTextsAction, SIGNAL(triggered()), textComboBox, SLOT(clear()));
+
+ event->accept();
+ menu.exec(event->globalPos());
+}
+
+void RegExpWindow::enterEscaped()
+{
+ const QString escapedPattern = QInputDialog::getText (this, tr("Enter pattern from code"), tr("Pattern"));
+ if ( escapedPattern.isEmpty())
+ return;
+ patternComboBox->lineEdit()->setText(unescapePattern(escapedPattern));
+
+}
diff --git a/src/plugins/regexp/regexpwindow.h b/src/plugins/regexp/regexpwindow.h
new file mode 100644
index 0000000000..066a7a44e8
--- /dev/null
+++ b/src/plugins/regexp/regexpwindow.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef REGEXPWINDOW_H
+#define REGEXPWINDOW_H
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QComboBox;
+class QCheckBox;
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace RegExp {
+namespace Internal {
+
+struct Settings;
+
+class RegExpWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ RegExpWindow(QWidget *parent = 0);
+
+ Settings settings() const;
+ void setSettings(const Settings &s);
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *);
+
+private slots:
+ void refresh();
+ void enterEscaped();
+
+private:
+ QLabel *patternLabel;
+ QLabel *escapedPatternLabel;
+ QLabel *syntaxLabel;
+ QLabel *textLabel;
+ QComboBox *patternComboBox;
+ QLineEdit *escapedPatternLineEdit;
+ QComboBox *textComboBox;
+ QCheckBox *caseSensitiveCheckBox;
+ QCheckBox *minimalCheckBox;
+ QComboBox *syntaxComboBox;
+
+ QLabel *indexLabel;
+ QLabel *matchedLengthLabel;
+ QLineEdit *indexEdit;
+ QLineEdit *matchedLengthEdit;
+
+ enum { MaxCaptures = 6 };
+ QLabel *captureLabels[MaxCaptures];
+ QLineEdit *captureEdits[MaxCaptures];
+};
+
+} //namespace Internal
+} //namespace RegExp
+
+#endif
diff --git a/src/plugins/regexp/settings.cpp b/src/plugins/regexp/settings.cpp
new file mode 100644
index 0000000000..336bfc0878
--- /dev/null
+++ b/src/plugins/regexp/settings.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settings.h"
+#include <QtCore/QSettings>
+
+static const char *syntaxKey = "Syntax";
+static const char *minimalKey = "Minimal";
+static const char *caseSensitiveKey = "CaseSensitive";
+static const char *patternKey = "Patterns";
+static const char *currentPatternKey = "CurrentPattern";
+static const char *matchKey = "Matches";
+static const char *currentMatchKey = "CurrentMatch";
+static const char *patternDefault = "[A-Za-z_]+([A-Za-z_0-9]*)";
+static const char *matchDefault = "(10 + delta4) * 32";
+static const char *settingsGroup = "RegExp";
+
+namespace RegExp {
+namespace Internal {
+
+Settings::Settings() :
+ m_patternSyntax(QRegExp::RegExp),
+ m_minimal(false),
+ m_caseSensitive(true),
+ m_patterns(QLatin1String(patternDefault)),
+ m_currentPattern(m_patterns.front()),
+ m_matches(QLatin1String(matchDefault)),
+ m_currentMatch(m_matches.front())
+{
+}
+
+void Settings::clear()
+{
+ *this = Settings();
+}
+
+void Settings::fromQSettings(QSettings *s)
+{
+ clear();
+ s->beginGroup(QLatin1String(settingsGroup));
+ m_patternSyntax = static_cast<QRegExp::PatternSyntax>(s->value(QLatin1String(syntaxKey), m_patternSyntax).toInt());
+ m_minimal = s->value(QLatin1String(minimalKey), m_minimal).toBool();
+ m_caseSensitive = s->value(QLatin1String(caseSensitiveKey), m_caseSensitive).toBool();
+ m_patterns = s->value(QLatin1String(patternKey), m_patterns).toStringList();
+ m_currentPattern = s->value(QLatin1String(currentPatternKey), m_currentPattern).toString();
+ m_matches = s->value(QLatin1String(matchKey), m_matches).toStringList();
+ m_currentMatch = s->value(QLatin1String(currentMatchKey), m_currentMatch).toString();
+ s->endGroup();
+}
+
+void Settings::toQSettings(QSettings *s) const
+{
+ s->beginGroup(QLatin1String(settingsGroup));
+ s->setValue(QLatin1String(syntaxKey), m_patternSyntax);
+ s->setValue(QLatin1String(minimalKey), m_minimal);
+ s->setValue(QLatin1String(caseSensitiveKey), m_caseSensitive);
+ s->setValue(QLatin1String(patternKey), m_patterns);
+ s->setValue(QLatin1String(currentPatternKey), m_currentPattern);
+ s->setValue(QLatin1String(matchKey), m_matches);
+ s->setValue(QLatin1String(currentMatchKey), m_currentMatch);
+ s->endGroup();
+}
+
+}
+}
diff --git a/src/plugins/regexp/settings.h b/src/plugins/regexp/settings.h
new file mode 100644
index 0000000000..779ec8611e
--- /dev/null
+++ b/src/plugins/regexp/settings.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef REGEXP_SETTINGS_H
+#define REGEXP_SETTINGS_H
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QRegExp>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace RegExp {
+namespace Internal {
+
+// Settings of the Regexp plugin.
+// Provides methods to serialize into QSettings.
+
+struct Settings {
+ Settings();
+ void clear();
+ void fromQSettings(QSettings *s);
+ void toQSettings(QSettings *s) const;
+
+ QRegExp::PatternSyntax m_patternSyntax;
+ bool m_minimal;
+ bool m_caseSensitive;
+
+ QStringList m_patterns;
+ QString m_currentPattern;
+ QStringList m_matches;
+ QString m_currentMatch;
+};
+
+} // namespace Internal
+} // namespace RegExp
+
+#endif // REGEXP_SETTINGS_H
diff --git a/src/plugins/resourceeditor/ResourceEditor.mimetypes.xml b/src/plugins/resourceeditor/ResourceEditor.mimetypes.xml
new file mode 100644
index 0000000000..82a1797028
--- /dev/null
+++ b/src/plugins/resourceeditor/ResourceEditor.mimetypes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/vnd.nokia.xml.qt.resource">
+ <sub-class-of type="text/xml"/>
+ <comment>Qt Resource file</comment>
+ <glob pattern="*.qrc"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/resourceeditor/ResourceEditor.pluginspec b/src/plugins/resourceeditor/ResourceEditor.pluginspec
new file mode 100644
index 0000000000..cddde0b0d9
--- /dev/null
+++ b/src/plugins/resourceeditor/ResourceEditor.pluginspec
@@ -0,0 +1,10 @@
+<plugin name="ResourceEditor" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Editor for qrc files.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/resourceeditor/images/qt_qrc.png b/src/plugins/resourceeditor/images/qt_qrc.png
new file mode 100644
index 0000000000..d22ca67610
--- /dev/null
+++ b/src/plugins/resourceeditor/images/qt_qrc.png
Binary files differ
diff --git a/src/plugins/resourceeditor/resourceeditor.pro b/src/plugins/resourceeditor/resourceeditor.pro
new file mode 100644
index 0000000000..e91099d963
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditor.pro
@@ -0,0 +1,24 @@
+TEMPLATE = lib
+TARGET = ResourceEditor
+
+qtAddLibrary(QtDesigner)
+
+include(../../qworkbenchplugin.pri)
+include(../../libs/utils/utils.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../../shared/qrceditor/qrceditor.pri)
+
+INCLUDEPATH += $$PWD/../../tools/utils
+
+HEADERS += resourceeditorfactory.h \
+resourceeditorplugin.h \
+resourcewizard.h \
+resourceeditorw.h \
+resourceeditorconstants.h
+
+SOURCES +=resourceeditorfactory.cpp \
+resourceeditorplugin.cpp \
+resourcewizard.cpp \
+resourceeditorw.cpp
+
+RESOURCES += resourceeditor.qrc
diff --git a/src/plugins/resourceeditor/resourceeditor.qrc b/src/plugins/resourceeditor/resourceeditor.qrc
new file mode 100644
index 0000000000..2265055f97
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditor.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/resourceeditor" >
+ <file>images/qt_qrc.png</file>
+ <file>ResourceEditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/resourceeditor/resourceeditorconstants.h b/src/plugins/resourceeditor/resourceeditorconstants.h
new file mode 100644
index 0000000000..9786a681e4
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorconstants.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RESOURCEEDITOR_CONSTANTS_H
+#define RESOURCEEDITOR_CONSTANTS_H
+
+namespace ResourceEditor {
+namespace Constants {
+const char * const C_RESOURCEEDITOR = "Resource Editor";
+const char * const C_RESOURCEWINDOW = "Resourcewindow";
+const char * const C_RESOURCE_MIMETYPE = "application/vnd.nokia.xml.qt.resource";
+}
+}
+
+#endif // RESOURCEEDITOR_CONSTANTS_H
diff --git a/src/plugins/resourceeditor/resourceeditorfactory.cpp b/src/plugins/resourceeditor/resourceeditorfactory.cpp
new file mode 100644
index 0000000000..8897b11524
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorfactory.cpp
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "resourceeditorfactory.h"
+#include "resourceeditorw.h"
+#include "resourceeditorplugin.h"
+#include "resourceeditorconstants.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/qdebug.h>
+
+using namespace ResourceEditor::Internal;
+using namespace ResourceEditor::Constants;
+
+ResourceEditorFactory::ResourceEditorFactory(Core::ICore *core, ResourceEditorPlugin *plugin) :
+ Core::IEditorFactory(plugin),
+ m_mimeTypes(QStringList(QLatin1String("application/vnd.nokia.xml.qt.resource"))),
+ m_kind(QLatin1String(C_RESOURCEEDITOR)),
+ m_core(core),
+ m_plugin(plugin)
+{
+ m_context += m_core->uniqueIDManager()
+ ->uniqueIdentifier(QLatin1String(ResourceEditor::Constants::C_RESOURCEEDITOR));
+ Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
+ iconProvider->registerIconForSuffix(QIcon(":/resourceeditor/images/qt_qrc.png"),
+ QLatin1String("qrc"));
+}
+
+QString ResourceEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *ResourceEditorFactory::open(const QString &fileName)
+{
+ Core::IEditor *iface = m_core->editorManager()->openEditor(fileName, kind());
+ if (!iface) {
+ qWarning() << "ResourceEditorFactory::open: openEditor failed for " << fileName;
+ return 0;
+ }
+ return iface->file();
+}
+
+Core::IEditor *ResourceEditorFactory::createEditor(QWidget *parent)
+{
+ return new ResourceEditorW(m_context, m_core, m_plugin, parent);
+}
+
+QStringList ResourceEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
diff --git a/src/plugins/resourceeditor/resourceeditorfactory.h b/src/plugins/resourceeditor/resourceeditorfactory.h
new file mode 100644
index 0000000000..9f22743a35
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorfactory.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RRESOURCEEDITORFACTORY_H
+#define RRESOURCEEDITORFACTORY_H
+
+#include <extensionsystem/ExtensionSystemInterfaces>
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+#include <QtCore/QStringList>
+
+namespace Core {
+class ICore;
+class IEditor;
+class IFile;
+}
+
+namespace ResourceEditor {
+namespace Internal {
+
+class ResourceEditorPlugin;
+
+class ResourceEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ typedef QList<int> Context;
+
+ ResourceEditorFactory(Core::ICore *core, ResourceEditorPlugin *plugin);
+
+ virtual QStringList mimeTypes() const;
+
+ //EditorFactory
+ QString kind() const;
+ Core::IFile *open(const QString &fileName);
+ Core::IEditor *createEditor(QWidget *parent);
+
+private:
+ const QStringList m_mimeTypes;
+ const QString m_kind;
+ Context m_context;
+
+ Core::ICore *m_core;
+ ResourceEditorPlugin *m_plugin;
+};
+
+} // namespace Internal
+} // namespace ResourceEditor
+
+#endif // RRESOURCEEDITORFACTORY_H
diff --git a/src/plugins/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp
new file mode 100644
index 0000000000..d0335db5a8
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorplugin.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "resourceeditorplugin.h"
+#include "resourceeditorw.h"
+#include "resourceeditorconstants.h"
+#include "resourcewizard.h"
+#include "resourceeditorfactory.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/qplugin.h>
+#include <QtGui/QAction>
+
+using namespace ResourceEditor::Internal;
+
+ResourceEditorPlugin::ResourceEditorPlugin() :
+ m_wizard(0),
+ m_editor(0),
+ m_core(NULL),
+ m_redoAction(NULL),
+ m_undoAction(NULL)
+{
+}
+
+ResourceEditorPlugin::~ResourceEditorPlugin()
+{
+ removeObject(m_editor);
+ removeObject(m_wizard);
+}
+
+bool ResourceEditorPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!m_core->mimeDatabase()->addMimeTypes(QLatin1String(":/resourceeditor/ResourceEditor.mimetypes.xml"), error_message))
+ return false;
+
+ m_editor = new ResourceEditorFactory(m_core, this);
+ addObject(m_editor);
+
+ Core::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+ wizardParameters.setDescription(tr("Resource file"));
+ wizardParameters.setName(tr("Resource file"));
+ wizardParameters.setCategory(QLatin1String("Qt"));
+ wizardParameters.setTrCategory(tr("Qt"));
+
+ m_wizard = new ResourceWizard(wizardParameters, m_core, this);
+ addObject(m_wizard);
+
+ error_message->clear();
+
+ // Register undo and redo
+ Core::ActionManagerInterface * const actionManager = m_core->actionManager();
+ int const pluginId = m_core->uniqueIDManager()->uniqueIdentifier(
+ Constants::C_RESOURCEEDITOR);
+ QList<int> const idList = QList<int>() << pluginId;
+ m_undoAction = new QAction(tr("&Undo"), this);
+ m_redoAction = new QAction(tr("&Redo"), this);
+ actionManager->registerAction(m_undoAction, Core::Constants::UNDO, idList);
+ actionManager->registerAction(m_redoAction, Core::Constants::REDO, idList);
+ connect(m_undoAction, SIGNAL(triggered()), this, SLOT(onUndo()));
+ connect(m_redoAction, SIGNAL(triggered()), this, SLOT(onRedo()));
+
+ return true;
+}
+
+void ResourceEditorPlugin::extensionsInitialized()
+{
+}
+
+void ResourceEditorPlugin::onUndo()
+{
+ currentEditor()->onUndo();
+}
+
+void ResourceEditorPlugin::onRedo()
+{
+ currentEditor()->onRedo();
+}
+
+void ResourceEditorPlugin::onUndoStackChanged(ResourceEditorW const *editor,
+ bool canUndo, bool canRedo)
+{
+ if (editor == currentEditor()) {
+ m_undoAction->setEnabled(canUndo);
+ m_redoAction->setEnabled(canRedo);
+ }
+}
+
+ResourceEditorW * ResourceEditorPlugin::currentEditor() const {
+ ResourceEditorW * const focusEditor = qobject_cast<ResourceEditorW *>(
+ m_core->editorManager()->currentEditor());
+ Q_ASSERT(focusEditor);
+ return focusEditor;
+}
+
+Q_EXPORT_PLUGIN(ResourceEditorPlugin)
diff --git a/src/plugins/resourceeditor/resourceeditorplugin.h b/src/plugins/resourceeditor/resourceeditorplugin.h
new file mode 100644
index 0000000000..6f75275da0
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorplugin.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RESOURCEEDITORPLUGIN_H
+#define RESOURCEEDITORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+QT_FORWARD_DECLARE_CLASS(QAction);
+
+namespace Core {
+ class ICore;
+}
+
+namespace ResourceEditor {
+namespace Internal {
+
+class ResourceEditorW;
+class ResourceWizard;
+class ResourceEditorFactory;
+
+class ResourceEditorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ ResourceEditorPlugin();
+ virtual ~ResourceEditorPlugin();
+
+ //Plugin
+ bool initialize(const QStringList &arguments, QString *error_message = 0);
+ void extensionsInitialized();
+
+private slots:
+ void onUndo();
+ void onRedo();
+
+public:
+ void onUndoStackChanged(ResourceEditorW const *editor, bool canUndo, bool canRedo);
+
+private:
+ ResourceEditorW * currentEditor() const;
+
+private:
+ ResourceWizard *m_wizard;
+ ResourceEditorFactory *m_editor;
+ Core::ICore *m_core;
+ QAction *m_redoAction;
+ QAction *m_undoAction;
+};
+
+} // namespace Internal
+} // namespace ResourceEditor
+
+#endif // RESOURCEEDITORPLUGIN_H
diff --git a/src/plugins/resourceeditor/resourceeditorw.cpp b/src/plugins/resourceeditor/resourceeditorw.cpp
new file mode 100644
index 0000000000..9eea18bce1
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorw.cpp
@@ -0,0 +1,271 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "resourceeditorw.h"
+#include "resourceeditorplugin.h"
+#include "resourceeditorconstants.h"
+
+#include <qrceditor.h>
+
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/qdebug.h>
+#include <QtGui/QMainWindow>
+#include <QtGui/QHBoxLayout>
+
+#include <coreplugin/icore.h>
+#include <utils/reloadpromptutils.h>
+
+namespace ResourceEditor {
+namespace Internal {
+
+enum { debugResourceEditorW = 0 };
+
+
+
+ResourceEditorFile::ResourceEditorFile(ResourceEditorW *parent) :
+ IFile(parent),
+ m_mimeType(QLatin1String(ResourceEditor::Constants::C_RESOURCE_MIMETYPE)),
+ m_parent(parent)
+{
+ if (debugResourceEditorW)
+ qDebug() << "ResourceEditorFile::ResourceEditorFile()";
+}
+
+QString ResourceEditorFile::mimeType() const
+{
+ return m_mimeType;
+}
+
+
+ResourceEditorW::ResourceEditorW(const QList<int> &context,
+ Core::ICore *core,
+ ResourceEditorPlugin *plugin,
+ QWidget *parent)
+ : m_context(context),
+ m_core(core),
+ m_resourceEditor(new SharedTools::QrcEditor(parent)),
+ m_resourceFile(new ResourceEditorFile(this)),
+ m_plugin(plugin)
+{
+ m_resourceEditor->setResourceDragEnabled(true);
+ m_resourceEditor->layout()->setMargin(9);
+
+ connect(m_resourceEditor, SIGNAL(dirtyChanged(bool)), this, SLOT(dirtyChanged(bool)));
+ connect(m_resourceEditor, SIGNAL(undoStackChanged(bool, bool)),
+ this, SLOT(onUndoStackChanged(bool, bool)));
+ connect(m_resourceFile, SIGNAL(changed()), this, SIGNAL(changed()));
+ if (debugResourceEditorW)
+ qDebug() << "ResourceEditorW::ResourceEditorW()";
+}
+
+ResourceEditorW::~ResourceEditorW()
+{
+ if (m_resourceEditor)
+ m_resourceEditor->deleteLater();
+}
+
+bool ResourceEditorW::createNew(const QString &contents)
+{
+ QTemporaryFile tempFile(0);
+ tempFile.setAutoRemove(true);
+ if (!tempFile.open())
+ return false;
+ const QString tempFileName = tempFile.fileName();
+ tempFile.write(contents.toUtf8());
+ tempFile.close();
+
+ const bool rc = m_resourceEditor->load(tempFileName);
+ m_resourceEditor->setFileName(QString());
+ if (debugResourceEditorW)
+ qDebug() << "ResourceEditorW::createNew: " << contents << " (" << tempFileName << ") returns " << rc;
+ return rc;
+}
+
+bool ResourceEditorW::open(const QString &fileName /*= QString()*/)
+{
+ if (debugResourceEditorW)
+ qDebug() << "ResourceEditorW::open: " << fileName;
+
+ if (fileName.isEmpty()) {
+ setDisplayName(tr("untitled"));
+ return true;
+ }
+
+ const QFileInfo fi(fileName);
+
+ const QString absFileName = fi.absoluteFilePath();
+
+ if (!fi.isReadable())
+ return false;
+
+ if (!m_resourceEditor->load(absFileName))
+ return false;
+
+ setDisplayName(fi.fileName());
+
+ emit changed();
+ return true;
+}
+
+bool ResourceEditorFile::save(const QString &name /*= QString()*/)
+{
+ if (debugResourceEditorW)
+ qDebug() << ">ResourceEditorW::save: " << name;
+
+ const QString oldFileName = fileName();
+ const QString actualName = name.isEmpty() ? oldFileName : name;
+ if (actualName.isEmpty())
+ return false;
+
+ m_parent->m_resourceEditor->setFileName(actualName);
+ if (!m_parent->m_resourceEditor->save()) {
+ m_parent->m_resourceEditor->setFileName(oldFileName);
+ return false;
+ }
+
+ m_parent->m_resourceEditor->setDirty(false);
+ m_parent->setDisplayName(QFileInfo(actualName).fileName());
+
+ emit changed();
+ return true;
+}
+
+const char *ResourceEditorW::kind() const {
+ return ResourceEditor::Constants::C_RESOURCEWINDOW;
+}
+
+QString ResourceEditorFile::fileName() const
+{
+ return m_parent->m_resourceEditor->fileName();
+}
+
+bool ResourceEditorFile::isModified() const
+{
+ return m_parent->m_resourceEditor->isDirty();
+}
+
+bool ResourceEditorFile::isReadOnly() const
+{
+ const QString fileName = m_parent->m_resourceEditor->fileName();
+ if (fileName.isEmpty())
+ return false;
+ const QFileInfo fi(fileName);
+ return !fi.isWritable();
+}
+
+bool ResourceEditorFile::isSaveAsAllowed() const
+{
+ return true;
+}
+
+void ResourceEditorFile::modified(Core::IFile::ReloadBehavior *behavior)
+{
+ const QString fileName = m_parent->m_resourceEditor->fileName();
+
+ switch (*behavior) {
+ case Core::IFile::ReloadNone:
+ return;
+ case Core::IFile::ReloadAll:
+ m_parent->open(fileName);
+ return;
+ case Core::IFile::ReloadPermissions:
+ emit changed();
+ return;
+ case Core::IFile::AskForReload:
+ break;
+ }
+
+ switch (Core::Utils::reloadPrompt(fileName, m_parent->m_core->mainWindow())) {
+ case Core::Utils::ReloadCurrent:
+ m_parent->open(fileName);
+ break;
+ case Core::Utils::ReloadAll:
+ m_parent->open(fileName);
+ *behavior = Core::IFile::ReloadAll;
+ break;
+ case Core::Utils::ReloadSkipCurrent:
+ break;
+ case Core::Utils::ReloadNone:
+ *behavior = Core::IFile::ReloadNone;
+ break;
+ }
+}
+
+QString ResourceEditorFile::defaultPath() const
+{
+ return QString();
+}
+
+void ResourceEditorW::setSuggestedFileName(const QString &fileName)
+{
+ m_suggestedName = fileName;
+}
+
+QString ResourceEditorFile::suggestedFileName() const
+{
+ return m_parent->m_suggestedName;
+}
+
+void ResourceEditorW::dirtyChanged(bool dirty)
+{
+ if (debugResourceEditorW)
+ qDebug() << " ResourceEditorW::dirtyChanged" << dirty;
+ if (dirty)
+ emit changed();
+}
+
+QWidget *ResourceEditorW::widget()
+{
+ return m_resourceEditor; /* we know it's a subclass of QWidget...*/
+}
+
+void ResourceEditorW::onUndoStackChanged(bool canUndo, bool canRedo)
+{
+ m_plugin->onUndoStackChanged(this, canUndo, canRedo);
+}
+
+void ResourceEditorW::onUndo()
+{
+ if (!m_resourceEditor.isNull())
+ m_resourceEditor.data()->onUndo();
+}
+
+void ResourceEditorW::onRedo()
+{
+ if (!m_resourceEditor.isNull())
+ m_resourceEditor.data()->onRedo();
+}
+
+}
+}
diff --git a/src/plugins/resourceeditor/resourceeditorw.h b/src/plugins/resourceeditor/resourceeditorw.h
new file mode 100644
index 0000000000..b580f37d90
--- /dev/null
+++ b/src/plugins/resourceeditor/resourceeditorw.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RESOURCEDITORW_H
+#define RESOURCEDITORW_H
+
+#include <coreplugin/ifile.h>
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QtGui/QWidget>
+#include <QtCore/QPointer>
+
+
+namespace Core {
+ class ICore;
+}
+
+namespace SharedTools {
+ class QrcEditor;
+}
+
+namespace ResourceEditor {
+namespace Internal {
+
+class ResourceEditorPlugin;
+class ResourceEditorW;
+
+class ResourceEditorFile
+ : public virtual Core::IFile
+{
+ Q_OBJECT
+
+public:
+ typedef QList<int> Context;
+
+ ResourceEditorFile(ResourceEditorW *parent = 0);
+
+ //IFile
+ bool save(const QString &fileName = QString());
+ QString fileName() const;
+ bool isModified() const;
+ bool isReadOnly() const;
+ bool isSaveAsAllowed() const;
+ void modified(Core::IFile::ReloadBehavior *behavior);
+ QString defaultPath() const;
+ QString suggestedFileName() const;
+ virtual QString mimeType() const;
+
+signals:
+ void changed();
+
+private:
+ const QString m_mimeType;
+ ResourceEditorW *m_parent;
+};
+
+class ResourceEditorW : public Core::IEditor
+{
+ Q_OBJECT
+
+public:
+ typedef QList<int> Context;
+
+ ResourceEditorW(const Context &context,
+ Core::ICore *core,
+ ResourceEditorPlugin *plugin,
+ QWidget *parent = 0);
+ ~ResourceEditorW();
+
+ // IEditor
+ bool createNew(const QString &contents);
+ bool open(const QString &fileName = QString());
+ bool duplicateSupported() const { return false; }
+ Core::IEditor *duplicate(QWidget *) { return 0; }
+ Core::IFile *file() { return m_resourceFile; }
+ const char *kind() const;
+ QString displayName() const { return m_displayName; }
+ void setDisplayName(const QString &title) { m_displayName = title; }
+ QToolBar *toolBar() { return 0; }
+ QByteArray saveState() const { return QByteArray(); }
+ bool restoreState(const QByteArray &/*state*/) { return true; }
+
+ // ContextInterface
+ Context context() const { return m_context; }
+ QWidget *widget();
+
+ void setSuggestedFileName(const QString &fileName);
+
+private slots:
+ void dirtyChanged(bool);
+ void onUndoStackChanged(bool canUndo, bool canRedo);
+
+private:
+ const QString m_extension;
+ const QString m_fileFilter;
+ QString m_displayName;
+ QString m_suggestedName;
+ const Context m_context;
+ Core::ICore *m_core;
+ QPointer<SharedTools::QrcEditor> m_resourceEditor;
+ ResourceEditorFile *m_resourceFile;
+ ResourceEditorPlugin *m_plugin;
+
+public:
+ void onUndo();
+ void onRedo();
+
+ friend class ResourceEditorFile;
+};
+
+} // namespace Internal
+} // namespace ResourceEditor
+
+#endif //RESOURCEDITORW_H
diff --git a/src/plugins/resourceeditor/resourcewizard.cpp b/src/plugins/resourceeditor/resourcewizard.cpp
new file mode 100644
index 0000000000..ce1b8eb8f1
--- /dev/null
+++ b/src/plugins/resourceeditor/resourcewizard.cpp
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "resourcewizard.h"
+#include "resourceeditorw.h"
+#include "resourceeditorconstants.h"
+
+namespace ResourceEditor {
+namespace Internal {
+
+ResourceWizard::ResourceWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent) :
+ Core::StandardFileWizard(parameters, core, parent)
+{
+}
+
+Core::GeneratedFiles
+ ResourceWizard::generateFilesFromPath(const QString &path,
+ const QString &name,
+ QString * /*errorMessage*/) const
+{
+ const QString suffix = preferredSuffix(QLatin1String(Constants::C_RESOURCE_MIMETYPE));
+ const QString fileName = Core::BaseFileWizard::buildFileName(path, name, suffix);
+ Core::GeneratedFile file(fileName);
+ file.setContents(QLatin1String("<RCC/>"));
+ file.setEditorKind(QLatin1String(Constants::C_RESOURCEEDITOR));
+ return Core::GeneratedFiles() << file;
+}
+
+}
+}
diff --git a/src/plugins/resourceeditor/resourcewizard.h b/src/plugins/resourceeditor/resourcewizard.h
new file mode 100644
index 0000000000..40abe4612c
--- /dev/null
+++ b/src/plugins/resourceeditor/resourcewizard.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef RESOURCEWIZARD_H
+#define RESOURCEWIZARD_H
+
+#include <coreplugin/basefilewizard.h>
+
+namespace ResourceEditor {
+namespace Internal {
+
+class ResourceWizard : public Core::StandardFileWizard
+{
+ Q_OBJECT
+
+public:
+
+ typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
+ explicit ResourceWizard(const BaseFileWizardParameters &parameters, Core::ICore *core, QObject *parent);
+
+protected:
+ virtual Core::GeneratedFiles
+ generateFilesFromPath(const QString &path, const QString &name,
+ QString *errorMessage) const;
+};
+
+} // namespace Internal
+} // namespace ResourceEditor
+
+#endif //RESOURCEWIZARD_H
diff --git a/src/plugins/snippets/Snippets.pluginspec b/src/plugins/snippets/Snippets.pluginspec
new file mode 100644
index 0000000000..362791eb16
--- /dev/null
+++ b/src/plugins/snippets/Snippets.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="Snippets" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Code snippet plugin.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/snippets/images/dir.png b/src/plugins/snippets/images/dir.png
new file mode 100644
index 0000000000..57cec6bcd3
--- /dev/null
+++ b/src/plugins/snippets/images/dir.png
Binary files differ
diff --git a/src/plugins/snippets/images/diropen.png b/src/plugins/snippets/images/diropen.png
new file mode 100644
index 0000000000..48fcb9b703
--- /dev/null
+++ b/src/plugins/snippets/images/diropen.png
Binary files differ
diff --git a/src/plugins/snippets/images/file.png b/src/plugins/snippets/images/file.png
new file mode 100644
index 0000000000..4a24ce3c2f
--- /dev/null
+++ b/src/plugins/snippets/images/file.png
Binary files differ
diff --git a/src/plugins/snippets/images/snippets.png b/src/plugins/snippets/images/snippets.png
new file mode 100644
index 0000000000..b799041d61
--- /dev/null
+++ b/src/plugins/snippets/images/snippets.png
Binary files differ
diff --git a/src/plugins/snippets/inputwidget.cpp b/src/plugins/snippets/inputwidget.cpp
new file mode 100644
index 0000000000..782e1d1c01
--- /dev/null
+++ b/src/plugins/snippets/inputwidget.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtGui/QApplication>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QBitmap>
+#include <QtGui/QPainter>
+#include <QtGui/QResizeEvent>
+
+#include "inputwidget.h"
+
+using namespace Snippets::Internal;
+
+InputWidget::InputWidget(const QString &text, const QString &value)
+ : QFrame(0, Qt::Popup)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ m_label = new QLabel();
+ m_label->setTextFormat(Qt::RichText);
+ m_label->setText(text);
+
+ m_lineEdit = new QLineEdit();
+ m_lineEdit->setText(value);
+ m_lineEdit->setSelection(0, value.length());
+
+ qApp->installEventFilter(this);
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(m_label);
+ layout->addWidget(m_lineEdit);
+ layout->setMargin(3);
+
+ setLayout(layout);
+ ensurePolished();
+
+ setAutoFillBackground(false);
+}
+
+void InputWidget::resizeEvent(QResizeEvent *event)
+{
+ int height = event->size().height();
+ int width = event->size().width();
+ qDebug() << event->size();
+
+ QPalette pal = palette();
+ QLinearGradient bg(0,0,0,height);
+ bg.setColorAt(0, QColor(195,195,255));
+ bg.setColorAt(1, QColor(230,230,255));
+ pal.setBrush(QPalette::Background, QBrush(bg));
+ setPalette(pal);
+
+ QBitmap bm(width, height);
+ bm.fill(Qt::color0);
+ QPainter p(&bm);
+ p.setBrush(QBrush(Qt::color1, Qt::SolidPattern));
+ p.setPen(Qt::color1);
+ int rw = (25 * height) / width;
+ p.drawRoundRect(0,0,width,height, rw, 25);
+ setMask(bm);
+}
+
+void InputWidget::showInputWidget(const QPoint &position)
+{
+ move(position);
+ show();
+ m_lineEdit->setFocus();
+}
+
+bool InputWidget::eventFilter(QObject *o, QEvent *e)
+{
+ if (o != m_lineEdit) {
+ switch (e->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ closeInputWidget(true);
+ default:
+ break;
+ }
+ } else if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+ switch (ke->key()) {
+ case Qt::Key_Escape:
+ qDebug() << "Escape";
+ closeInputWidget(true);
+ break;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ qDebug() << "Enter";
+ closeInputWidget(false);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void InputWidget::closeInputWidget(bool cancel)
+{
+ emit finished(cancel, m_lineEdit->text());
+ close();
+}
diff --git a/src/plugins/snippets/inputwidget.h b/src/plugins/snippets/inputwidget.h
new file mode 100644
index 0000000000..ef0386a300
--- /dev/null
+++ b/src/plugins/snippets/inputwidget.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INPUTWIDGET_H
+#define INPUTWIDGET_H
+
+#include <QtGui/QFrame>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace Snippets {
+namespace Internal {
+
+class InputWidget : public QFrame
+{
+ Q_OBJECT
+
+public:
+ InputWidget(const QString &text, const QString &value);
+ void showInputWidget(const QPoint &position);
+
+signals:
+ void finished(bool canceled, const QString &value);
+
+protected:
+ bool eventFilter(QObject *, QEvent *);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ void closeInputWidget(bool cancel);
+ QLabel *m_label;
+ QLineEdit *m_lineEdit;
+};
+
+} //namespace Internal
+} //namespace Snippets
+
+#endif // INPUTWIDGET_H
diff --git a/src/plugins/snippets/snippets.pro b/src/plugins/snippets/snippets.pro
new file mode 100644
index 0000000000..bbfb4b75b5
--- /dev/null
+++ b/src/plugins/snippets/snippets.pro
@@ -0,0 +1,24 @@
+TEMPLATE = lib
+TARGET = Snippets
+QT += xml
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
+
+INCLUDEPATH += ../projectexplorer
+
+HEADERS += snippetsplugin.h \
+ snippetswindow.h \
+ snippetspec.h \
+ snippetscompletion.h \
+ inputwidget.h
+
+SOURCES += snippetsplugin.cpp \
+ snippetswindow.cpp \
+ snippetspec.cpp \
+ snippetscompletion.cpp \
+ inputwidget.cpp
+
+RESOURCES += snippets.qrc
diff --git a/src/plugins/snippets/snippets.qrc b/src/plugins/snippets/snippets.qrc
new file mode 100644
index 0000000000..b36585dcc5
--- /dev/null
+++ b/src/plugins/snippets/snippets.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/snippets" >
+ <file>images/file.png</file>
+ <file>images/dir.png</file>
+ <file>images/diropen.png</file>
+ <file>images/snippets.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/snippets/snippetscompletion.cpp b/src/plugins/snippets/snippetscompletion.cpp
new file mode 100644
index 0000000000..cd6bf6a758
--- /dev/null
+++ b/src/plugins/snippets/snippetscompletion.cpp
@@ -0,0 +1,159 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "snippetscompletion.h"
+
+#include "snippetswindow.h"
+#include "snippetspec.h"
+#include "snippetsplugin.h"
+
+#include <texteditor/itexteditable.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QMap>
+#include <QtGui/QAction>
+#include <QtGui/QKeyEvent>
+
+using namespace Snippets::Internal;
+
+const QIcon SnippetsCompletion::m_fileIcon = QIcon(":/snippets/images/file.png");
+
+SnippetsCompletion::SnippetsCompletion(QObject *parent)
+ : ICompletionCollector(parent)
+{
+ m_core = SnippetsPlugin::core();
+ m_snippetsWnd = SnippetsPlugin::snippetsWindow();
+
+ updateCompletions();
+}
+
+SnippetsCompletion::~SnippetsCompletion()
+{
+ qDeleteAll(m_autoCompletions.values());
+ m_autoCompletions.clear();
+}
+
+void SnippetsCompletion::updateCompletions()
+{
+ qDeleteAll(m_autoCompletions.values());
+ m_autoCompletions.clear();
+
+ int index = 0;
+ foreach (SnippetSpec *spec, m_snippetsWnd->snippets()) {
+ if (!spec->completionShortcut().isEmpty()) {
+ TextEditor::CompletionItem *item = new TextEditor::CompletionItem;
+ item->m_key = spec->name();
+ item->m_collector = this;
+ item->m_index = index;
+ item->m_relevance = 0;
+ m_autoCompletions.insert(spec->completionShortcut(), item);
+ ++index;
+ }
+ }
+}
+
+bool SnippetsCompletion::triggersCompletion(TextEditor::ITextEditable *editor)
+{
+ QString currentWord = editor->textAt(editor->position() - 3, 3);
+ currentWord = currentWord.trimmed();
+ return currentWord.length() == 2 && m_autoCompletions.contains(currentWord) &&
+ !editor->characterAt(editor->position() - 1).isSpace();
+}
+
+int SnippetsCompletion::startCompletion(TextEditor::ITextEditable *editor)
+{
+ m_editor = editor;
+ m_startPosition = findStartOfName(m_editor);
+ return m_startPosition;
+}
+
+void SnippetsCompletion::completions(QList<TextEditor::CompletionItem *> *completions)
+{
+ const int length = m_editor->position() - m_startPosition;
+ if (length >= 2) {
+ QString key = m_editor->textAt(m_startPosition, length);
+ foreach (TextEditor::CompletionItem* item, m_autoCompletions.values()) {
+ if (item->m_key.startsWith(key, Qt::CaseInsensitive)) {
+ (*completions) << item;
+ }
+ }
+ }
+}
+
+QString SnippetsCompletion::text(TextEditor::CompletionItem *item) const
+{
+ const SnippetSpec *spec = m_snippetsWnd->snippets().at(item->m_index);
+ return spec->name();
+}
+
+QString SnippetsCompletion::details(TextEditor::CompletionItem *item) const
+{
+ const SnippetSpec *spec = m_snippetsWnd->snippets().at(item->m_index);
+ return spec->description();
+}
+
+QIcon SnippetsCompletion::icon(TextEditor::CompletionItem *) const
+{
+ return m_fileIcon;
+}
+
+void SnippetsCompletion::complete(TextEditor::CompletionItem *item)
+{
+ SnippetSpec *spec = m_snippetsWnd->snippets().at(item->m_index);
+
+ int length = m_editor->position() - m_startPosition;
+ m_editor->setCurPos(m_startPosition);
+ m_editor->remove(length);
+
+ m_snippetsWnd->insertSnippet(m_editor, spec);
+}
+
+bool SnippetsCompletion::partiallyComplete()
+{
+ return false;
+}
+
+void SnippetsCompletion::cleanup()
+{
+}
+
+int SnippetsCompletion::findStartOfName(const TextEditor::ITextEditor *editor)
+{
+ int pos = editor->position() - 1;
+ QChar chr = editor->characterAt(pos);
+
+ // Skip to the start of a name
+ while (!chr.isSpace() && !chr.isNull())
+ chr = editor->characterAt(--pos);
+
+ return pos + 1;
+}
diff --git a/src/plugins/snippets/snippetscompletion.h b/src/plugins/snippets/snippetscompletion.h
new file mode 100644
index 0000000000..02dfdbc257
--- /dev/null
+++ b/src/plugins/snippets/snippetscompletion.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SNIPPETSCOMPLETION_H
+#define SNIPPETSCOMPLETION_H
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QDir>
+#include <QtGui/QIcon>
+
+#include <texteditor/icompletioncollector.h>
+
+namespace Core {
+class ICore;
+}
+
+namespace TextEditor {
+class ITextEditable;
+class ITextEditor;
+}
+
+namespace Snippets {
+namespace Internal {
+
+class SnippetsWindow;
+class SnippetSpec;
+
+class SnippetsCompletion : public TextEditor::ICompletionCollector
+{
+ Q_OBJECT
+public:
+ SnippetsCompletion(QObject *parent);
+ ~SnippetsCompletion();
+
+ // ICompletionCollector
+ bool triggersCompletion(TextEditor::ITextEditable *editor);
+ int startCompletion(TextEditor::ITextEditable *editor);
+ void completions(QList<TextEditor::CompletionItem *> *completions);
+
+ QString text(TextEditor::CompletionItem *item) const;
+ QString details(TextEditor::CompletionItem *item) const;
+ QIcon icon(TextEditor::CompletionItem *item) const;
+
+ void complete(TextEditor::CompletionItem *item);
+ bool partiallyComplete();
+ void cleanup();
+
+private slots:
+ void updateCompletions();
+
+private:
+ static int findStartOfName(const TextEditor::ITextEditor *editor);
+
+ TextEditor::ITextEditable *m_editor;
+ int m_startPosition; // Position of the cursor from which completion started
+
+ SnippetsWindow *m_snippetsWnd;
+ Core::ICore *m_core;
+
+ QMultiMap<QString, TextEditor::CompletionItem *> m_autoCompletions;
+
+ static const QIcon m_fileIcon;
+};
+
+} // namespace Internal
+} // namespace Snippets
+
+#endif // SNIPPETSCOMPLETION_H
+
diff --git a/src/plugins/snippets/snippetspec.cpp b/src/plugins/snippets/snippetspec.cpp
new file mode 100644
index 0000000000..06820de3dc
--- /dev/null
+++ b/src/plugins/snippets/snippetspec.cpp
@@ -0,0 +1,100 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "snippetspec.h"
+#include "persistentsettings.h"
+
+using namespace Snippets::Internal;
+using ProjectExplorer::PersistentSettingsReader;
+
+bool SnippetSpec::load(const QString &fileName)
+{
+ PersistentSettingsReader reader;
+ if (!reader.load(fileName))
+ return false;
+
+ m_contents = reader.restoreValue(QLatin1String("Contents")).toString();
+ m_name = reader.restoreValue(QLatin1String("Name")).toString();
+ m_description = reader.restoreValue(QLatin1String("Description")).toString();
+ m_category = reader.restoreValue(QLatin1String("Category")).toString();
+ m_completionShortcut = reader.restoreValue(QLatin1String("Shortcut")).toString();
+
+ QMap<QString, QVariant> temp = reader.restoreValue(QLatin1String("Arguments")).toMap();
+ QMap<QString, QVariant>::const_iterator it, end;
+ end = temp.constEnd();
+ for (it = temp.constBegin(); it != end; ++it) {
+ m_argumentDescription.insert( it.key().toInt(), it.value().toString());
+ }
+
+ temp = reader.restoreValue(QLatin1String("ArgumentDefaults")).toMap();
+ end = temp.constEnd();
+ for (it = temp.constBegin(); it != end; ++it) {
+ m_argumentDefault.insert(it.key().toInt(), it.value().toString());
+ }
+
+ return true;
+}
+
+QString SnippetSpec::contents() const
+{
+ return m_contents;
+}
+
+QString SnippetSpec::name() const
+{
+ return m_name;
+}
+
+QString SnippetSpec::description() const
+{
+ return m_description;
+}
+
+QString SnippetSpec::category() const
+{
+ return m_category;
+}
+
+QString SnippetSpec::completionShortcut() const
+{
+ return m_completionShortcut;
+}
+
+QString SnippetSpec::argumentDescription(int id) const
+{
+ return m_argumentDescription.value(id);
+}
+
+QString SnippetSpec::argumentDefault(int id) const
+{
+ return m_argumentDefault.value(id);
+}
diff --git a/src/plugins/snippets/snippetspec.h b/src/plugins/snippets/snippetspec.h
new file mode 100644
index 0000000000..8a9d9525b9
--- /dev/null
+++ b/src/plugins/snippets/snippetspec.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SNIPPETSPEC_H
+#define SNIPPETSPEC_H
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+
+namespace Snippets {
+namespace Internal {
+
+class SnippetSpec
+{
+public:
+ bool load(const QString &fileName);
+
+ QString contents() const;
+ QString name() const;
+ QString description() const;
+ QString category() const;
+ QString completionShortcut() const;
+ QString argumentDescription(int id) const;
+ QString argumentDefault(int id) const;
+
+private:
+ QString m_contents;
+ QString m_name;
+ QString m_description;
+ QString m_category;
+ QString m_completionShortcut;
+ QMap<int, QString> m_argumentDescription;
+ QMap<int, QString> m_argumentDefault;
+};
+
+} //namespace Internal
+} //namespace Snippets
+
+#endif // SNIPPETSPEC_H
diff --git a/src/plugins/snippets/snippetsplugin.cpp b/src/plugins/snippets/snippetsplugin.cpp
new file mode 100644
index 0000000000..ddb8319819
--- /dev/null
+++ b/src/plugins/snippets/snippetsplugin.cpp
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "snippetswindow.h"
+#include "snippetscompletion.h"
+#include "snippetsplugin.h"
+#include "snippetspec.h"
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtGui/QShortcut>
+#include <QtGui/QApplication>
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/CoreTools>
+#include <texteditor/itexteditable.h>
+#include <texteditor/texteditorconstants.h>
+
+using namespace Snippets::Internal;
+
+SnippetsPlugin *SnippetsPlugin::m_instance = 0;
+
+SnippetsPlugin::SnippetsPlugin()
+{
+ m_instance = this;
+}
+
+SnippetsPlugin::~SnippetsPlugin()
+{
+ removeObject(m_snippetsCompletion);
+ delete m_snippetsCompletion;
+}
+
+void SnippetsPlugin::extensionsInitialized()
+{
+}
+
+bool SnippetsPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ QList<int> context;
+ context << m_core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+
+ m_snippetWnd = new SnippetsWindow();
+ addAutoReleasedObject(new Core::BaseView("Snippets.SnippetsTree",
+ m_snippetWnd,
+ QList<int>() << m_core->uniqueIDManager()->uniqueIdentifier(QLatin1String("Snippets Window"))
+ << m_core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR),
+ Qt::RightDockWidgetArea));
+ m_snippetsCompletion = new SnippetsCompletion(this);
+ addObject(m_snippetsCompletion);
+
+ foreach (SnippetSpec *snippet, m_snippetWnd->snippets()) {
+ QShortcut *sc = new QShortcut(m_snippetWnd);
+ Core::ICommand *cmd = am->registerShortcut(sc, simplifySnippetName(snippet), context);
+ cmd->setCategory(tr("Snippets"));
+ connect(sc, SIGNAL(activated()), this, SLOT(snippetActivated()));
+ m_shortcuts.insert(sc, snippet);
+ }
+
+ return true;
+}
+
+QString SnippetsPlugin::simplifySnippetName(SnippetSpec *snippet) const
+{
+ return QLatin1String("Snippets.")
+ + snippet->category().simplified().replace(QLatin1String(" "), QLatin1String(""))
+ + QLatin1Char('.')
+ + snippet->name().simplified().replace(QLatin1String(" "), QLatin1String(""));
+}
+
+void SnippetsPlugin::snippetActivated()
+{
+ SnippetSpec *snippet = m_shortcuts.value(sender());
+ if (snippet && m_core->editorManager()->currentEditor()) {
+ TextEditor::ITextEditable *te =
+ qobject_cast<TextEditor::ITextEditable *>(
+ m_core->editorManager()->currentEditor());
+ m_snippetWnd->insertSnippet(te, snippet);
+ }
+}
+
+Q_EXPORT_PLUGIN(SnippetsPlugin)
diff --git a/src/plugins/snippets/snippetsplugin.h b/src/plugins/snippets/snippetsplugin.h
new file mode 100644
index 0000000000..ab7fdbd69c
--- /dev/null
+++ b/src/plugins/snippets/snippetsplugin.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SNIPPETS_H
+#define SNIPPETS_H
+
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtGui/QShortcut>
+
+#include <extensionsystem/iplugin.h>
+
+namespace Core {
+class ICore;
+struct Application;
+}
+
+namespace Snippets {
+namespace Internal {
+
+class SnippetsWindow;
+class SnippetSpec;
+class SnippetsCompletion;
+
+class SnippetsPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ SnippetsPlugin();
+ virtual ~SnippetsPlugin();
+
+ static SnippetsPlugin *instance() { return m_instance; }
+ static SnippetsWindow *snippetsWindow() { return m_instance->m_snippetWnd; }
+ static Core::ICore *core() { return m_instance->m_core; }
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+private slots:
+ void snippetActivated();
+
+private:
+ static SnippetsPlugin *m_instance;
+
+ QString simplifySnippetName(SnippetSpec *snippet) const;
+ Core::ICore *m_core;
+ SnippetsCompletion *m_snippetsCompletion;
+ SnippetsWindow *m_snippetWnd;
+
+ int m_textContext;
+ int m_snippetsMode;
+ QShortcut *m_exitShortcut;
+ QShortcut *m_modeShortcut;
+ QMap<QObject*, SnippetSpec*> m_shortcuts;
+};
+
+} // namespace Internal
+} // namespace Snippets
+
+#endif // SNIPPETS_H
diff --git a/src/plugins/snippets/snippetswindow.cpp b/src/plugins/snippets/snippetswindow.cpp
new file mode 100644
index 0000000000..e44f21182d
--- /dev/null
+++ b/src/plugins/snippets/snippetswindow.cpp
@@ -0,0 +1,434 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "snippetswindow.h"
+#include "snippetspec.h"
+#include "inputwidget.h"
+#include "snippetsplugin.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/itexteditable.h>
+#include <texteditor/itexteditor.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtGui/QDragEnterEvent>
+#include <QtGui/QApplication>
+#include <QtGui/QLabel>
+#include <QtCore/QMimeData>
+#include <QtGui/QHeaderView>
+
+using namespace Snippets::Internal;
+
+const QIcon SnippetsWindow::m_fileIcon = QIcon(":/snippets/images/file.png");
+const QIcon SnippetsWindow::m_dirIcon = QIcon(":/snippets/images/dir.png");
+const QIcon SnippetsWindow::m_dirOpenIcon = QIcon(":/snippets/images/diropen.png");
+
+Q_DECLARE_METATYPE(Snippets::Internal::SnippetSpec *)
+
+SnippetsWindow::SnippetsWindow()
+{
+ m_core = SnippetsPlugin::core();
+
+ setWindowTitle(tr("Snippets"));
+ setWindowIcon(QIcon(":/snippets/images/snippets.png"));
+ setOrientation(Qt::Vertical);
+
+ m_snippetsTree = new SnippetsTree(this);
+ addWidget(m_snippetsTree);
+
+ m_descLabel = new QLabel(this);
+ m_descLabel->setAlignment(Qt::AlignTop|Qt::AlignLeft);
+ m_descLabel->setFrameShape(QFrame::Panel);
+ m_descLabel->setFrameShadow(QFrame::Raised);
+ m_descLabel->setWordWrap(true);
+ addWidget(m_descLabel);
+
+ m_snippetsDir = QDir::home();
+ if (!initSnippetsDir())
+ setDisabled(true);
+ else {
+ QDir defaultDir(m_core->resourcePath() + QLatin1String("/snippets"));
+ if (defaultDir.exists())
+ initSnippets(defaultDir);
+ initSnippets(m_snippetsDir);
+ }
+
+ connect(m_snippetsTree, SIGNAL(itemCollapsed(QTreeWidgetItem *)),
+ this, SLOT(setClosedIcon(QTreeWidgetItem *)));
+
+ connect(m_snippetsTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
+ this, SLOT(setOpenIcon(QTreeWidgetItem *)));
+
+ connect(m_snippetsTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+ this, SLOT(activateSnippet(QTreeWidgetItem *, int)));
+
+ connect(m_snippetsTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(updateDescription(QTreeWidgetItem *)));
+}
+
+SnippetsWindow::~SnippetsWindow()
+{
+ qDeleteAll(m_snippets);
+}
+
+
+void SnippetsWindow::activateSnippet(QTreeWidgetItem *item, int column)
+{
+ if (!item->parent())
+ return;
+
+ TextEditor::ITextEditable *editor = 0;
+ if (m_core->editorManager()->currentEditor())
+ editor = qobject_cast<TextEditor::ITextEditable *>(
+ m_core->editorManager()->currentEditor());
+ if (editor) {
+ SnippetSpec* spec = qVariantValue<SnippetSpec*>(item->data(0, Qt::UserRole));
+ insertSnippet(editor, spec);
+ }
+
+ Q_UNUSED(column);
+}
+
+const QList<SnippetSpec *> &SnippetsWindow::snippets() const
+{
+ return m_snippets;
+}
+
+void SnippetsWindow::initSnippets(const QDir &dir)
+{
+ QString name;
+ QString category;
+
+ QMap<QString, QTreeWidgetItem *> categories;
+ for (int i = 0; i < m_snippetsTree->topLevelItemCount(); ++i) {
+ categories.insert(m_snippetsTree->topLevelItem(i)->text(0),
+ m_snippetsTree->topLevelItem(i));
+ }
+
+ foreach (const QString &snippet, dir.entryList(QStringList("*.snp"))) {
+ SnippetSpec *spec = new SnippetSpec();
+ if (spec->load(dir.filePath(snippet))) {
+ if (!categories.contains(spec->category())) {
+ QTreeWidgetItem *citem = new QTreeWidgetItem(m_snippetsTree);
+ citem->setText(0, spec->category());
+ citem->setIcon(0, m_dirIcon);
+ categories.insert(spec->category(), citem);
+ }
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(
+ categories.value(spec->category()));
+ item->setText(0, spec->name());
+ item->setIcon(0, m_fileIcon);
+ QVariant v;
+ qVariantSetValue<SnippetSpec *>(v, spec);
+ item->setData(0, Qt::UserRole, v);
+
+ m_snippets.append(spec);
+ }
+ }
+}
+
+QString SnippetsWindow::createUniqueFileName()
+{
+ int fileNumber = 0;
+ QString baseName = "snippet";
+ while (m_snippetsDir.exists(baseName + QString::number(fileNumber) + ".snp")) {
+ ++fileNumber;
+ }
+ return baseName + QString::number(fileNumber) + ".snp";
+}
+
+void SnippetsWindow::writeSnippet(const QMimeData *)
+{
+}
+
+bool SnippetsWindow::initSnippetsDir()
+{
+ if (!m_snippetsDir.exists(".qworkbench"))
+ m_snippetsDir.mkdir(".qworkbench");
+ if (!m_snippetsDir.cd(".qworkbench"))
+ return false;
+
+ if (!m_snippetsDir.exists("snippets"))
+ m_snippetsDir.mkdir("snippets");
+ return m_snippetsDir.cd("snippets");
+}
+
+void SnippetsWindow::getArguments()
+{
+ QString contents = m_currentSnippet->contents();
+ int index = 0;
+ bool pc = false;
+ QString nrstr;
+
+ QSet<int> requiredArgs;
+ m_requiredArgs.clear();
+ m_args.clear();
+
+ while (index < contents.length()) {
+ QChar c = contents.at(index);
+ if (c == QLatin1Char('%')) {
+ pc = !pc;
+ } else if (pc) {
+ if (c.isNumber()) {
+ nrstr += c;
+ } else {
+ pc = false;
+ }
+ }
+
+ if (!pc && !nrstr.isEmpty()) {
+ requiredArgs << nrstr.toInt();
+ nrstr.clear();
+ }
+
+ ++index;
+ }
+
+ m_requiredArgs = requiredArgs.toList();
+ m_requiredArgs.prepend(-1);
+
+ showInputWidget(false, QString());
+}
+
+void SnippetsWindow::showInputWidget(bool canceled, const QString &value)
+{
+ if (canceled)
+ return;
+
+ TextEditor::ITextEditor *te = 0;
+ if (m_core->editorManager()->currentEditor())
+ te = qobject_cast<TextEditor::ITextEditor*>(
+ m_core->editorManager()->currentEditor());
+
+ int arg = m_requiredArgs.takeFirst();
+ if (arg != -1)
+ m_args << value;
+
+ if (!te || m_requiredArgs.isEmpty()) {
+ qDebug("replaceAndInsert");
+ replaceAndInsert();
+ } else {
+ QString desc = m_currentSnippet->argumentDescription(m_requiredArgs.first());
+ QString def = m_currentSnippet->argumentDefault(m_requiredArgs.first());
+ foreach(QString arg, m_args) {
+ desc = desc.arg(arg);
+ def = def.arg(arg);
+ }
+
+ InputWidget *iw = new InputWidget(desc, def);
+ connect(iw, SIGNAL(finished(bool, const QString &)),
+ this, SLOT(showInputWidget(bool, const QString &)));
+ iw->showInputWidget(te->cursorRect().bottomRight());
+ }
+}
+
+void SnippetsWindow::replaceAndInsert()
+{
+ QString result;
+ QString keyWord;
+ int setAnchor = -1;
+ int setCursor = -1;
+ int selLength = 0;
+
+ //clean up selection
+ int startPos = m_currentEditor->position(TextEditor::ITextEditable::Anchor);
+ int endPos = m_currentEditor->position();
+
+ if (startPos < 0) {
+ startPos = endPos;
+ } else {
+ if (startPos > endPos) {
+ int tmp = startPos;
+ startPos = endPos;
+ endPos = tmp;
+ }
+ selLength = endPos - startPos;
+ }
+
+ //parse the contents
+ m_currentEditor->setCurPos(startPos);
+ QString editorIndent = getCurrentIndent(m_currentEditor);
+ QString content = m_currentSnippet->contents();
+ foreach (const QString &arg, m_args) {
+ content = content.arg(arg);
+ }
+
+ int startOfKey = -1;
+ for (int i = 0; i<content.length(); ++i) {
+ //handle windows,mac and linux new lines...
+ if (content.at(i) == QLatin1Char('\n')) {
+ if ((i <= 0) || content.at(i-1) != QLatin1Char('\r'))
+ result += QLatin1Char('\n') + editorIndent;
+ continue;
+ } else if (content.at(i) == QLatin1Char('\r')) {
+ result += QLatin1Char('\n') + editorIndent;
+ continue;
+ }
+
+ if (content.at(i) == QChar('$')) {
+ if (startOfKey != -1) {
+ m_currentEditor->insert(result);
+ if (keyWord == QLatin1String("selection")) {
+ const QString &indent = indentOfString(content, i);
+ int selStartPos = m_currentEditor->position();
+ m_currentEditor->setCurPos(selStartPos + selLength);
+ insertIdents(m_currentEditor, indent, selStartPos, m_currentEditor->position());
+ } else if (keyWord == QLatin1String("anchor")) {
+ setAnchor = m_currentEditor->position();
+ } else if (keyWord == QLatin1String("cursor")) {
+ setCursor = m_currentEditor->position();
+ }
+ result.clear();
+ keyWord.clear();
+ startOfKey = -1;
+ } else {
+ startOfKey = i;
+ }
+ } else {
+ if (startOfKey != -1)
+ keyWord += content.at(i).toLower();
+ else
+ result += content.at(i);
+ }
+ }
+
+ m_currentEditor->insert(result);
+
+ if (setAnchor != -1) {
+ m_currentEditor->setCurPos(setAnchor);
+ m_currentEditor->select(setCursor);
+ } else if (setCursor != -1) {
+ m_currentEditor->setCurPos(setCursor);
+ }
+}
+
+void SnippetsWindow::insertSnippet(TextEditor::ITextEditable *editor, SnippetSpec *snippet)
+{
+ m_currentEditor = editor;
+ m_currentSnippet = snippet;
+ getArguments();
+}
+
+QString SnippetsWindow::getCurrentIndent(TextEditor::ITextEditor *editor)
+{
+ const int startPos = editor->position(TextEditor::ITextEditor::StartOfLine);
+ const int endPos = editor->position(TextEditor::ITextEditor::EndOfLine);
+ if (startPos < endPos)
+ return indentOfString(editor->textAt(startPos, endPos - startPos));
+ return QString();
+}
+
+void SnippetsWindow::insertIdents(TextEditor::ITextEditable *editor,
+ const QString &indent, int fromPos, int toPos)
+{
+ int offset = 0;
+ const int startPos = editor->position();
+ editor->setCurPos(toPos);
+ int currentLinePos = editor->position(TextEditor::ITextEditor::StartOfLine);
+ while (currentLinePos > fromPos) {
+ editor->setCurPos(currentLinePos);
+ editor->insert(indent);
+ offset += indent.length();
+ editor->setCurPos(currentLinePos-1);
+ currentLinePos = editor->position(TextEditor::ITextEditor::StartOfLine);
+ }
+ editor->setCurPos(startPos + offset);
+}
+
+QString SnippetsWindow::indentOfString(const QString &str, int at)
+{
+ QString result;
+ int startAt = at;
+ if (startAt < 0)
+ startAt = str.length() - 1;
+
+ // find start position
+ while (startAt >= 0 && str.at(startAt) != QChar('\n')
+ && str.at(startAt) != QChar('\r')) --startAt;
+
+ for (int i = (startAt + 1); i < str.length(); ++i) {
+ if (str.at(i) == QChar(' ') || str.at(i) == QChar('\t'))
+ result += str.at(i);
+ else
+ break;
+ }
+
+ return result;
+}
+
+void SnippetsWindow::setOpenIcon(QTreeWidgetItem *item)
+{
+ item->setIcon(0, m_dirOpenIcon);
+}
+
+void SnippetsWindow::setClosedIcon(QTreeWidgetItem *item)
+{
+ item->setIcon(0, m_dirIcon);
+}
+
+void SnippetsWindow::updateDescription(QTreeWidgetItem *item)
+{
+ const SnippetSpec* spec = qVariantValue<SnippetSpec*>(item->data(0, Qt::UserRole));
+ if (spec) {
+ m_descLabel->setText(QLatin1String("<b>") + spec->name() + QLatin1String("</b><br>")
+ + spec->description());
+ } else {
+ m_descLabel->setText(QLatin1String("<b>") + item->text(0) + QLatin1String("</b><br>"));
+ }
+}
+
+SnippetsTree::SnippetsTree(QWidget *parent)
+ : QTreeWidget(parent)
+{
+ setColumnCount(1);
+ header()->setVisible(false);
+ setAlternatingRowColors(true);
+ setAcceptDrops(true);
+}
+
+void SnippetsTree::dropEvent(QDropEvent *)
+{
+ //writeSnippet(event->mimeData());
+}
+
+void SnippetsTree::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasText())
+ event->acceptProposedAction();
+}
+
+void SnippetsTree::dragMoveEvent(QDragMoveEvent *)
+{
+}
diff --git a/src/plugins/snippets/snippetswindow.h b/src/plugins/snippets/snippetswindow.h
new file mode 100644
index 0000000000..9b9f54c376
--- /dev/null
+++ b/src/plugins/snippets/snippetswindow.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SNIPPETSWINDOW_H
+#define SNIPPETSWINDOW_H
+
+#include <QtCore/QDir>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QSplitter>
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QDir;
+class QLabel;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace TextEditor {
+class ITextEditable;
+class ITextEditor;
+}
+
+namespace Snippets {
+namespace Internal {
+
+class SnippetSpec;
+class SnippetsTree;
+class InputWidget;
+
+class SnippetsWindow : public QSplitter
+{
+ Q_OBJECT
+
+public:
+ SnippetsWindow();
+ ~SnippetsWindow();
+ const QList<SnippetSpec *> &snippets() const;
+ void insertSnippet(TextEditor::ITextEditable *editor, SnippetSpec *snippet);
+
+private slots:
+ void updateDescription(QTreeWidgetItem *item);
+ void activateSnippet(QTreeWidgetItem *item, int column);
+ void setOpenIcon(QTreeWidgetItem *item);
+ void setClosedIcon(QTreeWidgetItem *item);
+
+ void showInputWidget(bool canceled, const QString &value);
+
+private:
+ void getArguments();
+ void replaceAndInsert();
+ QString indentOfString(const QString &str, int at = -1);
+ void insertIdents(TextEditor::ITextEditable *editor,
+ const QString &indent, int fromPos, int toPos);
+ QString getCurrentIndent(TextEditor::ITextEditor *editor);
+
+ QList<SnippetSpec *> m_snippets;
+ QString createUniqueFileName();
+ void writeSnippet(const QMimeData *mData);
+ bool initSnippetsDir();
+ void initSnippets(const QDir &dir);
+
+ QList<int> m_requiredArgs;
+ QStringList m_args;
+ SnippetSpec *m_currentSnippet;
+ TextEditor::ITextEditable *m_currentEditor;
+
+ Core::ICore *m_core;
+ QDir m_snippetsDir;
+
+ SnippetsTree *m_snippetsTree;
+
+ QLabel *m_descLabel;
+
+ static const QIcon m_fileIcon;
+ static const QIcon m_dirIcon;
+ static const QIcon m_dirOpenIcon;
+};
+
+class SnippetsTree : public QTreeWidget
+{
+ Q_OBJECT
+
+public:
+ SnippetsTree(QWidget *parent);
+
+protected:
+ void dragMoveEvent(QDragMoveEvent * event);
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dropEvent(QDropEvent *event);
+};
+
+} // namespace Internal
+} // namespace Snippets
+
+#endif // SNIPPETSWINDOW_H
+
diff --git a/src/plugins/subversion/Subversion.mimetypes.xml b/src/plugins/subversion/Subversion.mimetypes.xml
new file mode 100644
index 0000000000..6aa0c3eda9
--- /dev/null
+++ b/src/plugins/subversion/Subversion.mimetypes.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/vnd.nokia.text.subversion.submit">
+ <comment>Subversion submit template</comment>
+ <sub-class-of type="text/plain"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/subversion/Subversion.pluginspec b/src/plugins/subversion/Subversion.pluginspec
new file mode 100644
index 0000000000..f503ff1340
--- /dev/null
+++ b/src/plugins/subversion/Subversion.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="Subversion" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Subversion integration.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="VCSBase" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/subversion/annotationhighlighter.cpp b/src/plugins/subversion/annotationhighlighter.cpp
new file mode 100644
index 0000000000..e6269ef061
--- /dev/null
+++ b/src/plugins/subversion/annotationhighlighter.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "annotationhighlighter.h"
+
+namespace Subversion {
+namespace Internal {
+
+SubversionAnnotationHighlighter::SubversionAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ VCSBase::BaseAnnotationHighlighter(changeNumbers, document),
+ m_blank(QLatin1Char(' '))
+{
+}
+
+QString SubversionAnnotationHighlighter::changeNumber(const QString &block) const
+{
+ const int pos = block.indexOf(m_blank);
+ return pos > 1 ? block.left(pos) : QString();
+}
+
+}
+}
diff --git a/src/plugins/subversion/annotationhighlighter.h b/src/plugins/subversion/annotationhighlighter.h
new file mode 100644
index 0000000000..4078ea477e
--- /dev/null
+++ b/src/plugins/subversion/annotationhighlighter.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ANNOTATIONHIGHLIGHTER_H
+#define ANNOTATIONHIGHLIGHTER_H
+
+#include <vcsbase/baseannotationhighlighter.h>
+
+namespace Subversion {
+namespace Internal {
+
+// Annotation highlighter for subversion triggering on 'changenumber '
+class SubversionAnnotationHighlighter : public VCSBase::BaseAnnotationHighlighter
+{
+ Q_OBJECT
+public:
+ explicit SubversionAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = 0);
+
+private:
+ virtual QString changeNumber(const QString &block) const;
+
+ const QChar m_blank;
+};
+
+} //namespace Subversion
+} //namespace Internal
+
+#endif
diff --git a/src/plugins/subversion/changenumberdialog.cpp b/src/plugins/subversion/changenumberdialog.cpp
new file mode 100644
index 0000000000..4cdb6b05e1
--- /dev/null
+++ b/src/plugins/subversion/changenumberdialog.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QIntValidator>
+
+#include "changenumberdialog.h"
+
+using namespace Subversion::Internal;
+
+ChangeNumberDialog::ChangeNumberDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ m_ui.numberLineEdit->setValidator(new QIntValidator(0, 1000000, this));
+}
+
+int ChangeNumberDialog::number() const
+{
+ if (m_ui.numberLineEdit->text().isEmpty())
+ return -1;
+ bool ok;
+ return m_ui.numberLineEdit->text().toInt(&ok);
+}
diff --git a/src/plugins/subversion/changenumberdialog.h b/src/plugins/subversion/changenumberdialog.h
new file mode 100644
index 0000000000..ebc2d87cb8
--- /dev/null
+++ b/src/plugins/subversion/changenumberdialog.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CHANGENUMBERDIALOG_H
+#define CHANGENUMBERDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_changenumberdialog.h"
+
+namespace Subversion {
+namespace Internal {
+
+class ChangeNumberDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ChangeNumberDialog(QWidget *parent = 0);
+ int number() const;
+
+private:
+ Ui::ChangeNumberDialog m_ui;
+
+};
+
+} //namespace Subversion
+} //namespace Internal
+
+#endif
+
+
diff --git a/src/plugins/subversion/changenumberdialog.ui b/src/plugins/subversion/changenumberdialog.ui
new file mode 100644
index 0000000000..ff3e651750
--- /dev/null
+++ b/src/plugins/subversion/changenumberdialog.ui
@@ -0,0 +1,79 @@
+<ui version="4.0" >
+ <class>Subversion::Internal::ChangeNumberDialog</class>
+ <widget class="QDialog" name="Subversion::Internal::ChangeNumberDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>319</width>
+ <height>76</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Change Number</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="numberLineEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Change Number:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <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>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Subversion::Internal::ChangeNumberDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>59</x>
+ <y>24</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>160</x>
+ <y>38</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Subversion::Internal::ChangeNumberDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>59</x>
+ <y>24</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>160</x>
+ <y>38</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/subversion/images/diff.png b/src/plugins/subversion/images/diff.png
new file mode 100644
index 0000000000..b3597f9ff8
--- /dev/null
+++ b/src/plugins/subversion/images/diff.png
Binary files differ
diff --git a/src/plugins/subversion/images/submit.png b/src/plugins/subversion/images/submit.png
new file mode 100644
index 0000000000..4f302302b9
--- /dev/null
+++ b/src/plugins/subversion/images/submit.png
Binary files differ
diff --git a/src/plugins/subversion/settingspage.cpp b/src/plugins/subversion/settingspage.cpp
new file mode 100644
index 0000000000..16ed648483
--- /dev/null
+++ b/src/plugins/subversion/settingspage.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+#include "subversionsettings.h"
+#include "subversionplugin.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtGui/QFileDialog>
+
+using namespace Subversion::Internal;
+
+SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.browseButton, SIGNAL(clicked()), this, SLOT(browseForCommand()));
+}
+
+SubversionSettings SettingsPageWidget::settings() const
+{
+ SubversionSettings rc;
+ rc.svnCommand = m_ui.svnCmdLineEdit->text();
+ rc.useAuthentication = m_ui.userGroupBox->isChecked();
+ rc.user = m_ui.usernameLineEdit->text();
+ rc.password = m_ui.passwordLineEdit->text();
+ if (rc.user.isEmpty())
+ rc.useAuthentication = false;
+ return rc;
+}
+
+void SettingsPageWidget::setSettings(const SubversionSettings &s)
+{
+ m_ui.svnCmdLineEdit->setText(s.svnCommand);
+ m_ui.usernameLineEdit->setText(s.user);
+ m_ui.passwordLineEdit->setText(s.password);
+ m_ui.userGroupBox->setChecked(s.useAuthentication);
+}
+
+void SettingsPageWidget::browseForCommand()
+{
+ QString cmd = QFileDialog::getOpenFileName(window(), tr("Subversion Command"));
+ if (!cmd.isEmpty())
+ m_ui.svnCmdLineEdit->setText(cmd);
+}
+
+SettingsPage::SettingsPage()
+{
+}
+
+QString SettingsPage::name() const
+{
+ return tr("General");
+}
+
+QString SettingsPage::category() const
+{
+ return QLatin1String("Subversion");
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("Subversion");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ if (!m_widget)
+ m_widget = new SettingsPageWidget(parent);
+ m_widget->setSettings(SubversionPlugin::subversionPluginInstance()->settings());
+ return m_widget;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted || !m_widget)
+ return;
+ SubversionPlugin::subversionPluginInstance()->setSettings(m_widget->settings());
+}
diff --git a/src/plugins/subversion/settingspage.h b/src/plugins/subversion/settingspage.h
new file mode 100644
index 0000000000..6bed2236b0
--- /dev/null
+++ b/src/plugins/subversion/settingspage.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSPAGE_H
+#define SETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+#include <QtCore/QPointer>
+#include <QtCore/QString>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_settingspage.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Subversion {
+ namespace Internal {
+
+struct SubversionSettings;
+
+class SettingsPageWidget : public QWidget {
+ Q_OBJECT
+public:
+ explicit SettingsPageWidget(QWidget *parent = 0);
+
+ SubversionSettings settings() const;
+ void setSettings(const SubversionSettings &);
+
+private slots:;
+ void browseForCommand();
+
+private:
+ Ui::SettingsPage m_ui;
+};
+
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+private:
+ QPointer<SettingsPageWidget> m_widget;
+};
+
+ } //namespace Subversion
+} //namespace Internal
+
+#endif // SETTINGSPAGE_H
diff --git a/src/plugins/subversion/settingspage.ui b/src/plugins/subversion/settingspage.ui
new file mode 100644
index 0000000000..14e5ebce87
--- /dev/null
+++ b/src/plugins/subversion/settingspage.ui
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Subversion::Internal::SettingsPage</class>
+ <widget class="QWidget" name="Subversion::Internal::SettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>427</width>
+ <height>280</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="commandHBox">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="commandLabel">
+ <property name="text">
+ <string>Subversion Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="svnCmdLineEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="browseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="userGroupBox">
+ <property name="title">
+ <string>Authentication</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="usernameLabel">
+ <property name="text">
+ <string>User name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="usernameLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="passwordLabel">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="passwordLineEdit">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>105</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>svnCmdLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/subversion/subversion.pro b/src/plugins/subversion/subversion.pro
new file mode 100644
index 0000000000..7de5499fa7
--- /dev/null
+++ b/src/plugins/subversion/subversion.pro
@@ -0,0 +1,34 @@
+TEMPLATE = lib
+TARGET = Subversion
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/vcsbase/vcsbase.pri)
+include(../../libs/utils/utils.pri)
+
+HEADERS += annotationhighlighter.h \
+ subversionplugin.h \
+ subversioncontrol.h \
+ subversionoutputwindow.h \
+ settingspage.h \
+ subversioneditor.h \
+ changenumberdialog.h \
+ subversionsubmiteditor.h \
+ subversionsettings.h
+
+SOURCES += annotationhighlighter.cpp \
+ subversionplugin.cpp \
+ subversioncontrol.cpp \
+ subversionoutputwindow.cpp \
+ settingspage.cpp \
+ subversioneditor.cpp \
+ changenumberdialog.cpp \
+ subversionsubmiteditor.cpp \
+ subversionsettings.cpp
+
+FORMS += settingspage.ui \
+ changenumberdialog.ui
+
+RESOURCES += subversion.qrc
diff --git a/src/plugins/subversion/subversion.qrc b/src/plugins/subversion/subversion.qrc
new file mode 100644
index 0000000000..7fa3a2a31e
--- /dev/null
+++ b/src/plugins/subversion/subversion.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/trolltech.subversion" >
+ <file>images/diff.png</file>
+ <file>images/submit.png</file>
+ <file>Subversion.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/subversion/subversionconstants.h b/src/plugins/subversion/subversionconstants.h
new file mode 100644
index 0000000000..eaf2575508
--- /dev/null
+++ b/src/plugins/subversion/subversionconstants.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSION_CONSTANTS_H
+#define SUBVERSION_CONSTANTS_H
+
+namespace Subversion {
+ namespace Constants {
+ const char * const SUBVERSION_SUBMIT_MIMETYPE = "application/vnd.nokia.text.subversion.submit";
+ const char * const SUBVERSIONEDITOR = "Subversion Editor";
+ const char * const SUBVERSIONEDITOR_KIND = "Subversion Editor";
+ const char * const SUBVERSIONCOMMITEDITOR = "Subversion Commit Editor";
+ const char * const SUBVERSIONCOMMITEDITOR_KIND = "Subversion Commit Editor";
+ const char * const ICON_SUBMIT = ":/trolltech.subversion/images/submit.png";
+ const char * const ICON_DIFF = ":/trolltech.subversion/images/diff.png";
+ const char * const SUBMIT_CURRENT = "Nokia.Subversion.SubmitCurrentLog";
+ const char * const DIFF_SELECTED = "Nokia.Subversion.DiffSelectedFilesInLog";
+ enum { debug = 0 };
+ }
+}
+
+#endif
diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp
new file mode 100644
index 0000000000..0357eccf5b
--- /dev/null
+++ b/src/plugins/subversion/subversioncontrol.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "subversioncontrol.h"
+#include "subversionplugin.h"
+
+namespace Subversion {
+namespace Internal {
+
+SubversionControl::SubversionControl(SubversionPlugin *plugin) :
+ m_plugin(plugin)
+{
+}
+
+bool SubversionControl::vcsOpen(const QString & /* fileName */)
+{
+ // Open for edit: N/A
+ return true;
+}
+
+bool SubversionControl::vcsAdd(const QString &fileName)
+{
+ return m_plugin->vcsAdd(fileName);
+}
+
+bool SubversionControl::vcsDelete(const QString &fileName)
+{
+ return m_plugin->vcsDelete(fileName);
+}
+
+bool SubversionControl::managesDirectory(const QString &directory) const
+{
+ return m_plugin->managesDirectory(directory);
+}
+
+QString SubversionControl::findTopLevelForDirectory(const QString &directory) const
+{
+ return m_plugin->findTopLevelForDirectory(directory);
+}
+}
+}
diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h
new file mode 100644
index 0000000000..7be525275f
--- /dev/null
+++ b/src/plugins/subversion/subversioncontrol.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSIONCONTROL_H
+#define SUBVERSIONCONTROL_H
+
+#include <coreplugin/iversioncontrol.h>
+
+namespace Subversion {
+namespace Internal {
+class SubversionPlugin;
+
+// Just a proxy for SubversionPlugin
+class SubversionControl : public Core::IVersionControl
+{
+ Q_OBJECT
+public:
+ explicit SubversionControl(SubversionPlugin *plugin);
+ virtual bool managesDirectory(const QString &directory) const;
+ virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool vcsOpen(const QString &fileName);
+ virtual bool vcsAdd(const QString &fileName);
+ virtual bool vcsDelete(const QString &filename);
+
+private:
+ SubversionPlugin *m_plugin;
+};
+
+}
+}
+#endif
diff --git a/src/plugins/subversion/subversioneditor.cpp b/src/plugins/subversion/subversioneditor.cpp
new file mode 100644
index 0000000000..d87138aae1
--- /dev/null
+++ b/src/plugins/subversion/subversioneditor.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "subversioneditor.h"
+#include "annotationhighlighter.h"
+#include "subversionconstants.h"
+
+#include <vcsbase/diffhighlighter.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QTextCursor>
+
+namespace Subversion {
+namespace Internal {
+
+SubversionEditor::SubversionEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent) :
+ VCSBase::VCSBaseEditor(type, parent),
+ m_changeNumberPattern(QLatin1String("^\\d+$")),
+ m_revisionNumberPattern(QLatin1String("^r\\d+$"))
+{
+ Q_ASSERT(m_changeNumberPattern.isValid());
+ Q_ASSERT(m_revisionNumberPattern.isValid());
+}
+
+QSet<QString> SubversionEditor::annotationChanges() const
+{
+ QSet<QString> changes;
+ const QString txt = toPlainText();
+ if (txt.isEmpty())
+ return changes;
+ // Hunt for first change number in annotation: "<change>:"
+ QRegExp r(QLatin1String("^(\\d+):"));
+ Q_ASSERT(r.isValid());
+ if (r.indexIn(txt) != -1) {
+ changes.insert(r.cap(1));
+ r.setPattern(QLatin1String("\n(\\d+):"));
+ Q_ASSERT(r.isValid());
+ int pos = 0;
+ while ((pos = r.indexIn(txt, pos)) != -1) {
+ pos += r.matchedLength();
+ changes.insert(r.cap(1));
+ }
+ }
+ if (Subversion::Constants::debug)
+ qDebug() << "SubversionEditor::annotationChanges() returns #" << changes.size();
+ return changes;
+}
+
+QString SubversionEditor::changeUnderCursor(const QTextCursor &c) const
+{
+ QTextCursor cursor = c;
+ // Any number is regarded as change number.
+ cursor.select(QTextCursor::WordUnderCursor);
+ if (!cursor.hasSelection())
+ return QString();
+ QString change = cursor.selectedText();
+ // Annotation output has number, log output has revision numbers
+ // as r1, r2...
+ if (m_changeNumberPattern.exactMatch(change))
+ return change;
+ if (m_revisionNumberPattern.exactMatch(change)) {
+ change.remove(0, 1);
+ return change;
+ }
+ return QString();
+}
+
+/* code:
+ Index: main.cpp
+===================================================================
+--- main.cpp (revision 2)
++++ main.cpp (working copy)
+@@ -6,6 +6,5 @@
+\endcode
+*/
+
+VCSBase::DiffHighlighter *SubversionEditor::createDiffHighlighter() const
+{
+ const QRegExp filePattern(QLatin1String("^[-+][-+][-+] .*|^Index: .*|^==*$"));
+ Q_ASSERT(filePattern.isValid());
+ return new VCSBase::DiffHighlighter(filePattern);
+}
+
+VCSBase::BaseAnnotationHighlighter *SubversionEditor::createAnnotationHighlighter(const QSet<QString> &changes) const
+{
+ return new SubversionAnnotationHighlighter(changes);
+}
+
+QString SubversionEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
+{
+ // "+++ /depot/.../mainwindow.cpp<tab>(revision 3)"
+ // Go back chunks
+ const QString diffIndicator = QLatin1String("+++ ");
+ for (QTextBlock block = inBlock; block.isValid() ; block = block.previous()) {
+ QString diffFileName = block.text();
+ if (diffFileName.startsWith(diffIndicator)) {
+ diffFileName.remove(0, diffIndicator.size());
+ const int tabIndex = diffFileName.lastIndexOf(QLatin1Char('\t'));
+ if (tabIndex != -1)
+ diffFileName.truncate(tabIndex);
+ if (Subversion::Constants::debug)
+ qDebug() << Q_FUNC_INFO << diffFileName;
+ return diffFileName;
+ }
+ }
+ return QString();
+}
+
+}
+}
diff --git a/src/plugins/subversion/subversioneditor.h b/src/plugins/subversion/subversioneditor.h
new file mode 100644
index 0000000000..9dee4a9d5a
--- /dev/null
+++ b/src/plugins/subversion/subversioneditor.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSIONEDITOR_H
+#define SUBVERSIONEDITOR_H
+
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/QRegExp>
+
+namespace Subversion {
+namespace Internal {
+
+class SubversionEditor : public VCSBase::VCSBaseEditor
+{
+ Q_OBJECT
+
+public:
+ explicit SubversionEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent);
+
+private:
+ virtual QSet<QString> annotationChanges() const;
+ virtual QString changeUnderCursor(const QTextCursor &) const;
+ virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
+ virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const;
+ virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const;
+
+ const QRegExp m_changeNumberPattern;
+ const QRegExp m_revisionNumberPattern;
+};
+
+} // namespace Internal
+} // namespace Subversion
+
+#endif // SUBVERSIONEDITOR_H
diff --git a/src/plugins/subversion/subversionoutputwindow.cpp b/src/plugins/subversion/subversionoutputwindow.cpp
new file mode 100644
index 0000000000..f3d8fd8ac1
--- /dev/null
+++ b/src/plugins/subversion/subversionoutputwindow.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "subversionoutputwindow.h"
+#include "subversionplugin.h"
+
+#include <QtGui/QListWidget>
+#include <QtCore/QDebug>
+
+using namespace Subversion::Internal;
+
+SubversionOutputWindow::SubversionOutputWindow(SubversionPlugin *svnPlugin)
+ : m_svnPlugin(svnPlugin)
+{
+ m_outputListWidget = new QListWidget;
+ m_outputListWidget->setFrameStyle(QFrame::NoFrame);
+ m_outputListWidget->setWindowTitle(tr("Subversion Output"));
+ m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+}
+
+SubversionOutputWindow::~SubversionOutputWindow()
+{
+ delete m_outputListWidget;
+}
+
+QWidget *SubversionOutputWindow::outputWidget(QWidget *parent)
+{
+ m_outputListWidget->setParent(parent);
+ return m_outputListWidget;
+}
+
+QString SubversionOutputWindow::name() const
+{
+ return tr("Subversion");
+}
+
+void SubversionOutputWindow::clearContents()
+{
+ m_outputListWidget->clear();
+}
+
+int SubversionOutputWindow::priorityInStatusBar() const
+{
+ return -1;
+}
+
+void SubversionOutputWindow::visibilityChanged(bool b)
+{
+ if (b)
+ m_outputListWidget->setFocus();
+}
+
+void SubversionOutputWindow::append(const QString &txt, bool doPopup)
+{
+ const QStringList lines = txt.split(QLatin1Char('\n'));
+ foreach (const QString &s, lines)
+ m_outputListWidget->addItem(s);
+ m_outputListWidget->scrollToBottom();
+
+ if (doPopup)
+ popup();
+}
+
+bool SubversionOutputWindow::canFocus()
+{
+ return false;
+}
+
+bool SubversionOutputWindow::hasFocus()
+{
+ return m_outputListWidget->hasFocus();
+}
+
+void SubversionOutputWindow::setFocus()
+{
+}
diff --git a/src/plugins/subversion/subversionoutputwindow.h b/src/plugins/subversion/subversionoutputwindow.h
new file mode 100644
index 0000000000..cd1bda5e9d
--- /dev/null
+++ b/src/plugins/subversion/subversionoutputwindow.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSIONOUTPUTWINDOW_H
+#define SUBVERSIONOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+QT_BEGIN_NAMESPACE
+class QListWidget;
+QT_END_NAMESPACE
+
+namespace Subversion {
+ namespace Internal {
+
+class SubversionPlugin;
+
+class SubversionOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ SubversionOutputWindow(SubversionPlugin *svnPlugin);
+ ~SubversionOutputWindow();
+
+ QWidget *outputWidget(QWidget *parent);
+ QList<QWidget*> toolBarWidgets(void) const {
+ return QList<QWidget *>();
+ }
+
+ QString name() const;
+ void clearContents();
+ int priorityInStatusBar() const;
+ void visibilityChanged(bool visible);
+
+ virtual bool canFocus();
+ virtual bool hasFocus();
+ virtual void setFocus();
+
+public slots:
+ void append(const QString &txt, bool popup = false);
+
+private:
+
+ SubversionPlugin *m_svnPlugin;
+ QListWidget *m_outputListWidget;
+};
+
+} // namespace Subversion
+} // namespace Internal
+
+#endif
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
new file mode 100644
index 0000000000..7c44e87fea
--- /dev/null
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -0,0 +1,1087 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "subversionplugin.h"
+
+#include "settingspage.h"
+#include "subversioneditor.h"
+
+#include "subversionoutputwindow.h"
+#include "subversionsubmiteditor.h"
+#include "changenumberdialog.h"
+#include "subversionconstants.h"
+#include "subversioncontrol.h"
+
+#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/basevcssubmiteditorfactory.h>
+#include <utils/synchronousprocess.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QTextCodec>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDir>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtGui/QFileDialog>
+
+using namespace Subversion::Internal;
+
+// Timeout for normal output commands
+enum { subversionShortTimeOut = 10000 };
+// Timeout for submit, update
+enum { subversionLongTimeOut = 120000 };
+
+// #pragma mark -- SubversionPlugin
+
+const char * const SubversionPlugin::SUBVERSION_MENU = "Subversion.Menu";
+const char * const SubversionPlugin::ADD = "Subversion.Add";
+const char * const SubversionPlugin::DELETE_FILE = "Subversion.Delete";
+const char * const SubversionPlugin::REVERT = "Subversion.Revert";
+const char * const SubversionPlugin::SEPARATOR0 = "Subversion.Separator0";
+const char * const SubversionPlugin::DIFF_PROJECT = "Subversion.DiffAll";
+const char * const SubversionPlugin::DIFF_CURRENT = "Subversion.DiffCurrent";
+const char * const SubversionPlugin::SEPARATOR1 = "Subversion.Separator1";
+const char * const SubversionPlugin::COMMIT_ALL = "Subversion.CommitAll";
+const char * const SubversionPlugin::COMMIT_CURRENT = "Subversion.CommitCurrent";
+const char * const SubversionPlugin::SEPARATOR2 = "Subversion.Separator2";
+const char * const SubversionPlugin::FILELOG_CURRENT = "Subversion.FilelogCurrent";
+const char * const SubversionPlugin::ANNOTATE_CURRENT = "Subversion.AnnotateCurrent";
+const char * const SubversionPlugin::SEPARATOR3 = "Subversion.Separator3";
+const char * const SubversionPlugin::STATUS = "Subversion.Status";
+const char * const SubversionPlugin::UPDATE = "Subversion.Update";
+
+static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
+{
+ VCSBase::RegularCommandOutput,
+ "Subversion Command Log Editor",
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_svn_commandlog",
+ "scslog"},
+{ VCSBase::LogOutput,
+ "Subversion File Log Editor",
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_svn_filelog",
+ "scsfilelog"},
+{ VCSBase::AnnotateOutput,
+ "Subversion Annotation Editor",
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_svn_annotation",
+ "scsannotate"},
+{ VCSBase::DiffOutput,
+ "Subversion Diff Editor",
+ Core::Constants::C_GLOBAL,
+ "text/x-patch","diff"}
+};
+
+// Utility to find a parameter set by type
+static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
+{
+ const VCSBase::EditorContentType et = static_cast<VCSBase::EditorContentType>(ie);
+ return VCSBase::VCSBaseEditor::findType(editorParameters, sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters), et);
+}
+
+static inline QString debugCodec(const QTextCodec *c)
+{
+ return c ? QString::fromAscii(c->name()) : QString::fromAscii("Null codec");
+}
+
+inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property, const QString &entry)
+{
+ foreach (Core::IEditor *ed, core->editorManager()->openedEditors())
+ if (ed->property(property).toString() == entry)
+ return ed;
+ return 0;
+}
+
+// ------------- SubversionPlugin
+Core::ICore *SubversionPlugin::m_coreInstance = 0;
+SubversionPlugin *SubversionPlugin::m_subversionPluginInstance = 0;
+
+SubversionPlugin::SubversionPlugin() :
+ m_svnDotDirectory(QLatin1String(".svn")),
+ m_versionControl(0),
+ m_coreListener(0),
+ m_settingsPage(0),
+ m_changeTmpFile(0),
+ m_submitEditorFactory(0),
+ m_subversionOutputWindow(0),
+ m_projectExplorer(0),
+ m_addAction(0),
+ m_deleteAction(0),
+ m_revertAction(0),
+ m_diffProjectAction(0),
+ m_diffCurrentAction(0),
+ m_commitAllAction(0),
+ m_commitCurrentAction(0),
+ m_filelogCurrentAction(0),
+ m_annotateCurrentAction(0),
+ m_statusAction(0),
+ m_updateProjectAction(0),
+ m_submitCurrentLogAction(0),
+ m_submitDiffAction(0),
+ m_submitUndoAction(0),
+ m_submitRedoAction(0)
+{
+}
+
+SubversionPlugin::~SubversionPlugin()
+{
+ if (m_versionControl) {
+ removeObject(m_versionControl);
+ delete m_versionControl;
+ m_versionControl = 0;
+ }
+
+ if (m_settingsPage) {
+ removeObject(m_settingsPage);
+ delete m_settingsPage;
+ m_settingsPage = 0;
+ }
+ if (m_subversionOutputWindow) {
+ removeObject(m_subversionOutputWindow);
+ delete m_subversionOutputWindow;
+ m_subversionOutputWindow = 0;
+ }
+ if (m_submitEditorFactory) {
+ removeObject(m_submitEditorFactory);
+ delete m_submitEditorFactory;
+ m_submitEditorFactory = 0;
+ }
+
+ if (!m_editorFactories.empty()) {
+ foreach(Core::IEditorFactory* pf, m_editorFactories)
+ removeObject(pf);
+ qDeleteAll(m_editorFactories);
+ m_editorFactories.clear();
+ }
+
+ if (m_coreListener) {
+ removeObject(m_coreListener);
+ delete m_coreListener;
+ m_coreListener = 0;
+ }
+ cleanChangeTmpFile();
+}
+
+void SubversionPlugin::cleanChangeTmpFile()
+{
+ if (m_changeTmpFile) {
+ if (m_changeTmpFile->isOpen())
+ m_changeTmpFile->close();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ }
+}
+
+static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
+ Subversion::Constants::SUBVERSION_SUBMIT_MIMETYPE,
+ Subversion::Constants::SUBVERSIONCOMMITEDITOR_KIND,
+ Subversion::Constants::SUBVERSIONCOMMITEDITOR,
+ Core::Constants::UNDO,
+ Core::Constants::REDO,
+ Subversion::Constants::SUBMIT_CURRENT,
+ Subversion::Constants::DIFF_SELECTED
+};
+
+bool SubversionPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ typedef VCSBase::VCSSubmitEditorFactory<SubversionSubmitEditor> SubversionSubmitEditorFactory;
+ typedef VCSBase::VCSEditorFactory<SubversionEditor> SubversionEditorFactory;
+ using namespace Constants;
+
+ using namespace Core::Constants;
+ using namespace ExtensionSystem;
+
+ m_subversionPluginInstance = this;
+ m_coreInstance = PluginManager::instance()->getObject<Core::ICore>();
+
+ if (!m_coreInstance->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.subversion/Subversion.mimetypes.xml"), errorMessage))
+ return false;
+
+ m_versionControl = new SubversionControl(this);
+ addObject(m_versionControl);
+
+ if (QSettings *settings = m_coreInstance->settings())
+ m_settings.fromSettings(settings);
+
+ m_coreListener = new CoreListener(this);
+ addObject(m_coreListener);
+
+ m_settingsPage = new SettingsPage;
+ addObject(m_settingsPage);
+
+ m_submitEditorFactory = new SubversionSubmitEditorFactory(&submitParameters);
+ addObject(m_submitEditorFactory);
+
+ static const char *describeSlot = SLOT(describe(QString,QString));
+ const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
+ for (int i = 0; i < editorCount; i++) {
+ m_editorFactories.push_back(new SubversionEditorFactory(editorParameters + i, m_coreInstance, this, describeSlot));
+ addObject(m_editorFactories.back());
+ }
+
+ m_subversionOutputWindow = new SubversionOutputWindow(this);
+ addObject(m_subversionOutputWindow);
+
+ //register actions
+ Core::ActionManagerInterface *ami = m_coreInstance->actionManager();
+ Core::IActionContainer *toolsContainer = ami->actionContainer(M_TOOLS);
+
+ Core::IActionContainer *subversionMenu =
+ ami->createMenu(QLatin1String(SUBVERSION_MENU));
+ subversionMenu->menu()->setTitle(tr("&Subversion"));
+ toolsContainer->addMenu(subversionMenu);
+
+ QList<int> globalcontext;
+ globalcontext << m_coreInstance->uniqueIDManager()->uniqueIdentifier(C_GLOBAL);
+
+ Core::ICommand *command;
+ m_addAction = new QAction(tr("Add"), this);
+ command = ami->registerAction(m_addAction, SubversionPlugin::ADD,
+ globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+S,Alt+A")));
+ connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile()));
+ subversionMenu->addAction(command);
+
+ m_deleteAction = new QAction(tr("Delete"), this);
+ command = ami->registerAction(m_deleteAction, SubversionPlugin::DELETE_FILE,
+ globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deleteCurrentFile()));
+ subversionMenu->addAction(command);
+
+ m_revertAction = new QAction(tr("Revert"), this);
+ command = ami->registerAction(m_revertAction, SubversionPlugin::REVERT,
+ globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
+ subversionMenu->addAction(command);
+
+ QAction *tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ subversionMenu->addAction(ami->registerAction(tmpaction,
+ SubversionPlugin::SEPARATOR0, globalcontext));
+
+ m_diffProjectAction = new QAction(tr("Diff Project"), this);
+ command = ami->registerAction(m_diffProjectAction, SubversionPlugin::DIFF_PROJECT,
+ globalcontext);
+ connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffProject()));
+ subversionMenu->addAction(command);
+
+ m_diffCurrentAction = new QAction(tr("Diff Current File"), this);
+ command = ami->registerAction(m_diffCurrentAction,
+ SubversionPlugin::DIFF_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+S,Alt+D")));
+ connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
+ subversionMenu->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ subversionMenu->addAction(ami->registerAction(tmpaction,
+ SubversionPlugin::SEPARATOR1, globalcontext));
+
+ m_commitAllAction = new QAction(tr("Commit All Files"), this);
+ command = ami->registerAction(m_commitAllAction, SubversionPlugin::COMMIT_ALL,
+ globalcontext);
+ connect(m_commitAllAction, SIGNAL(triggered()), this, SLOT(startCommitAll()));
+ subversionMenu->addAction(command);
+
+ m_commitCurrentAction = new QAction(tr("Commit Current File"), this);
+ command = ami->registerAction(m_commitCurrentAction,
+ SubversionPlugin::COMMIT_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+S,Alt+C")));
+ connect(m_commitCurrentAction, SIGNAL(triggered()), this, SLOT(startCommitCurrentFile()));
+ subversionMenu->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ subversionMenu->addAction(ami->registerAction(tmpaction,
+ SubversionPlugin::SEPARATOR2, globalcontext));
+
+ m_filelogCurrentAction = new QAction(tr("Filelog Current File"), this);
+ command = ami->registerAction(m_filelogCurrentAction,
+ SubversionPlugin::FILELOG_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_filelogCurrentAction, SIGNAL(triggered()), this,
+ SLOT(filelogCurrentFile()));
+ subversionMenu->addAction(command);
+
+ m_annotateCurrentAction = new QAction(tr("Annotate Current File"), this);
+ command = ami->registerAction(m_annotateCurrentAction,
+ SubversionPlugin::ANNOTATE_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_annotateCurrentAction, SIGNAL(triggered()), this,
+ SLOT(annotateCurrentFile()));
+ subversionMenu->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ subversionMenu->addAction(ami->registerAction(tmpaction,
+ SubversionPlugin::SEPARATOR3, globalcontext));
+
+ m_statusAction = new QAction(tr("Project Status"), this);
+ command = ami->registerAction(m_statusAction, SubversionPlugin::STATUS,
+ globalcontext);
+ connect(m_statusAction, SIGNAL(triggered()), this, SLOT(projectStatus()));
+ subversionMenu->addAction(command);
+
+ m_updateProjectAction = new QAction(tr("Update Project"), this);
+ command = ami->registerAction(m_updateProjectAction, SubversionPlugin::UPDATE, globalcontext);
+ connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateProject()));
+ subversionMenu->addAction(command);
+
+ // Actions of the submit editor
+ QList<int> svncommitcontext;
+ svncommitcontext << m_coreInstance->uniqueIDManager()->uniqueIdentifier(Constants::SUBVERSIONCOMMITEDITOR);
+
+ m_submitCurrentLogAction = new QAction(QIcon(Constants::ICON_SUBMIT), tr("Commit"), this);
+ command = ami->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, svncommitcontext);
+ connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
+
+ m_submitDiffAction = new QAction(QIcon(Constants::ICON_DIFF), tr("Diff Selected Files"), this);
+ command = ami->registerAction(m_submitDiffAction , Constants::DIFF_SELECTED, svncommitcontext);
+
+ m_submitUndoAction = new QAction(tr("&Undo"), this);
+ command = ami->registerAction(m_submitUndoAction, Core::Constants::UNDO, svncommitcontext);
+
+ m_submitRedoAction = new QAction(tr("&Redo"), this);
+ command = ami->registerAction(m_submitRedoAction, Core::Constants::REDO, svncommitcontext);
+
+ connect(m_coreInstance, SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions()));
+
+ return true;
+}
+
+void SubversionPlugin::extensionsInitialized()
+{
+ using namespace ExtensionSystem;
+ using namespace ProjectExplorer;
+
+ m_projectExplorer = PluginManager::instance()->getObject<ProjectExplorerPlugin>();
+ if (m_projectExplorer) {
+ connect(m_projectExplorer,
+ SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
+ m_subversionPluginInstance, SLOT(updateActions()));
+ }
+ updateActions();
+}
+
+bool SubversionPlugin::editorAboutToClose(Core::IEditor *iEditor)
+{
+ if (!m_changeTmpFile || !iEditor || qstrcmp(Constants::SUBVERSIONCOMMITEDITOR, iEditor->kind()))
+ return true;
+
+ Core::IFile *fileIFace = iEditor->file();
+ const SubversionSubmitEditor *editor = qobject_cast<SubversionSubmitEditor *>(iEditor);
+ if (!fileIFace || !editor)
+ return true;
+
+ // Submit editor closing. Make it write out the commit message
+ // and retrieve files
+ const QFileInfo editorFile(fileIFace->fileName());
+ const QFileInfo changeFile(m_changeTmpFile->fileName());
+ if (editorFile.absoluteFilePath() != changeFile.absoluteFilePath())
+ return true; // Oops?!
+
+ // Prompt user.
+ const QMessageBox::StandardButton answer = QMessageBox::question(
+ m_coreInstance->mainWindow(), tr("Closing Subversion Editor"),
+ tr("Do you want to commit the change?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ switch (answer) {
+ case QMessageBox::Cancel:
+ return false; // Keep editing and change file
+ case QMessageBox::No:
+ cleanChangeTmpFile();
+ return true; // Cancel all
+ default:
+ break;
+ }
+
+ const QStringList fileList = editor->checkedFiles();
+ if (!fileList.empty()) {
+ // get message & commit
+ m_coreInstance->fileManager()->blockFileChange(fileIFace);
+ fileIFace->save();
+ m_coreInstance->fileManager()->unblockFileChange(fileIFace);
+ commit(m_changeTmpFile->fileName(), fileList);
+ }
+ cleanChangeTmpFile();
+ return true;
+}
+
+void SubversionPlugin::diffFiles(const QStringList &files)
+{
+ svnDiff(files);
+}
+
+void SubversionPlugin::svnDiff(const QStringList &files, QString diffname)
+{
+ if (Subversion::Constants::debug)
+ qDebug() << Q_FUNC_INFO << files << diffname;
+ const QString source = files.empty() ? QString() : files.front();
+ QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, source);
+
+ if (files.count() == 1 && diffname.isEmpty())
+ diffname = QFileInfo(files.front()).fileName();
+
+ QStringList args(QLatin1String("diff"));
+ args << files;
+
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, false, codec);
+ if (response.error)
+ return;
+
+ // diff of a single file? re-use an existing view if possible to support
+ // the common usage pattern of continuously changing and diffing a file
+ if (files.count() == 1) {
+ // Show in the same editor if diff has been executed before
+ if (Core::IEditor *editor = locateEditor(m_coreInstance, "originalFileName", files.front())) {
+ editor->createNew(response.stdOut);
+ m_coreInstance->editorManager()->setCurrentEditor(editor);
+ return;
+ }
+ }
+ const QString title = tr("svn diff %1").arg(diffname);
+ Core::IEditor *editor = showOutputInEditor(title, response.stdOut, VCSBase::DiffOutput, source, codec);
+ if (files.count() == 1)
+ editor->setProperty("originalFileName", files.front());
+}
+
+SubversionSubmitEditor *SubversionPlugin::openSubversionSubmitEditor(const QString &fileName)
+{
+ Core::IEditor *editor = m_coreInstance->editorManager()->openEditor(fileName, QLatin1String(Constants::SUBVERSIONCOMMITEDITOR_KIND));
+ SubversionSubmitEditor *submitEditor = qobject_cast<SubversionSubmitEditor*>(editor);
+ Q_ASSERT(submitEditor);
+ // The actions are for some reason enabled by the context switching
+ // mechanism. Disable them correctly.
+ m_submitDiffAction->setEnabled(false);
+ m_submitUndoAction->setEnabled(false);
+ m_submitRedoAction->setEnabled(false);
+ connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(diffFiles(QStringList)));
+
+ return submitEditor;
+}
+
+void SubversionPlugin::updateActions()
+{
+ QString fileName = currentFileName();
+ const bool hasFile = !fileName.isEmpty();
+
+ m_addAction->setEnabled(hasFile);
+ m_deleteAction->setEnabled(hasFile);
+ m_revertAction->setEnabled(hasFile);
+ m_diffProjectAction->setEnabled(true);
+ m_diffCurrentAction->setEnabled(hasFile);
+ m_commitAllAction->setEnabled(true);
+ m_commitCurrentAction->setEnabled(hasFile);
+ m_filelogCurrentAction->setEnabled(hasFile);
+ m_annotateCurrentAction->setEnabled(hasFile);
+ m_statusAction->setEnabled(true);
+
+ QString baseName;
+ if (hasFile)
+ baseName = QFileInfo(fileName).fileName();
+
+ m_addAction->setText(tr("Add %1").arg(baseName));
+ m_deleteAction->setText(tr("Delete %1").arg(baseName));
+ m_revertAction->setText(tr("Revert %1").arg(baseName));
+ m_diffCurrentAction->setText(tr("Diff %1").arg(baseName));
+ m_commitCurrentAction->setText(tr("Commit %1").arg(baseName));
+ m_filelogCurrentAction->setText(tr("Filelog %1").arg(baseName));
+ m_annotateCurrentAction->setText(tr("Annotate %1").arg(baseName));
+}
+
+void SubversionPlugin::addCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ vcsAdd(file);
+}
+
+void SubversionPlugin::deleteCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ vcsDelete(file);
+}
+
+void SubversionPlugin::revertCurrentFile()
+{
+ const QString file = QDir::toNativeSeparators(currentFileName());
+ if (file.isEmpty())
+ return;
+
+ QStringList args(QLatin1String("diff"));
+ args.push_back(file);
+
+ const SubversionResponse diffResponse = runSvn(args, subversionShortTimeOut, false);
+ if (diffResponse.error)
+ return;
+
+ if (diffResponse.stdOut.isEmpty())
+ return;
+ if (QMessageBox::warning(0, tr("svn revert"), tr("The file has been changed. Do you want to revert it?"),
+ QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
+ return;
+
+ Core::FileManager *fm = m_coreInstance->fileManager();
+ QList<Core::IFile *> files = fm->managedFiles(file);
+ foreach (Core::IFile *file, files) {
+ fm->blockFileChange(file);
+ }
+
+ // revert
+ args.clear();
+ args.push_back(QLatin1String("revert"));
+ args.append(file);
+
+ const SubversionResponse revertResponse = runSvn(args, subversionShortTimeOut, true);
+ if (revertResponse.error) {
+ foreach (Core::IFile *file, files)
+ fm->unblockFileChange(file);
+ return;
+ }
+
+ Core::IFile::ReloadBehavior tempBehavior = Core::IFile::ReloadAll;
+ foreach (Core::IFile *file, files) {
+ file->modified(&tempBehavior);
+ fm->unblockFileChange(file);
+ }
+}
+
+// Get a unique set of toplevel directories for the current projects.
+// To be used for "diff all" or "commit all".
+QStringList SubversionPlugin::currentProjectsTopLevels(QString *name) const
+{
+ typedef QList<ProjectExplorer::Project *> ProjectList;
+ ProjectList projects;
+ // Compile list of projects
+ if (ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject()) {
+ projects.push_back(currentProject);
+ } else {
+ if (const ProjectExplorer::SessionManager *session = m_projectExplorer->session())
+ projects.append(session->projects());
+ }
+ // Get unique set of toplevels and concat project names
+ QStringList toplevels;
+ const QChar blank(QLatin1Char(' '));
+ foreach (const ProjectExplorer::Project *p, projects) {
+ if (name) {
+ if (!name->isEmpty())
+ name->append(blank);
+ name->append(p->name());
+ }
+
+ const QString projectPath = QFileInfo(p->file()->fileName()).absolutePath();
+ const QString topLevel = findTopLevelForDirectory(projectPath);
+ if (!topLevel.isEmpty() && !toplevels.contains(topLevel))
+ toplevels.push_back(topLevel);
+ }
+ return toplevels;
+}
+
+void SubversionPlugin::diffProject()
+{
+ QString diffName;
+ const QStringList topLevels = currentProjectsTopLevels(&diffName);
+ if (!topLevels.isEmpty())
+ svnDiff(topLevels, diffName);
+}
+
+void SubversionPlugin::diffCurrentFile()
+{
+ svnDiff(QStringList(currentFileName()));
+}
+
+void SubversionPlugin::startCommitCurrentFile()
+{
+ const QString file = QDir::toNativeSeparators(currentFileName());
+ if (!file.isEmpty())
+ startCommit(QStringList(file));
+}
+
+void SubversionPlugin::startCommitAll()
+{
+ // Make sure we have only repository for commit
+ const QStringList files = currentProjectsTopLevels();
+ switch (files.size()) {
+ case 0:
+ break;
+ case 1:
+ startCommit(files);
+ break;
+ default: {
+ const QString msg = tr("The commit list spans several respositories (%1). Please commit them one by one.").
+ arg(files.join(QString(QLatin1Char(' '))));
+ QMessageBox::warning(0, tr("svn commit"), msg, QMessageBox::Ok);
+ }
+ break;
+ }
+}
+
+/* Start commit of files of a single repository by displaying
+ * template and files in a submit editor. On closing, the real
+ * commit will start. */
+void SubversionPlugin::startCommit(const QStringList &files)
+{
+ if (files.empty())
+ return;
+
+ if (m_changeTmpFile) {
+ showOutput(tr("Another commit is currently being executed."));
+ return;
+ }
+
+ QStringList args(QLatin1String("status"));
+ args += files;
+ if (args.size() == 1)
+ return;
+
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, false);
+ if (response.error)
+ return;
+ // Get list of added/modified/deleted files
+ const QStringList statusOutput = parseStatusOutput(response.stdOut);
+ if (statusOutput.empty()) {
+ showOutput(tr("There are no modified files."), true);
+ return;
+ }
+
+ // Create a new submit change file containing the submit template
+ QTemporaryFile *changeTmpFile = new QTemporaryFile(this);
+ changeTmpFile->setAutoRemove(true);
+ if (!changeTmpFile->open()) {
+ showOutput(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
+ delete changeTmpFile;
+ return;
+ }
+ m_changeTmpFile = changeTmpFile;
+ // TODO: Retrieve submit template from
+ const QString submitTemplate;
+ // Create a submit
+ m_changeTmpFile->write(submitTemplate.toUtf8());
+ m_changeTmpFile->flush();
+ m_changeTmpFile->seek(0);
+ // Create a submit editor and set file list
+ SubversionSubmitEditor *editor = openSubversionSubmitEditor(m_changeTmpFile->fileName());
+ editor->setFileList(statusOutput);
+}
+
+// Parse "status" output for added/modified/deleted files
+QStringList SubversionPlugin::parseStatusOutput(const QString &output) const
+{
+ QStringList changeSet;
+ const QString newLine = QString(QLatin1Char('\n'));
+ const QStringList list = output.split(newLine, QString::SkipEmptyParts);
+ foreach (const QString& l, list) {
+ QString line(l.trimmed());
+ if (line.startsWith(QLatin1Char('A')) || line.startsWith(QLatin1Char('D'))
+ || line.startsWith(QLatin1Char('M')))
+ changeSet.append(line);
+ }
+ return changeSet;
+}
+
+bool SubversionPlugin::commit(const QString &messageFile,
+ const QStringList &subVersionFileList)
+{
+ if (Subversion::Constants::debug)
+ qDebug() << Q_FUNC_INFO << messageFile << subVersionFileList;
+ // Transform the status list which is sth
+ // "[ADM]<blanks>file" into an args list. The files of the status log
+ // can be relative or absolute depending on where the command was run.
+ QStringList args = QStringList(QLatin1String("commit"));
+ args << QLatin1String("--non-interactive") << QLatin1String("--file") << messageFile;
+ args.append(subVersionFileList);
+ const SubversionResponse response = runSvn(args, subversionLongTimeOut, true);
+ return !response.error ;
+}
+
+void SubversionPlugin::filelogCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ filelog(file);
+}
+
+void SubversionPlugin::filelog(const QString &file)
+{
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, file);
+ // no need for temp file
+ QStringList args(QLatin1String("log"));
+ args.append(QDir::toNativeSeparators(file));
+
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, false, codec);
+ if (response.error)
+ return;
+
+ // Re-use an existing view if possible to support
+ // the common usage pattern of continuously changing and diffing a file
+
+ if (Core::IEditor *editor = locateEditor(m_coreInstance, "logFileName", file)) {
+ editor->createNew(response.stdOut);
+ m_coreInstance->editorManager()->setCurrentEditor(editor);
+ } else {
+ const QString title = tr("svn log %1").arg(QFileInfo(file).fileName());
+ Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::LogOutput, file, codec);
+ newEditor->setProperty("logFileName", file);
+ }
+}
+
+void SubversionPlugin::updateProject()
+{
+ const QStringList topLevels = currentProjectsTopLevels();
+ if (topLevels.empty())
+ return;
+
+ QStringList args(QLatin1String("update"));
+ args.append(topLevels);
+ runSvn(args, subversionLongTimeOut, false);
+}
+
+void SubversionPlugin::annotateCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ annotate(file);
+}
+
+void SubversionPlugin::annotate(const QString &file)
+{
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, file);
+
+ QStringList args(QLatin1String("annotate"));
+ args.push_back(QLatin1String("-v"));
+ args.append(QDir::toNativeSeparators(file));
+
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, false, codec);
+ if (response.error)
+ return;
+
+ // Re-use an existing view if possible to support
+ // the common usage pattern of continuously changing and diffing a file
+
+ if (Core::IEditor *editor = locateEditor(m_coreInstance, "annotateFileName", file)) {
+ editor->createNew(response.stdOut);
+ m_coreInstance->editorManager()->setCurrentEditor(editor);
+ } else {
+ const QString title = tr("svn annotate %1").arg(QFileInfo(file).fileName());
+ Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::AnnotateOutput, file, codec);
+ newEditor->setProperty("annotateFileName", file);
+ }
+}
+
+void SubversionPlugin::projectStatus()
+{
+ if (!m_projectExplorer)
+ return;
+
+ QStringList args(QLatin1String("status"));
+ args += currentProjectsTopLevels();
+
+ if (args.size() == 1)
+ return;
+
+ runSvn(args, subversionShortTimeOut, true);
+}
+
+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())
+ return;
+ if (Subversion::Constants::debug)
+ qDebug() << Q_FUNC_INFO << source << topLevel << changeNr;
+ // Number must be > 1
+ bool ok;
+ const int number = changeNr.toInt(&ok);
+ if (!ok || number < 2)
+ return;
+ QStringList args(QLatin1String("diff"));
+ args.push_back(QLatin1String("-r"));
+ QString diffArg;
+ QTextStream(&diffArg) << (number - 1) << ':' << number;
+ args.push_back(diffArg);
+ args.push_back(topLevel);
+
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, source);
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, false, codec);
+ if (response.error)
+ return;
+
+ // Re-use an existing view if possible to support
+ // the common usage pattern of continuously changing and diffing a file
+ const QString id = diffArg + source;
+ if (Core::IEditor *editor = locateEditor(m_coreInstance, "describeChange", id)) {
+ editor->createNew(response.stdOut);
+ m_coreInstance->editorManager()->setCurrentEditor(editor);
+ } else {
+ const QString title = tr("svn describe %1#%2").arg(QFileInfo(source).fileName(), changeNr);
+ Core::IEditor *newEditor = showOutputInEditor(title, response.stdOut, VCSBase::DiffOutput, source, codec);
+ newEditor->setProperty("describeChange", id);
+ }
+}
+
+void SubversionPlugin::submitCurrentLog()
+{
+ m_coreInstance->editorManager()->closeEditors(QList<Core::IEditor*>()
+ << m_coreInstance->editorManager()->currentEditor());
+}
+
+QString SubversionPlugin::currentFileName() const
+{
+ const QString fileName = m_coreInstance->fileManager()->currentFile();
+ if (!fileName.isEmpty()) {
+ const QFileInfo fi(fileName);
+ if (fi.exists())
+ return fi.canonicalFilePath();
+ }
+ return QString();
+}
+
+static inline QString processStdErr(QProcess &proc)
+{
+ return QString::fromLocal8Bit(proc.readAllStandardError()).remove(QLatin1Char('\r'));
+}
+
+static inline QString processStdOut(QProcess &proc, QTextCodec *outputCodec = 0)
+{
+ const QByteArray stdOutData = proc.readAllStandardOutput();
+ QString stdOut = outputCodec ? outputCodec->toUnicode(stdOutData) : QString::fromLocal8Bit(stdOutData);
+ return stdOut.remove(QLatin1Char('\r'));
+}
+
+SubversionResponse SubversionPlugin::runSvn(const QStringList &arguments,
+ int timeOut,
+ bool showStdOutInOutputWindow,
+ QTextCodec *outputCodec)
+{
+ const QString executable = m_settings.svnCommand;
+ SubversionResponse response;
+ if (executable.isEmpty()) {
+ response.error = true;
+ response.message =tr("No subversion executable specified!");
+ return response;
+ }
+ const QStringList allArgs = m_settings.addOptions(arguments);
+
+ // Hide passwords, etc in the log window
+ const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
+ const QString outputText = tr("%1 Executing: %2 %3\n").arg(timeStamp, executable, SubversionSettings::formatArguments(allArgs));
+ showOutput(outputText, false);
+
+ if (Subversion::Constants::debug)
+ qDebug() << "runSvn" << timeOut << outputText;
+
+ // Run, connect stderr to the output window
+ Core::Utils::SynchronousProcess process;
+ process.setTimeout(timeOut);
+ process.setStdOutCodec(outputCodec);
+
+ process.setStdErrBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_subversionOutputWindow, SLOT(append(QString,bool)));
+
+ // connect stdout to the output window if desired
+ if (showStdOutInOutputWindow) {
+ process.setStdOutBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_subversionOutputWindow, SLOT(append(QString,bool)));
+ }
+
+ const Core::Utils::SynchronousProcessResponse sp_resp = process.run(executable, allArgs);
+ response.error = true;
+ response.stdErr = sp_resp.stdErr;
+ response.stdOut = sp_resp.stdOut;
+ switch (sp_resp.result) {
+ case Core::Utils::SynchronousProcessResponse::Finished:
+ response.error = false;
+ break;
+ case Core::Utils::SynchronousProcessResponse::FinishedError:
+ response.message = tr("The process terminated with exit code %1.").arg(sp_resp.exitCode);
+ break;
+ case Core::Utils::SynchronousProcessResponse::TerminatedAbnormally:
+ response.message = tr("The process terminated abnormally.");
+ break;
+ case Core::Utils::SynchronousProcessResponse::StartFailed:
+ response.message = tr("Could not start subversion '%1'. Please check your settings in the preferences.").arg(executable);
+ break;
+ case Core::Utils::SynchronousProcessResponse::Hang:
+ response.message = tr("Subversion did not respond within timeout limit (%1 ms).").arg(timeOut);
+ break;
+ }
+ if (response.error)
+ m_subversionOutputWindow->append(response.message, true);
+
+ return response;
+}
+
+void SubversionPlugin::showOutput(const QString &output, bool bringToForeground)
+{
+ m_subversionOutputWindow->append(output);
+ if (bringToForeground)
+ m_subversionOutputWindow->popup();
+}
+
+Core::IEditor * SubversionPlugin::showOutputInEditor(const QString& title, const QString &output,
+ int editorType, const QString &source,
+ QTextCodec *codec)
+{
+ const VCSBase::VCSBaseEditorParameters *params = findType(editorType);
+ Q_ASSERT(params);
+ const QString kind = QLatin1String(params->kind);
+ if (Subversion::Constants::debug)
+ qDebug() << "SubversionPlugin::showOutputInEditor" << title << kind << "Size= " << output.size() << " Type=" << editorType << debugCodec(codec);
+ QString s = title;
+ Core::IEditor *ediface = m_coreInstance->editorManager()->newFile(kind, &s, output.toLocal8Bit());
+ SubversionEditor *e = qobject_cast<SubversionEditor*>(ediface->widget());
+ if (!e)
+ return 0;
+ s.replace(QLatin1Char(' '), QLatin1Char('_'));
+ e->setSuggestedFileName(s);
+ if (!source.isEmpty())
+ e->setSource(source);
+ if (codec)
+ e->setCodec(codec);
+ return e->editableInterface();
+}
+
+SubversionSettings SubversionPlugin::settings() const
+{
+ return m_settings;
+}
+
+void SubversionPlugin::setSettings(const SubversionSettings &s)
+{
+ if (s != m_settings) {
+ m_settings = s;
+ if (QSettings *settings = m_coreInstance->settings())
+ m_settings.toSettings(settings);
+ }
+}
+
+Core::ICore *SubversionPlugin::coreInstance()
+{
+ Q_ASSERT(m_coreInstance);
+ return m_coreInstance;
+}
+
+SubversionPlugin *SubversionPlugin::subversionPluginInstance()
+{
+ Q_ASSERT(m_subversionPluginInstance);
+ return m_subversionPluginInstance;
+}
+
+bool SubversionPlugin::vcsAdd(const QString &rawFileName)
+{
+ const QString file = QDir::toNativeSeparators(rawFileName);
+ QStringList args(QLatin1String("add"));
+ args.push_back(file);
+
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, true);
+ return !response.error;
+}
+
+bool SubversionPlugin::vcsDelete(const QString &rawFileName)
+{
+ const QString file = QDir::toNativeSeparators(rawFileName);
+
+ QStringList args(QLatin1String("delete"));
+ args.push_back(file);
+
+ const SubversionResponse response = runSvn(args, subversionShortTimeOut, true);
+ 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
+{
+ const QDir dir(directory);
+ const bool rc = dir.exists() && managesDirectory(dir);
+ if (Subversion::Constants::debug)
+ qDebug() << "SubversionPlugin::managesDirectory" << directory << rc;
+ return rc;
+}
+
+bool SubversionPlugin::managesDirectory(const QDir &directory) const
+{
+ const QString svnDir = directory.absoluteFilePath(m_svnDotDirectory);
+ return QFileInfo(svnDir).isDir();
+}
+
+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 QDir::toNativeSeparators(lastDirectory.absolutePath());
+ }
+ return QString();
+}
+
+Q_EXPORT_PLUGIN(SubversionPlugin)
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
new file mode 100644
index 0000000000..d01d0a05bb
--- /dev/null
+++ b/src/plugins/subversion/subversionplugin.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSIONPLUGIN_H
+#define SUBVERSIONPLUGIN_H
+
+#include "subversionsettings.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/icorelistener.h>
+#include <extensionsystem/iplugin.h>
+#include <coreplugin/icorelistener.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QDir;
+class QAction;
+class QTemporaryFile;
+class QTextCodec;
+QT_END_NAMESPACE
+
+namespace Core {
+ class ICore;
+ class IEditorFactory;
+ class IVersionControl;
+}
+
+namespace ProjectExplorer {
+ class ProjectExplorerPlugin;
+}
+
+namespace Subversion {
+namespace Internal {
+
+class CoreListener;
+class SettingsPage;
+class SubversionOutputWindow;
+class SubversionSubmitEditor;
+
+struct SubversionResponse
+{
+ SubversionResponse() : error(false) {}
+ bool error;
+ QString stdOut;
+ QString stdErr;
+ QString message;
+};
+
+class SubversionPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ SubversionPlugin();
+ ~SubversionPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ bool editorAboutToClose(Core::IEditor *editor);
+
+ void svnDiff(const QStringList &files, QString diffname = QString());
+
+ SubversionSubmitEditor *openSubversionSubmitEditor(const QString &fileName);
+
+ SubversionSettings settings() const;
+ void setSettings(const SubversionSettings &s);
+
+ // IVersionControl
+ bool vcsAdd(const QString &fileName);
+ bool vcsDelete(const QString &fileName);
+ bool managesDirectory(const QString &directory) const;
+ QString findTopLevelForDirectory(const QString &directory) const;
+
+ static Core::ICore *coreInstance();
+ static SubversionPlugin *subversionPluginInstance();
+
+private slots:
+ void updateActions();
+ void addCurrentFile();
+ void deleteCurrentFile();
+ void revertCurrentFile();
+ void diffProject();
+ void diffCurrentFile();
+ void startCommitAll();
+ void startCommitCurrentFile();
+ void filelogCurrentFile();
+ void annotateCurrentFile();
+ void projectStatus();
+ void describe(const QString &source, const QString &changeNr);
+ void updateProject();
+ void submitCurrentLog();
+ void diffFiles(const QStringList &);
+
+private:
+ QString currentFileName() const;
+ Core::IEditor * showOutputInEditor(const QString& title, const QString &output,
+ int editorType, const QString &source,
+ QTextCodec *codec);
+ SubversionResponse runSvn(const QStringList &arguments, int timeOut,
+ bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0);
+ void showOutput(const QString &output, bool bringToForeground = true);
+ QStringList parseStatusOutput(const QString &output) const;
+ void annotate(const QString &file);
+ void filelog(const QString &file);
+ bool managesDirectory(const QDir &directory) const;
+ QString findTopLevelForDirectoryI(const QString &directory) const;
+ QStringList currentProjectsTopLevels(QString *name = 0) const;
+ void startCommit(const QStringList &files);
+ bool commit(const QString &messageFile, const QStringList &subVersionFileList);
+ void cleanChangeTmpFile();
+
+ const QString m_svnDotDirectory;
+
+ SubversionSettings m_settings;
+ Core::IVersionControl *m_versionControl;
+ CoreListener *m_coreListener;
+ SettingsPage *m_settingsPage;
+ QTemporaryFile *m_changeTmpFile;
+
+ Core::IEditorFactory *m_submitEditorFactory;
+ QList<Core::IEditorFactory*> m_editorFactories;
+
+ SubversionOutputWindow *m_subversionOutputWindow;
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+
+ QAction *m_addAction;
+ QAction *m_deleteAction;
+ QAction *m_revertAction;
+ QAction *m_diffProjectAction;
+ QAction *m_diffCurrentAction;
+ QAction *m_commitAllAction;
+ QAction *m_commitCurrentAction;
+ QAction *m_filelogCurrentAction;
+ QAction *m_annotateCurrentAction;
+ QAction *m_statusAction;
+ QAction *m_updateProjectAction;
+
+ QAction *m_submitCurrentLogAction;
+ QAction *m_submitDiffAction;
+ QAction *m_submitUndoAction;
+ QAction *m_submitRedoAction;
+
+ static const char * const SUBVERSION_MENU;
+ static const char * const ADD;
+ static const char * const DELETE_FILE;
+ static const char * const REVERT;
+ static const char * const SEPARATOR0;
+ static const char * const DIFF_PROJECT;
+ static const char * const DIFF_CURRENT;
+ static const char * const SEPARATOR1;
+ static const char * const COMMIT_ALL;
+ static const char * const COMMIT_CURRENT;
+ static const char * const SEPARATOR2;
+ static const char * const FILELOG_CURRENT;
+ static const char * const ANNOTATE_CURRENT;
+ static const char * const SEPARATOR3;
+ static const char * const STATUS;
+ static const char * const UPDATE;
+
+ static Core::ICore *m_coreInstance;
+ static SubversionPlugin *m_subversionPluginInstance;
+
+ friend class SubversionOutputWindow;
+};
+
+// Just a proxy for SubversionPlugin
+class CoreListener : public Core::ICoreListener
+{
+ Q_OBJECT
+public:
+ CoreListener(SubversionPlugin *plugin) : m_plugin(plugin) { }
+
+ // Start commit when submit editor closes
+ bool editorAboutToClose(Core::IEditor *editor) {
+ return m_plugin->editorAboutToClose(editor);
+ }
+
+ // TODO: how to handle that ???
+ bool coreAboutToClose() {
+ return true;
+ }
+
+private:
+ SubversionPlugin *m_plugin;
+};
+
+} // namespace Subversion
+} // namespace Internal
+
+#endif // SUBVERSIONPLUGIN_H
diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp
new file mode 100644
index 0000000000..ca4a946c7c
--- /dev/null
+++ b/src/plugins/subversion/subversionsettings.cpp
@@ -0,0 +1,133 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "subversionsettings.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QTextStream>
+
+static const char *groupC = "Subversion";
+static const char *commandKeyC = "Command";
+static const char *userKeyC = "User";
+static const char *passwordKeyC = "Password";
+static const char *authenticationKeyC = "Authentication";
+
+static const char *userNameOptionC = "--username";
+static const char *passwordOptionC = "--password";
+
+static QString defaultCommand()
+{
+ QString rc;
+ rc = QLatin1String("svn");
+#if defined(Q_OS_WIN32)
+ rc.append(QLatin1String(".exe"));
+#endif
+ return rc;
+}
+
+namespace Subversion {
+namespace Internal {
+
+SubversionSettings::SubversionSettings() :
+ svnCommand(defaultCommand()),
+ useAuthentication(false)
+{
+}
+
+void SubversionSettings::fromSettings(QSettings *settings)
+{
+ settings->beginGroup(QLatin1String(groupC));
+ svnCommand = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString();
+ useAuthentication = settings->value(QLatin1String(authenticationKeyC), QVariant(false)).toBool();
+ user = settings->value(QLatin1String(userKeyC), QString()).toString();
+ password = settings->value(QLatin1String(passwordKeyC), QString()).toString();
+ settings->endGroup();
+}
+
+void SubversionSettings::toSettings(QSettings *settings) const
+{
+ settings->beginGroup(QLatin1String(groupC));
+ settings->setValue(QLatin1String(commandKeyC), svnCommand);
+ settings->setValue(QLatin1String(authenticationKeyC), QVariant(useAuthentication));
+ settings->setValue(QLatin1String(userKeyC), user);
+ settings->setValue(QLatin1String(passwordKeyC), password);
+ settings->endGroup();
+}
+
+bool SubversionSettings::equals(const SubversionSettings &s) const
+{
+ return svnCommand == s.svnCommand
+ && useAuthentication == s.useAuthentication
+ && user == s.user
+ && password == s.password;
+}
+
+QStringList SubversionSettings::addOptions(const QStringList &args) const
+{
+ if (!useAuthentication || user.isEmpty())
+ return args;
+
+ QStringList rc;
+ rc.push_back(QLatin1String(userNameOptionC));
+ rc.push_back(user);
+ if (!password.isEmpty()) {
+ rc.push_back(QLatin1String(passwordOptionC));
+ rc.push_back(password);
+ }
+ rc.append(args);
+ return rc;
+}
+
+// Format arguments for log windows hiding passwords, etc.
+QString SubversionSettings::formatArguments(const QStringList &args)
+{
+ QString rc;
+ QTextStream str(&rc);
+ const int size = args.size();
+ // Skip authentication options
+ for (int i = 0; i < size; i++) {
+ const QString &arg = args.at(i);
+ if (i)
+ str << ' ';
+ str << arg;
+ if (arg == QLatin1String(userNameOptionC) || arg == QLatin1String(passwordOptionC)) {
+ str << " ********";
+ i++;
+ }
+ }
+ return rc;
+}
+
+
+}
+}
+
diff --git a/src/plugins/subversion/subversionsettings.h b/src/plugins/subversion/subversionsettings.h
new file mode 100644
index 0000000000..32c0c301ff
--- /dev/null
+++ b/src/plugins/subversion/subversionsettings.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSIONSETTINGS_H
+#define SUBVERSIONSETTINGS_H
+
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Subversion {
+namespace Internal {
+
+// Todo: Add user name and password?
+struct SubversionSettings {
+ SubversionSettings();
+
+ void fromSettings(QSettings *);
+ void toSettings(QSettings *) const;
+
+ // Add authentication and (maybe future) options to the
+ // command line
+ QStringList addOptions(const QStringList &args) const;
+ // Format arguments for log windows hiding passwords, etc.
+ static QString formatArguments(const QStringList &args);
+
+ bool equals(const SubversionSettings &s) const;
+
+ QString svnCommand;
+ bool useAuthentication;
+ QString user;
+ QString password;
+};
+
+inline bool operator==(const SubversionSettings &p1, const SubversionSettings &p2)
+ { return p1.equals(p2); }
+inline bool operator!=(const SubversionSettings &p1, const SubversionSettings &p2)
+ { return !p1.equals(p2); }
+}
+}
+
+#endif
diff --git a/src/plugins/subversion/subversionsubmiteditor.cpp b/src/plugins/subversion/subversionsubmiteditor.cpp
new file mode 100644
index 0000000000..1301041378
--- /dev/null
+++ b/src/plugins/subversion/subversionsubmiteditor.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "subversionsubmiteditor.h"
+
+#include <utils/submiteditorwidget.h>
+
+namespace Subversion {
+namespace Internal {
+
+SubversionSubmitEditor::SubversionSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters,
+ QWidget *parentWidget) :
+ VCSBase::VCSBaseSubmitEditor(parameters, new Core::Utils::SubmitEditorWidget(parentWidget))
+{
+ setDisplayName(tr("Subversion Submit"));
+}
+
+QStringList SubversionSubmitEditor::vcsFileListToFileList(const QStringList &rl) const
+{
+ QStringList files;
+ const QStringList::const_iterator cend = rl.constEnd();
+ for (QStringList::const_iterator it = rl.constBegin(); it != cend; ++it)
+ files.push_back(SubversionSubmitEditor::fileFromStatusLine(*it));
+ return files;
+}
+
+QString SubversionSubmitEditor::fileFromStatusLine(const QString &statusLine)
+{
+ enum { filePos = 7 };
+ return statusLine.mid(filePos, statusLine.size() - filePos);
+}
+
+}
+}
diff --git a/src/plugins/subversion/subversionsubmiteditor.h b/src/plugins/subversion/subversionsubmiteditor.h
new file mode 100644
index 0000000000..3ba3335e49
--- /dev/null
+++ b/src/plugins/subversion/subversionsubmiteditor.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBVERSIONSUBMITEDITOR_H
+#define SUBVERSIONSUBMITEDITOR_H
+
+#include <vcsbase/vcsbasesubmiteditor.h>
+
+namespace Subversion {
+namespace Internal {
+
+class SubversionSubmitEditor : public VCSBase::VCSBaseSubmitEditor
+{
+ Q_OBJECT
+public:
+ SubversionSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters,
+ QWidget *parentWidget = 0);
+
+ static QString fileFromStatusLine(const QString &statusLine);
+
+private:
+ virtual QStringList vcsFileListToFileList(const QStringList &) const;
+};
+
+} // namespace Internal
+} // namespace Subversion
+
+#endif // SUBVERSIONSUBMITEDITOR_H
diff --git a/src/plugins/texteditor/TextEditor.mimetypes.xml b/src/plugins/texteditor/TextEditor.mimetypes.xml
new file mode 100644
index 0000000000..e78754da68
--- /dev/null
+++ b/src/plugins/texteditor/TextEditor.mimetypes.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="text/plain">
+ <comment>Plain text document</comment>
+ <sub-class-of type="application/octet-stream"/>
+ <comment xml:lang="bg">Документ Ñ Ð½ÐµÑ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð°Ð½ текÑÑ‚</comment>
+ <comment xml:lang="ca">document de text pla</comment>
+ <comment xml:lang="cs">Prostý textový dokument</comment>
+ <comment xml:lang="da">ren tekst-dokument</comment>
+ <comment xml:lang="de">einfaches Textdokument</comment>
+ <comment xml:lang="el">έγγÏαφο Î±Ï€Î»Î¿Ï ÎºÎµÎ¹Î¼Î­Î½Î¿Ï…</comment>
+ <comment xml:lang="eo">plata teksta dokumento</comment>
+ <comment xml:lang="es">documento de texto sencillo</comment>
+ <comment xml:lang="eu">testu soileko dokumentua</comment>
+ <comment xml:lang="fi">perustekstiasiakirja</comment>
+ <comment xml:lang="fr">document plein texte</comment>
+ <comment xml:lang="hu">egyszerű szöveg</comment>
+ <comment xml:lang="it">Documento in testo semplice</comment>
+ <comment xml:lang="ja">平文テキストドキュメント</comment>
+ <comment xml:lang="ko">보통 text 문서</comment>
+ <comment xml:lang="lt">paprastas tekstinis dokumentas</comment>
+ <comment xml:lang="ms">Dokumen teks jernih</comment>
+ <comment xml:lang="nb">vanlig tekstdokument</comment>
+ <comment xml:lang="nl">platte tekst document</comment>
+ <comment xml:lang="nn">vanleg tekstdokument</comment>
+ <comment xml:lang="pl">zwykły dokument tekstowy</comment>
+ <comment xml:lang="pt">documento em texto simples</comment>
+ <comment xml:lang="pt_BR">Documento somente texto</comment>
+ <comment xml:lang="sq">dokument teksti i thjeshtë</comment>
+ <comment xml:lang="sr">обичан текÑтуални документ</comment>
+ <comment xml:lang="sv">vanligt textdokument</comment>
+ <comment xml:lang="uk">звичайний текÑтовий документ</comment>
+ <comment xml:lang="vi">thư nhập thô (văn bản không có kiểu dáng)</comment>
+ <comment xml:lang="zh_CN">纯文本文档</comment>
+ <comment xml:lang="zh_TW">普通文本檔</comment>
+ <glob pattern="*.txt"/>
+ </mime-type>
+ <mime-type type="application/xml">
+ <sub-class-of type="text/plain"/>
+ <comment>XML document</comment>
+ <glob pattern="*.xml"/>
+ <glob pattern="*.xsl"/>
+ <glob pattern="*.xslt"/>
+ <glob pattern="*.xbl"/>
+ <alias type="text/xml"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/texteditor/TextEditor.pluginspec b/src/plugins/texteditor/TextEditor.pluginspec
new file mode 100644
index 0000000000..aaad622ea4
--- /dev/null
+++ b/src/plugins/texteditor/TextEditor.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="TextEditor" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Text editor framework and the implementation of the basic text editor.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="Find" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp
new file mode 100644
index 0000000000..4c11a626db
--- /dev/null
+++ b/src/plugins/texteditor/basefilefind.cpp
@@ -0,0 +1,233 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basefilefind.h"
+
+#include <coreplugin/stylehelper.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <find/textfindconstants.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtDebug>
+#include <QtCore/QDirIterator>
+#include <QtGui/QPushButton>
+#include <QtGui/QFileDialog>
+
+using namespace Core::Utils;
+using namespace Find;
+using namespace TextEditor;
+
+BaseFileFind::BaseFileFind(Core::ICore *core, SearchResultWindow *resultWindow)
+ : m_core(core),
+ m_resultWindow(resultWindow),
+ m_isSearching(false),
+ m_resultLabel(0),
+ m_filterCombo(0),
+ m_useRegExp(false),
+ m_useRegExpCheckBox(0)
+{
+ m_watcher.setPendingResultsLimit(1);
+ connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
+ connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
+}
+
+bool BaseFileFind::isEnabled() const
+{
+ return !m_isSearching;
+}
+
+QStringList BaseFileFind::fileNameFilters() const
+{
+ QStringList filters;
+ if (m_filterCombo && !m_filterCombo->currentText().isEmpty()) {
+ QStringList parts = m_filterCombo->currentText().split(",");
+ foreach (const QString &part, parts) {
+ QString filter = part.trimmed();
+ if (!filter.isEmpty()) {
+ filters << filter;
+ }
+ }
+ }
+ return filters;
+}
+
+void BaseFileFind::findAll(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ m_isSearching = true;
+ emit changed();
+ updateComboEntries(m_filterCombo, false);
+ m_watcher.setFuture(QFuture<FileSearchResult>());
+ m_resultWindow->clearContents();
+ m_resultWindow->popup(true);
+ if (m_useRegExp)
+ m_watcher.setFuture(Core::Utils::findInFilesRegExp(txt, files(), findFlags));
+ else
+ m_watcher.setFuture(Core::Utils::findInFiles(txt, files(), findFlags));
+ Core::FutureProgress *progress = m_core->progressManager()->addTask(m_watcher.future(),
+ "Search",
+ Constants::TASK_SEARCH);
+ progress->setWidget(createProgressWidget());
+ connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
+}
+
+void BaseFileFind::displayResult(int index) {
+ Core::Utils::FileSearchResult result = m_watcher.future().resultAt(index);
+ ResultWindowItem *item = m_resultWindow->addResult(result.fileName,
+ result.lineNumber,
+ result.matchingLine,
+ result.matchStart,
+ result.matchLength);
+ if (item)
+ connect(item, SIGNAL(activated(const QString&,int,int)), this, SLOT(openEditor(const QString&,int,int)));
+
+ if (m_resultLabel)
+ m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
+}
+
+void BaseFileFind::searchFinished()
+{
+ m_isSearching = false;
+ m_resultLabel = 0;
+ emit changed();
+}
+
+QWidget *BaseFileFind::createProgressWidget()
+{
+ m_resultLabel = new QLabel;
+ // ### TODO this setup should be done by style
+ QFont f = m_resultLabel->font();
+ f.setBold(true);
+ f.setPointSizeF(StyleHelper::sidebarFontSize());
+ m_resultLabel->setFont(f);
+ m_resultLabel->setPalette(StyleHelper::sidebarFontPalette(m_resultLabel->palette()));
+ m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
+ return m_resultLabel;
+}
+
+QWidget *BaseFileFind::createPatternWidget()
+{
+/*
+ QWidget *widget = new QWidget;
+ QHBoxLayout *hlayout = new QHBoxLayout(widget);
+ hlayout->setMargin(0);
+ widget->setLayout(hlayout);
+*/
+ QString filterToolTip = tr("List of comma separated wildcard filters");
+/*
+ QLabel *label = new QLabel(tr("File pattern:"));
+ label->setToolTip(filterToolTip);
+*/
+/*
+ hlayout->addWidget(label);
+*/
+ m_filterCombo = new QComboBox;
+ m_filterCombo->setEditable(true);
+ m_filterCombo->setModel(&m_filterStrings);
+ m_filterCombo->setMaxCount(10);
+ m_filterCombo->setMinimumContentsLength(10);
+ m_filterCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
+ m_filterCombo->setInsertPolicy(QComboBox::InsertAtBottom);
+ m_filterCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_filterCombo->setToolTip(filterToolTip);
+ syncComboWithSettings(m_filterCombo, m_filterSetting);
+/*
+ hlayout->addWidget(m_filterCombo);
+*/
+ return m_filterCombo;
+}
+
+QWidget *BaseFileFind::createRegExpWidget()
+{
+ m_useRegExpCheckBox = new QCheckBox(tr("Use Regular Expressions"));
+ m_useRegExpCheckBox->setChecked(m_useRegExp);
+ connect(m_useRegExpCheckBox, SIGNAL(toggled(bool)), this, SLOT(syncRegExpSetting(bool)));
+ return m_useRegExpCheckBox;
+}
+
+void BaseFileFind::writeCommonSettings(QSettings *settings)
+{
+ settings->setValue("filters", m_filterStrings.stringList());
+ if (m_filterCombo)
+ settings->setValue("currentFilter", m_filterCombo->currentText());
+ settings->setValue("useRegExp", m_useRegExp);
+}
+
+void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter)
+{
+ QStringList filters = settings->value("filters").toStringList();
+ m_filterSetting = settings->value("currentFilter").toString();
+ m_useRegExp = settings->value("useRegExp", false).toBool();
+ if (m_useRegExpCheckBox)
+ m_useRegExpCheckBox->setChecked(m_useRegExp);
+ if (filters.isEmpty())
+ filters << defaultFilter;
+ if (m_filterSetting.isEmpty())
+ m_filterSetting = filters.first();
+ m_filterStrings.setStringList(filters);
+ syncComboWithSettings(m_filterCombo, m_filterSetting);
+}
+
+void BaseFileFind::syncComboWithSettings(QComboBox *combo, const QString &setting)
+{
+ if (!combo)
+ return;
+ int index = combo->findText(setting);
+ if (index < 0)
+ combo->setEditText(setting);
+ else
+ combo->setCurrentIndex(index);
+}
+
+void BaseFileFind::updateComboEntries(QComboBox *combo, bool onTop)
+{
+ int index = combo->findText(combo->currentText());
+ if (index < 0) {
+ if (onTop) {
+ combo->insertItem(0, combo->currentText());
+ } else {
+ combo->addItem(combo->currentText());
+ }
+ combo->setCurrentIndex(combo->findText(combo->currentText()));
+ }
+}
+
+void BaseFileFind::syncRegExpSetting(bool useRegExp)
+{
+ m_useRegExp = useRegExp;
+}
+
+void BaseFileFind::openEditor(const QString &fileName, int line, int column)
+{
+ TextEditor::BaseTextEditor::openEditorAt(fileName, line, column);
+}
diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h
new file mode 100644
index 0000000000..562a4487cc
--- /dev/null
+++ b/src/plugins/texteditor/basefilefind.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEFILEFIND_H
+#define BASEFILEFIND_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/icore.h>
+#include <find/ifindfilter.h>
+#include <find/searchresultwindow.h>
+#include <utils/filesearch.h>
+
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QPointer>
+#include <QtGui/QLabel>
+#include <QtGui/QComboBox>
+#include <QtGui/QStringListModel>
+#include <QtGui/QCheckBox>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT BaseFileFind : public Find::IFindFilter
+{
+ Q_OBJECT
+
+public:
+ BaseFileFind(Core::ICore *core, Find::SearchResultWindow *resultWindow);
+
+ bool isEnabled() const;
+ void findAll(const QString &txt, QTextDocument::FindFlags findFlags);
+
+protected:
+ virtual QStringList files() = 0;
+ void writeCommonSettings(QSettings *settings);
+ void readCommonSettings(QSettings *settings, const QString &defaultFilter);
+ QWidget *createPatternWidget();
+ QWidget *createRegExpWidget();
+ void syncComboWithSettings(QComboBox *combo, const QString &setting);
+ void updateComboEntries(QComboBox *combo, bool onTop);
+ QStringList fileNameFilters() const;
+
+private slots:
+ void displayResult(int index);
+ void searchFinished();
+ void openEditor(const QString &fileName, int line, int column);
+ void syncRegExpSetting(bool useRegExp);
+
+private:
+ QWidget *createProgressWidget();
+
+ Core::ICore *m_core;
+ Find::SearchResultWindow *m_resultWindow;
+ QFutureWatcher<Core::Utils::FileSearchResult> m_watcher;
+ bool m_isSearching;
+ QLabel *m_resultLabel;
+ QStringListModel m_filterStrings;
+ QString m_filterSetting;
+ QPointer<QComboBox> m_filterCombo;
+ bool m_useRegExp;
+ QCheckBox *m_useRegExpCheckBox;
+};
+
+} // namespace TextEditor
+
+#endif // BASEFILEFIND_H
diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp
new file mode 100644
index 0000000000..916bc11f2f
--- /dev/null
+++ b/src/plugins/texteditor/basetextdocument.cpp
@@ -0,0 +1,349 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basetextdocument.h"
+#include "basetexteditor.h"
+#include "storagesettings.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QTextCodec>
+#include <QtGui/QMainWindow>
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QApplication>
+
+#ifndef TEXTEDITOR_STANDALONE
+#include <utils/reloadpromptutils.h>
+#include "coreplugin/icore.h"
+#endif
+
+using namespace TextEditor;
+
+#if defined (Q_OS_WIN)
+# define NATIVE_LINE_TERMINATOR CRLFLineTerminator
+#else
+# define NATIVE_LINE_TERMINATOR LFLineTerminator
+#endif
+
+DocumentMarker::DocumentMarker(QTextDocument *doc)
+ : ITextMarkable(doc), document(doc)
+{
+}
+
+BaseTextDocument::BaseTextDocument()
+ : m_document(new QTextDocument(this)),
+ m_highlighter(0)
+{
+ m_documentMarker = new DocumentMarker(m_document);
+ m_lineTerminatorMode = NativeLineTerminator;
+ m_isBinaryData = false;
+ m_codec = QTextCodec::codecForLocale();
+ m_hasDecodingError = false;
+}
+
+BaseTextDocument::~BaseTextDocument()
+{
+ QTextBlock block = m_document->begin();
+ while (block.isValid()) {
+ if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData()))
+ data->documentClosing();
+ block = block.next();
+ }
+ delete m_document;
+ m_document = 0;
+}
+
+QString BaseTextDocument::mimeType() const
+{
+ return m_mimeType;
+}
+
+void BaseTextDocument::setMimeType(const QString &mt)
+{
+ m_mimeType = mt;
+}
+
+bool BaseTextDocument::save(const QString &fileName)
+{
+ QTextCursor cursor(m_document);
+
+ cursor.beginEditBlock();
+ if (m_storageSettings.m_cleanWhitespace)
+ cleanWhitespace(cursor, m_storageSettings.m_inEntireDocument);
+ if (m_storageSettings.m_addFinalNewLine)
+ ensureFinalNewLine(cursor);
+ cursor.endEditBlock();
+
+ QString fName = m_fileName;
+ if (!fileName.isEmpty())
+ fName = fileName;
+
+ QFile file(fName);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
+ return false;
+
+ QString plainText = m_document->toPlainText();
+
+ if (m_lineTerminatorMode == CRLFLineTerminator)
+ plainText.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
+
+ file.write(m_codec->fromUnicode(plainText));
+ if (!file.flush())
+ return false;
+ file.close();
+
+ const QFileInfo fi(fName);
+ m_fileName = fi.absoluteFilePath();
+
+ m_document->setModified(false);
+ emit titleChanged(fi.fileName());
+ emit changed();
+
+ m_isBinaryData = false;
+ m_hasDecodingError = false;
+ m_decodingErrorSample.clear();
+
+ return true;
+}
+
+bool BaseTextDocument::isReadOnly() const
+{
+ if (m_isBinaryData || m_hasDecodingError)
+ return true;
+ if (m_fileName.isEmpty()) //have no corresponding file, so editing is ok
+ return false;
+ const QFileInfo fi(m_fileName);
+ return !fi.isWritable();
+}
+
+bool BaseTextDocument::isModified() const
+{
+ return m_document->isModified();
+}
+
+bool BaseTextDocument::open(const QString &fileName)
+{
+ QString title = tr("untitled");
+ if (!fileName.isEmpty()) {
+ const QFileInfo fi(fileName);
+ m_fileName = fi.absoluteFilePath();
+
+ QFile file(fileName);
+ if (!file.exists())
+ return false;
+
+ if (!fi.isReadable())
+ return false;
+
+ if (!fi.isWritable()) {
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+ } else {
+ if (!file.open(QIODevice::ReadWrite))
+ return false;
+ }
+ title = fi.fileName();
+
+ QByteArray buf = file.readAll();
+ int bytesRead = buf.size();
+
+ QTextCodec *codec = m_codec;
+
+ // code taken from qtextstream
+ if (bytesRead >= 4 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe && uchar(buf[2]) == 0 && uchar(buf[3]) == 0)
+ || (uchar(buf[0]) == 0 && uchar(buf[1]) == 0 && uchar(buf[2]) == 0xfe && uchar(buf[3]) == 0xff))) {
+ codec = QTextCodec::codecForName("UTF-32");
+ } else if (bytesRead >= 2 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe)
+ || (uchar(buf[0]) == 0xfe && uchar(buf[1]) == 0xff))) {
+ codec = QTextCodec::codecForName("UTF-16");
+ } else if (!codec) {
+ codec = QTextCodec::codecForLocale();
+ }
+ // end code taken from qtextstream
+
+ m_codec = codec;
+
+#if 0 // should work, but does not, Qt bug with "system" codec
+ QTextDecoder *decoder = m_codec->makeDecoder();
+ QString text = decoder->toUnicode(buf);
+ m_hasDecodingError = (decoder->hasFailure());
+ delete decoder;
+#else
+ QString text = m_codec->toUnicode(buf);
+ QByteArray verifyBuf = m_codec->fromUnicode(text); // slow
+ // the minSize trick lets us ignore unicode headers
+ int minSize = qMin(verifyBuf.size(), buf.size());
+ m_hasDecodingError = (minSize < buf.size()- 4
+ || memcmp(verifyBuf.constData() + verifyBuf.size() - minSize,
+ buf.constData() + buf.size() - minSize, minSize));
+#endif
+
+ if (m_hasDecodingError) {
+ int p = buf.indexOf('\n', 16384);
+ if (p < 0)
+ m_decodingErrorSample = buf;
+ else
+ m_decodingErrorSample = buf.left(p);
+ } else {
+ m_decodingErrorSample.clear();
+ }
+
+ int lf = text.indexOf('\n');
+ if (lf > 0 && text.at(lf-1) == QLatin1Char('\r')) {
+ m_lineTerminatorMode = CRLFLineTerminator;
+ } else if (lf >= 0) {
+ m_lineTerminatorMode = LFLineTerminator;
+ } else {
+ m_lineTerminatorMode = NativeLineTerminator;
+ }
+
+ m_document->setModified(false);
+ m_document->setUndoRedoEnabled(false);
+ if (m_isBinaryData)
+ m_document->setHtml(tr("<em>Binary data</em>"));
+ else
+ m_document->setPlainText(text);
+ m_document->setUndoRedoEnabled(true);
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(m_document->documentLayout());
+ Q_ASSERT(documentLayout);
+ documentLayout->lastSaveRevision = 0;
+ m_document->setModified(false);
+ emit titleChanged(title);
+ emit changed();
+ }
+ return true;
+}
+
+void BaseTextDocument::reload(QTextCodec *codec)
+{
+ Q_ASSERT(codec);
+ m_codec = codec;
+ reload();
+}
+
+void BaseTextDocument::reload()
+{
+ emit aboutToReload();
+ if (open(m_fileName)) {
+ emit reloaded();
+ }
+}
+
+void BaseTextDocument::modified(Core::IFile::ReloadBehavior *behavior)
+{
+ switch (*behavior) {
+ case Core::IFile::ReloadNone:
+ return;
+ case Core::IFile::ReloadAll:
+ reload();
+ return;
+ case Core::IFile::ReloadPermissions:
+ emit changed();
+ return;
+ case Core::IFile::AskForReload:
+ break;
+ }
+
+#ifndef TEXTEDITOR_STANDALONE
+ switch (Core::Utils::reloadPrompt(m_fileName, QApplication::activeWindow())) {
+ case Core::Utils::ReloadCurrent:
+ reload();
+ break;
+ case Core::Utils::ReloadAll:
+ reload();
+ *behavior = Core::IFile::ReloadAll;
+ break;
+ case Core::Utils::ReloadSkipCurrent:
+ break;
+ case Core::Utils::ReloadNone:
+ *behavior = Core::IFile::ReloadNone;
+ break;
+ }
+#endif
+}
+
+void BaseTextDocument::setSyntaxHighlighter(QSyntaxHighlighter *highlighter)
+{
+ if (m_highlighter)
+ delete m_highlighter;
+ m_highlighter = highlighter;
+ m_highlighter->setParent(this);
+ m_highlighter->setDocument(m_document);
+}
+
+void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool inEntireDocument)
+{
+
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(m_document->documentLayout());
+
+ QTextBlock block = m_document->firstBlock();
+ while (block.isValid()) {
+
+ if (inEntireDocument || block.revision() > documentLayout->lastSaveRevision) {
+
+ QString blockText = block.text();
+ if (int trailing = m_tabSettings.trailingWhitespaces(blockText)) {
+ cursor.setPosition(block.position() + block.length() - 1);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, trailing);
+ cursor.removeSelectedText();
+ }
+ if (!m_tabSettings.isIndentationClean(blockText)) {
+ cursor.setPosition(block.position());
+ int firstNonSpace = m_tabSettings.firstNonSpace(blockText);
+ if (firstNonSpace == blockText.length()) {
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ } else {
+ int column = m_tabSettings.columnAt(blockText, firstNonSpace);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace);
+ QString indentationString = m_tabSettings.indentationString(0, column);
+ cursor.insertText(indentationString);
+ }
+ }
+ }
+
+ block = block.next();
+ }
+}
+
+void BaseTextDocument::ensureFinalNewLine(QTextCursor& cursor)
+{
+ cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
+ bool emptyFile = !cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+
+ if (!emptyFile && cursor.selectedText().at(0) != QChar::ParagraphSeparator)
+ {
+ cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
+ cursor.insertText(QLatin1String("\n"));
+ }
+}
diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h
new file mode 100644
index 0000000000..8dbfda2ea8
--- /dev/null
+++ b/src/plugins/texteditor/basetextdocument.h
@@ -0,0 +1,161 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTDOCUMENT_H
+#define BASETEXTDOCUMENT_H
+
+#include "texteditor_global.h"
+#include "storagesettings.h"
+#include "itexteditor.h"
+#include "tabsettings.h"
+
+QT_BEGIN_NAMESPACE
+class QTextCursor;
+class QTextDocument;
+class QSyntaxHighlighter;
+QT_END_NAMESPACE
+
+
+namespace Core { class ICore; }
+
+namespace TextEditor {
+
+
+class DocumentMarker : public ITextMarkable
+{
+ Q_OBJECT
+public:
+ DocumentMarker(QTextDocument *);
+
+ // ITextMarkable
+ bool addMark(ITextMark *mark, int line);
+ TextMarks marksAt(int line) const;
+ void removeMark(ITextMark *mark);
+ bool hasMark(ITextMark *mark) const;
+ void updateMark(ITextMark *mark);
+
+private:
+ QTextDocument *document;
+};
+
+
+
+class TEXTEDITOR_EXPORT BaseTextDocument
+ : public Core::IFile
+{
+ Q_OBJECT
+
+public:
+ BaseTextDocument();
+ ~BaseTextDocument();
+ void setStorageSettings(const StorageSettings &storageSettings) { m_storageSettings = storageSettings; }
+ void setTabSettings(const TabSettings &tabSettings) { m_tabSettings = tabSettings; }
+
+ inline const StorageSettings &storageSettings() const { return m_storageSettings; }
+ inline const TabSettings &tabSettings() const { return m_tabSettings; }
+
+ DocumentMarker *documentMarker() const {return m_documentMarker; }
+
+ //IFile
+ virtual bool save(const QString &fileName = QString());
+ virtual QString fileName() const { return m_fileName; }
+ virtual bool isReadOnly() const;
+ virtual bool isModified() const;
+ virtual bool isSaveAsAllowed() const { return true; }
+ virtual void modified(Core::IFile::ReloadBehavior *behavior);
+ virtual QString mimeType() const;
+ void setMimeType(const QString &mt);
+
+ virtual QString defaultPath() const { return m_defaultPath; }
+ virtual QString suggestedFileName() const { return m_suggestedFileName; }
+
+ void setDefaultPath(const QString &defaultPath) { m_defaultPath = defaultPath; }
+ void setSuggestedFileName(const QString &suggestedFileName) { m_suggestedFileName = suggestedFileName; }
+
+ virtual bool open(const QString &fileName = QString());
+ virtual void reload();
+
+ QTextDocument *document() const { return m_document; }
+ void setSyntaxHighlighter(QSyntaxHighlighter *highlighter);
+ QSyntaxHighlighter *syntaxHighlighter() const { return m_highlighter; }
+
+
+ inline bool isBinaryData() const { return m_isBinaryData; }
+ inline bool hasDecodingError() const { return m_hasDecodingError || m_isBinaryData; }
+ inline QTextCodec *codec() const { return m_codec; }
+ inline void setCodec(QTextCodec *c) { m_codec = c; }
+ inline QByteArray decodingErrorSample() const { return m_decodingErrorSample; }
+
+ void reload(QTextCodec *codec);
+
+signals:
+ void titleChanged(QString title);
+ void changed();
+ void aboutToReload();
+ void reloaded();
+
+private:
+ QString m_fileName;
+ QString m_defaultPath;
+ QString m_suggestedFileName;
+ QString m_mimeType;
+ StorageSettings m_storageSettings;
+ TabSettings m_tabSettings;
+ Core::ICore *m_core;
+ QTextDocument *m_document;
+ DocumentMarker *m_documentMarker;
+ QSyntaxHighlighter *m_highlighter;
+
+ enum LineTerminatorMode {
+ LFLineTerminator,
+ CRLFLineTerminator,
+ NativeLineTerminator =
+#if defined (Q_OS_WIN)
+ CRLFLineTerminator
+#else
+ LFLineTerminator
+#endif
+ };
+ LineTerminatorMode m_lineTerminatorMode;
+ QTextCodec *m_codec;
+
+ bool m_isBinaryData;
+ bool m_hasDecodingError;
+ QByteArray m_decodingErrorSample;
+
+ void cleanWhitespace(QTextCursor& cursor, bool onlyInModifiedLines);
+ void ensureFinalNewLine(QTextCursor& cursor);
+};
+
+} // namespace TextEditor
+
+#endif
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
new file mode 100644
index 0000000000..a112770f93
--- /dev/null
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -0,0 +1,3453 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditor_global.h"
+#include "texteditorconstants.h"
+#ifndef TEXTEDITOR_STANDALONE
+#include "texteditorplugin.h"
+#include "completionsupport.h"
+#endif
+#include "basetextdocument.h"
+#include "basetexteditor_p.h"
+#include "codecselector.h"
+
+#ifndef TEXTEDITOR_STANDALONE
+#include <coreplugin/icore.h>
+#include <coreplugin/manhattanstyle.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <find/basetextfind.h>
+#include <texteditor/fontsettings.h>
+#include <utils/reloadpromptutils.h>
+#include <aggregation/aggregate.h>
+#endif
+#include <utils/linecolumnlabel.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTextCodec>
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+#include <QtGui/QAbstractTextDocumentLayout>
+#include <QtGui/QApplication>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QPrinter>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QPainter>
+#include <QtGui/QScrollBar>
+#include <QtGui/QShortcut>
+#include <QtGui/QScrollBar>
+#include <QtGui/QStyle>
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextLayout>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolTip>
+#include <QtGui/QInputDialog>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+
+namespace TextEditor {
+ namespace Internal {
+
+class TextEditExtraArea : public QWidget {
+ BaseTextEditor *textEdit;
+public:
+ TextEditExtraArea(BaseTextEditor *edit):QWidget(edit) {
+ textEdit = edit;
+ setAutoFillBackground(true);
+ }
+public:
+
+ QSize sizeHint() const {
+ return QSize(textEdit->extraAreaWidth(), 0);
+ }
+protected:
+ void paintEvent(QPaintEvent *event){
+ textEdit->extraAreaPaintEvent(event);
+ }
+ void mousePressEvent(QMouseEvent *event){
+ textEdit->extraAreaMouseEvent(event);
+ }
+ void mouseMoveEvent(QMouseEvent *event){
+ textEdit->extraAreaMouseEvent(event);
+ }
+ void mouseReleaseEvent(QMouseEvent *event){
+ textEdit->extraAreaMouseEvent(event);
+ }
+ void leaveEvent(QEvent *event){
+ textEdit->extraAreaLeaveEvent(event);
+ }
+
+ void wheelEvent(QWheelEvent *event) {
+ QCoreApplication::sendEvent(textEdit->viewport(), event);
+ }
+};
+
+ }
+}
+
+ITextEditor *BaseTextEditor::openEditorAt(const QString &fileName,
+ int line,
+ int column)
+{
+ Core::EditorManager *editorManager =
+ ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->editorManager();
+ editorManager->addCurrentPositionToNavigationHistory(true);
+ Core::IEditor *editor = editorManager->openEditor(fileName, QString(), true);
+ TextEditor::ITextEditor *texteditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ if (texteditor) {
+ texteditor->gotoLine(line, column);
+ editorManager->addCurrentPositionToNavigationHistory();
+ return texteditor;
+ }
+ return 0;
+}
+
+BaseTextEditor::BaseTextEditor(QWidget *parent)
+ : QPlainTextEdit(parent)
+{
+ d = new BaseTextEditorPrivate();
+ d->q = this;
+ d->m_extraArea = new TextEditExtraArea(this);
+ d->m_extraArea->setMouseTracking(true);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+
+ d->setupDocumentSignals(d->m_document);
+ d->setupDocumentSignals(d->m_document);
+
+ d->m_lastScrollPos = -1;
+ setCursorWidth(2);
+
+
+ // from RESEARCH
+
+ setLayoutDirection(Qt::LeftToRight);
+ viewport()->setMouseTracking(true);
+ d->extraAreaSelectionAnchorBlockNumber
+ = d->extraAreaToggleMarkBlockNumber
+ = d->extraAreaHighlightCollapseBlockNumber
+ = d->extraAreaHighlightFadingBlockNumber
+ = -1;
+ d->extraAreaCollapseAlpha = 255;
+
+ d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber = -1;
+
+ connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(slotUpdateExtraAreaWidth()));
+ connect(this, SIGNAL(modificationChanged(bool)), this, SLOT(slotModificationChanged(bool)));
+ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorPositionChanged()));
+ connect(this, SIGNAL(updateRequest(QRect, int)), this, SLOT(slotUpdateRequest(QRect, int)));
+ connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
+
+// (void) new QShortcut(tr("CTRL+L"), this, SLOT(centerCursor()), 0, Qt::WidgetShortcut);
+// (void) new QShortcut(tr("F9"), this, SLOT(slotToggleMark()), 0, Qt::WidgetShortcut);
+// (void) new QShortcut(tr("F11"), this, SLOT(slotToggleBlockVisible()));
+
+
+ // parentheses matcher
+ d->m_parenthesesMatchingEnabled = false;
+ d->m_formatRange = true;
+ d->m_matchFormat.setForeground(Qt::red);
+ d->m_rangeFormat.setBackground(QColor(0xb4, 0xee, 0xb4));
+ d->m_mismatchFormat.setBackground(Qt::magenta);
+ d->m_parenthesesMatchingTimer = new QTimer(this);
+ d->m_parenthesesMatchingTimer->setSingleShot(true);
+ connect(d->m_parenthesesMatchingTimer, SIGNAL(timeout()), this, SLOT(_q_matchParentheses()));
+
+
+ d->m_searchResultFormat.setBackground(QColor(0xffef0b));
+
+ slotUpdateExtraAreaWidth();
+ slotCursorPositionChanged();
+ setFrameStyle(QFrame::NoFrame);
+
+
+ d->extraAreaTimeLine = new QTimeLine(150, this);
+ d->extraAreaTimeLine->setFrameRange(0, 255);
+ connect(d->extraAreaTimeLine, SIGNAL(frameChanged(int)), this,
+ SLOT(setCollapseIndicatorAlpha(int)));
+
+
+ connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(currentEditorChanged(Core::IEditor*)));
+}
+
+BaseTextEditor::~BaseTextEditor()
+{
+ delete d;
+ d = 0;
+}
+
+QString BaseTextEditor::mimeType() const
+{
+ return d->m_document->mimeType();
+}
+
+void BaseTextEditor::setMimeType(const QString &mt)
+{
+ d->m_document->setMimeType(mt);
+}
+
+void BaseTextEditor::print(QPrinter *printer)
+{
+ const bool oldFullPage = printer->fullPage();
+ printer->setFullPage(true);
+ QPrintDialog *dlg = new QPrintDialog(printer, this);
+ dlg->setWindowTitle(tr("Print Document"));
+ if (dlg->exec() == QDialog::Accepted) {
+ d->print(printer);
+ }
+ printer->setFullPage(oldFullPage);
+ delete dlg;
+}
+
+static void printPage(int index, QPainter *painter, const QTextDocument *doc,
+ const QRectF &body, const QRectF &titleBox,
+ const QString &title)
+{
+ painter->save();
+
+ painter->translate(body.left(), body.top() - (index - 1) * body.height());
+ QRectF view(0, (index - 1) * body.height(), body.width(), body.height());
+
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+ QAbstractTextDocumentLayout::PaintContext ctx;
+
+ painter->setFont(QFont(doc->defaultFont()));
+ QRectF box = titleBox.translated(0, view.top());
+ int dpix = painter->device()->logicalDpiX();
+ int dpiy = painter->device()->logicalDpiY();
+ int mx = 5 * dpix / 72.0;
+ int my = 2 * dpiy / 72.0;
+ painter->fillRect(box.adjusted(-mx, -my, mx, my), QColor(210, 210, 210));
+ if (!title.isEmpty())
+ painter->drawText(box, Qt::AlignCenter, title);
+ const QString pageString = QString::number(index);
+ painter->drawText(box, Qt::AlignRight, pageString);
+
+ painter->setClipRect(view);
+ ctx.clip = view;
+ // don't use the system palette text as default text color, on HP/UX
+ // for example that's white, and white text on white paper doesn't
+ // look that nice
+ ctx.palette.setColor(QPalette::Text, Qt::black);
+
+ layout->draw(painter, ctx);
+
+ painter->restore();
+}
+
+void BaseTextEditorPrivate::print(QPrinter *printer)
+{
+
+ QTextDocument *doc = q->document();
+
+ QString title = q->displayName();
+ if (title.isEmpty())
+ printer->setDocName(title);
+
+
+ QPainter p(printer);
+
+ // Check that there is a valid device to print to.
+ if (!p.isActive())
+ return;
+
+ doc = doc->clone(doc);
+
+ QTextOption opt = doc->defaultTextOption();
+ opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ doc->setDefaultTextOption(opt);
+
+ (void)doc->documentLayout(); // make sure that there is a layout
+
+
+ QColor background = q->palette().color(QPalette::Base);
+ bool backgroundIsDark = background.value() < 128;
+
+ for (QTextBlock srcBlock = q->document()->firstBlock(), dstBlock = doc->firstBlock();
+ srcBlock.isValid() && dstBlock.isValid();
+ srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) {
+
+
+ QList<QTextLayout::FormatRange> formatList = srcBlock.layout()->additionalFormats();
+ if (backgroundIsDark) {
+ // adjust syntax highlighting colors for better contrast
+ for (int i = formatList.count() - 1; i >=0; --i) {
+ QTextCharFormat &format = formatList[i].format;
+ if (format.background().color() == background) {
+ QBrush brush = format.foreground();
+ QColor color = brush.color();
+ int h,s,v,a;
+ color.getHsv(&h, &s, &v, &a);
+ color.setHsv(h, s, qMin(128, v), a);
+ brush.setColor(color);
+ format.setForeground(brush);
+ }
+ format.setBackground(Qt::white);
+ }
+ }
+
+ dstBlock.layout()->setAdditionalFormats(formatList);
+ }
+
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+ layout->setPaintDevice(p.device());
+
+ int dpiy = p.device()->logicalDpiY();
+ int margin = (int) ((2/2.54)*dpiy); // 2 cm margins
+
+ QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
+ fmt.setMargin(margin);
+ doc->rootFrame()->setFrameFormat(fmt);
+
+ QRectF pageRect(printer->pageRect());
+ QRectF body = QRectF(0, 0, pageRect.width(), pageRect.height());
+ QFontMetrics fontMetrics(doc->defaultFont(), p.device());
+
+ QRectF titleBox(margin,
+ body.top() + margin
+ - fontMetrics.height()
+ - 6 * dpiy / 72.0,
+ body.width() - 2*margin,
+ fontMetrics.height());
+ doc->setPageSize(body.size());
+
+ int docCopies;
+ int pageCopies;
+ if (printer->collateCopies() == true){
+ docCopies = 1;
+ pageCopies = printer->numCopies();
+ } else {
+ docCopies = printer->numCopies();
+ pageCopies = 1;
+ }
+
+ int fromPage = printer->fromPage();
+ int toPage = printer->toPage();
+ bool ascending = true;
+
+ if (fromPage == 0 && toPage == 0) {
+ fromPage = 1;
+ toPage = doc->pageCount();
+ }
+ // paranoia check
+ fromPage = qMax(1, fromPage);
+ toPage = qMin(doc->pageCount(), toPage);
+
+ if (printer->pageOrder() == QPrinter::LastPageFirst) {
+ int tmp = fromPage;
+ fromPage = toPage;
+ toPage = tmp;
+ ascending = false;
+ }
+
+ for (int i = 0; i < docCopies; ++i) {
+
+ int page = fromPage;
+ while (true) {
+ for (int j = 0; j < pageCopies; ++j) {
+ if (printer->printerState() == QPrinter::Aborted
+ || printer->printerState() == QPrinter::Error)
+ goto UserCanceled;
+ printPage(page, &p, doc, body, titleBox, title);
+ if (j < pageCopies - 1)
+ printer->newPage();
+ }
+
+ if (page == toPage)
+ break;
+
+ if (ascending)
+ ++page;
+ else
+ --page;
+
+ printer->newPage();
+ }
+
+ if ( i < docCopies - 1)
+ printer->newPage();
+ }
+
+UserCanceled:
+ delete doc;
+}
+
+
+bool DocumentMarker::addMark(TextEditor::ITextMark *mark, int line)
+{
+ Q_ASSERT(line >= 1);
+ int blockNumber = line - 1;
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document->documentLayout());
+ Q_ASSERT(documentLayout);
+ QTextBlock block = document->findBlockByNumber(blockNumber);
+
+ if (block.isValid()) {
+ TextBlockUserData *userData = TextEditDocumentLayout::userData(block);
+ userData->addMark(mark);
+ mark->updateLineNumber(blockNumber + 1);
+ mark->updateBlock(block);
+ documentLayout->hasMarks = true;
+ documentLayout->requestUpdate();
+ return true;
+ }
+ return false;
+}
+
+
+TextEditor::TextMarks DocumentMarker::marksAt(int line) const
+{
+ Q_ASSERT(line >= 1);
+ int blockNumber = line - 1;
+ QTextBlock block = document->findBlockByNumber(blockNumber);
+
+ if (block.isValid()) {
+ if (TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
+ return userData->marks();
+ }
+ return TextMarks();
+}
+
+void DocumentMarker::removeMark(TextEditor::ITextMark *mark)
+{
+ bool needUpdate = false;
+ QTextBlock block = document->begin();
+ while (block.isValid()) {
+ if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData())) {
+ needUpdate |= data->removeMark(mark);
+ }
+ block = block.next();
+ }
+ if (needUpdate)
+ updateMark(0);
+}
+
+
+bool DocumentMarker::hasMark(TextEditor::ITextMark *mark) const
+{
+ QTextBlock block = document->begin();
+ while (block.isValid()) {
+ if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData())) {
+ if (data->hasMark(mark))
+ return true;
+ }
+ block = block.next();
+ }
+ return false;
+}
+
+ITextMarkable *BaseTextEditor::markableInterface() const
+{
+ return baseTextDocument()->documentMarker();
+}
+
+ITextEditable *BaseTextEditor::editableInterface() const
+{
+ if (!d->m_editable) {
+ d->m_editable = const_cast<BaseTextEditor*>(this)->createEditableInterface();
+ connect(this, SIGNAL(textChanged()),
+ d->m_editable, SIGNAL(contentsChanged()));
+ connect(this, SIGNAL(changed()),
+ d->m_editable, SIGNAL(changed()));
+ connect(this,
+ SIGNAL(markRequested(TextEditor::ITextEditor *, int)),
+ d->m_editable,
+ SIGNAL(markRequested(TextEditor::ITextEditor *, int)));
+ }
+ return d->m_editable;
+}
+
+
+void BaseTextEditor::currentEditorChanged(Core::IEditor *editor)
+{
+ if (editor == d->m_editable) {
+ if (d->m_document->hasDecodingError()) {
+ Core::EditorManager::instance()->showEditorInfoBar(QLatin1String(Constants::SELECT_ENCODING),
+ tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding. Editing not possible.").arg(displayName()).arg(QString::fromLatin1(d->m_document->codec()->name())),
+ tr("Select Encoding"),
+ this, SLOT(selectEncoding()));
+ }
+ }
+}
+
+void BaseTextEditor::selectEncoding()
+{
+ BaseTextDocument *doc = d->m_document;
+ CodecSelector codecSelector(this, doc);
+
+ switch (codecSelector.exec()) {
+ case CodecSelector::Reload:
+ doc->reload(codecSelector.selectedCodec());
+ setReadOnly(d->m_document->hasDecodingError());
+ if (doc->hasDecodingError())
+ currentEditorChanged(Core::EditorManager::instance()->currentEditor());
+ else
+ Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String(Constants::SELECT_ENCODING));
+ break;
+ case CodecSelector::Save:
+ doc->setCodec(codecSelector.selectedCodec());
+ Core::EditorManager::instance()->saveEditor(editableInterface());
+ break;
+ case CodecSelector::Cancel:
+ break;
+ }
+}
+
+
+void DocumentMarker::updateMark(ITextMark *mark)
+{
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document->documentLayout());
+ Q_ASSERT(documentLayout);
+ Q_UNUSED(mark);
+ documentLayout->requestUpdate();
+}
+
+
+void BaseTextEditor::triggerCompletions()
+{
+ emit requestAutoCompletion(editableInterface(), true);
+}
+
+bool BaseTextEditor::createNew(const QString &contents)
+{
+ setPlainText(contents);
+ document()->setModified(false);
+ return true;
+}
+
+bool BaseTextEditor::open(const QString &fileName)
+{
+ if (d->m_document->open(fileName)) {
+ moveCursor(QTextCursor::Start);
+ setReadOnly(d->m_document->hasDecodingError());
+ return true;
+ }
+ return false;
+}
+
+Core::IFile * BaseTextEditor::file()
+{
+ return d->m_document;
+}
+
+void BaseTextEditor::editorContentsChange(int position, int charsRemoved, int charsAdded)
+{
+ d->m_contentsChanged = true;
+
+ // Keep the line numbers and the block information for the text marks updated
+ if (charsRemoved != 0) {
+ d->updateMarksLineNumber();
+ d->updateMarksBlock(document()->findBlock(position));
+ } else {
+ const QTextBlock posBlock = document()->findBlock(position);
+ const QTextBlock nextBlock = document()->findBlock(position + charsAdded);
+ if (posBlock != nextBlock) {
+ d->updateMarksLineNumber();
+ d->updateMarksBlock(posBlock);
+ d->updateMarksBlock(nextBlock);
+ } else {
+ d->updateMarksBlock(posBlock);
+ }
+ }
+}
+
+
+void BaseTextEditor::slotSelectionChanged()
+{
+ bool changed = (d->m_inBlockSelectionMode != d->m_lastEventWasBlockSelectionEvent);
+ d->m_inBlockSelectionMode = d->m_lastEventWasBlockSelectionEvent;
+ if (changed || d->m_inBlockSelectionMode)
+ viewport()->update();
+ if (!d->m_inBlockSelectionMode)
+ d->m_blockSelectionExtraX = 0;
+}
+
+void BaseTextEditor::keyPressEvent(QKeyEvent *e)
+{
+
+ d->clearVisibleCollapsedBlock();
+
+ QKeyEvent *original_e = e;
+ d->m_lastEventWasBlockSelectionEvent = false;
+
+ if (e->key() == Qt::Key_Escape) {
+ e->accept();
+ QTextCursor cursor = textCursor();
+ cursor.clearSelection();
+ setTextCursor(cursor);
+ return;
+ }
+
+ d->m_contentsChanged = false;
+
+ bool ro = isReadOnly();
+
+ if (d->m_inBlockSelectionMode) {
+ if (e == QKeySequence::Cut) {
+ if (!ro) {
+ cut();
+ e->accept();
+ return;
+ }
+ } else if (e == QKeySequence::Delete) {
+ if (!ro) {
+ d->removeBlockSelection();
+ e->accept();
+ return;
+ }
+ }
+ }
+
+
+ if (!ro
+ && (e == QKeySequence::InsertParagraphSeparator
+ || (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))
+ ) {
+
+ QTextCursor cursor = textCursor();
+ if (d->m_inBlockSelectionMode)
+ cursor.clearSelection();
+ cursor.insertBlock();
+ if (d->m_document->tabSettings().m_autoIndent) {
+ indent(document(), cursor, QChar::Null);
+ }
+ e->accept();
+ setTextCursor(cursor);
+ return;
+ } else switch (e->key()) {
+
+
+#if 0
+ case Qt::Key_sterling: {
+
+ static bool toggle = false;
+ if ((toggle = !toggle)) {
+ QList<BaseTextEditor::BlockRange> rangeList;
+ rangeList += BaseTextEditor::BlockRange(4, 12);
+ rangeList += BaseTextEditor::BlockRange(15, 19);
+ setIfdefedOutBlocks(rangeList);
+ } else {
+ setIfdefedOutBlocks(QList<BaseTextEditor::BlockRange>());
+ }
+ e->accept();
+ return;
+
+ } break;
+#endif
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ if (ro) break;
+ indentOrUnindent(e->key() == Qt::Key_Tab);
+ e->accept();
+ return;
+ case Qt::Key_Backspace:
+ if (ro) break;
+ if (d->m_document->tabSettings().m_smartBackspace
+ && (e->modifiers() & (Qt::ControlModifier
+ | Qt::ShiftModifier
+ | Qt::AltModifier
+ | Qt::MetaModifier)) == Qt::NoModifier
+ && !textCursor().hasSelection()) {
+ handleBackspaceKey();
+ e->accept();
+ return;
+ }
+ break;
+ case Qt::Key_Home:
+ if (!(e == QKeySequence::MoveToStartOfDocument) && !(e == QKeySequence::SelectStartOfDocument)) {
+ handleHomeKey(e->modifiers() & Qt::ShiftModifier);
+ e->accept();
+ return;
+ }
+ break;
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ if (e->modifiers() & Qt::ControlModifier) {
+ verticalScrollBar()->triggerAction(
+ e->key() == Qt::Key_Up ? QAbstractSlider::SliderSingleStepSub :
+ QAbstractSlider::SliderSingleStepAdd);
+ e->accept();
+ return;
+ }
+ // fall through
+ case Qt::Key_Right:
+ case Qt::Key_Left:
+#ifndef Q_OS_MAC
+ if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
+
+ d->m_lastEventWasBlockSelectionEvent = true;
+
+ if (d->m_inBlockSelectionMode) {
+ if (e->key() == Qt::Key_Right && textCursor().atBlockEnd()) {
+ d->m_blockSelectionExtraX++;
+ viewport()->update();
+ e->accept();
+ return;
+ } else if (e->key() == Qt::Key_Left && d->m_blockSelectionExtraX > 0) {
+ d->m_blockSelectionExtraX--;
+ e->accept();
+ viewport()->update();
+ return;
+ }
+ }
+
+ e = new QKeyEvent(
+ e->type(),
+ e->key(),
+ e->modifiers() & ~Qt::AltModifier,
+ e->text(),
+ e->isAutoRepeat(),
+ e->count()
+ );
+ }
+#endif
+ break;
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ if (e->modifiers() == Qt::ControlModifier) {
+ verticalScrollBar()->triggerAction(
+ e->key() == Qt::Key_PageUp ? QAbstractSlider::SliderPageStepSub :
+ QAbstractSlider::SliderPageStepAdd);
+ e->accept();
+ return;
+ }
+ break;
+
+ default:
+ if (! ro && d->m_document->tabSettings().m_autoIndent
+ && ! e->text().isEmpty() && isElectricCharacter(e->text().at(0))) {
+ QTextCursor cursor = textCursor();
+ const QString text = e->text();
+ cursor.insertText(text);
+ const QString leftText = cursor.block().text().left(cursor.position() - 1 - cursor.block().position());
+ if (leftText.simplified().isEmpty()) {
+ const QChar typedChar = e->text().at(0);
+ indent(document(), cursor, typedChar);
+ }
+#if 0
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
+ Q_ASSERT(documentLayout);
+ documentLayout->requestUpdate(); // a bit drastic
+ e->accept();
+#endif
+ setTextCursor(cursor);
+ return;
+ }
+ break;
+ }
+
+ if (d->m_inBlockSelectionMode) {
+ QString text = e->text();
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
+ d->removeBlockSelection(text);
+ goto skip_event;
+ }
+ }
+
+ QPlainTextEdit::keyPressEvent(e);
+
+skip_event:
+ if (!ro && e->key() == Qt::Key_Delete && d->m_parenthesesMatchingEnabled)
+ slotCursorPositionChanged(); // parentheses matching
+
+ if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint())
+ emit requestAutoCompletion(editableInterface(), false);
+
+ if (e != original_e)
+ delete e;
+}
+
+void BaseTextEditor::gotoLine(int line, int column)
+{
+ const int blockNumber = line - 1;
+ const QTextBlock &block = document()->findBlockByNumber(blockNumber);
+ if (block.isValid()) {
+ QTextCursor cursor(block);
+ if (column > 0) {
+ cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, column);
+ } else {
+ int pos = cursor.position();
+ while (characterAt(pos).category() == QChar::Separator_Space) {
+ ++pos;
+ }
+ cursor.setPosition(pos);
+ }
+ setTextCursor(cursor);
+ centerCursor();
+ }
+}
+
+int BaseTextEditor::position(ITextEditor::PositionOperation posOp, int at) const
+{
+ QTextCursor tc = textCursor();
+
+ if (at != -1)
+ tc.setPosition(at);
+
+ if (posOp == ITextEditor::Current)
+ return tc.position();
+
+ switch (posOp) {
+ case ITextEditor::EndOfLine:
+ tc.movePosition(QTextCursor::EndOfLine);
+ return tc.position();
+ case ITextEditor::StartOfLine:
+ tc.movePosition(QTextCursor::StartOfLine);
+ return tc.position();
+ case ITextEditor::Anchor:
+ if (tc.hasSelection())
+ return tc.anchor();
+ break;
+ case ITextEditor::EndOfDoc:
+ tc.movePosition(QTextCursor::End);
+ return tc.position();
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+void BaseTextEditor::convertPosition(int pos, int *line, int *column) const
+{
+ QTextBlock block = document()->findBlock(pos);
+ if (!block.isValid()) {
+ (*line) = -1;
+ (*column) = -1;
+ } else {
+ (*line) = block.blockNumber() + 1;
+ (*column) = pos - block.position();
+ }
+}
+
+QChar BaseTextEditor::characterAt(int pos) const
+{
+ return document()->characterAt(pos);
+}
+
+bool BaseTextEditor::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::ShortcutOverride:
+ e->ignore(); // we are a really nice citizen
+ return true;
+ default:
+ break;
+ }
+
+ return QPlainTextEdit::event(e);
+}
+
+void BaseTextEditor::duplicateFrom(BaseTextEditor *editor)
+{
+ if (this == editor)
+ return;
+ setDisplayName(editor->displayName());
+ d->m_revisionsVisible = editor->d->m_revisionsVisible;
+ if (d->m_document == editor->d->m_document)
+ return;
+ d->setupDocumentSignals(editor->d->m_document);
+ d->m_document = editor->d->m_document;
+}
+
+QString BaseTextEditor::displayName() const
+{
+ return d->m_displayName;
+}
+
+void BaseTextEditor::setDisplayName(const QString &title)
+{
+ d->m_displayName = title;
+}
+
+BaseTextDocument *BaseTextEditor::baseTextDocument() const
+{
+ return d->m_document;
+}
+
+void BaseTextEditor::setBaseTextDocument(BaseTextDocument *doc)
+{
+ if (doc) {
+ d->setupDocumentSignals(doc);
+ d->m_document = doc;
+ }
+}
+
+void BaseTextEditor::memorizeCursorPosition()
+{
+ d->m_tempState = saveState();
+}
+
+void BaseTextEditor::restoreCursorPosition()
+{
+ restoreState(d->m_tempState);
+}
+
+QByteArray BaseTextEditor::saveState() const
+{
+ QByteArray state;
+ QDataStream stream(&state, QIODevice::WriteOnly);
+ stream << 0; // version number
+ stream << verticalScrollBar()->value();
+ stream << horizontalScrollBar()->value();
+ int line, column;
+ convertPosition(textCursor().position(), &line, &column);
+ stream << line;
+ stream << column;
+ return state;
+}
+
+bool BaseTextEditor::restoreState(const QByteArray &state)
+{
+ int version;
+ int vval;
+ int hval;
+ int lval;
+ int cval;
+ QDataStream stream(state);
+ stream >> version;
+ stream >> vval;
+ stream >> hval;
+ stream >> lval;
+ stream >> cval;
+ gotoLine(lval, cval);
+ verticalScrollBar()->setValue(vval);
+ horizontalScrollBar()->setValue(hval);
+ return true;
+}
+
+void BaseTextEditor::setDefaultPath(const QString &defaultPath)
+{
+ baseTextDocument()->setDefaultPath(defaultPath);
+}
+
+void BaseTextEditor::setSuggestedFileName(const QString &suggestedFileName)
+{
+ baseTextDocument()->setSuggestedFileName(suggestedFileName);
+}
+
+void BaseTextEditor::setParenthesesMatchingEnabled(bool b)
+{
+ d->m_parenthesesMatchingEnabled = b;
+}
+
+bool BaseTextEditor::isParenthesesMatchingEnabled() const
+{
+ return d->m_parenthesesMatchingEnabled;
+}
+
+void BaseTextEditor::setHighlightCurrentLine(bool b)
+{
+ d->m_highlightCurrentLine = b;
+ slotCursorPositionChanged();
+}
+
+bool BaseTextEditor::highlightCurrentLine() const
+{
+ return d->m_highlightCurrentLine;
+}
+
+void BaseTextEditor::setLineNumbersVisible(bool b)
+{
+ d->m_lineNumbersVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::lineNumbersVisible() const
+{
+ return d->m_lineNumbersVisible;
+}
+
+void BaseTextEditor::setMarksVisible(bool b)
+{
+ d->m_marksVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::marksVisible() const
+{
+ return d->m_marksVisible;
+}
+
+void BaseTextEditor::setRequestMarkEnabled(bool b)
+{
+ d->m_requestMarkEnabled = b;
+}
+
+bool BaseTextEditor::requestMarkEnabled() const
+{
+ return d->m_requestMarkEnabled;
+}
+
+void BaseTextEditor::setLineSeparatorsAllowed(bool b)
+{
+ d->m_lineSeparatorsAllowed = b;
+}
+
+bool BaseTextEditor::lineSeparatorsAllowed() const
+{
+ return d->m_lineSeparatorsAllowed;
+}
+
+
+void BaseTextEditor::setCodeFoldingVisible(bool b)
+{
+ d->m_codeFoldingVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::codeFoldingVisible() const
+{
+ return d->m_codeFoldingVisible;
+}
+
+void BaseTextEditor::setRevisionsVisible(bool b)
+{
+ d->m_revisionsVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::revisionsVisible() const
+{
+ return d->m_revisionsVisible;
+}
+
+void BaseTextEditor::setVisibleWrapColumn(int column)
+{
+ d->m_visibleWrapColumn = column;
+ viewport()->update();
+}
+
+int BaseTextEditor::visibleWrapColumn() const
+{
+ return d->m_visibleWrapColumn;
+}
+
+void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT));
+ const QTextCharFormat selectionFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SELECTION));
+ const QTextCharFormat lineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_LINE_NUMBER));
+ const QTextCharFormat searchResultFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_RESULT));
+ const QTextCharFormat searchScopeFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_SCOPE));
+ const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES));
+ const QTextCharFormat currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE));
+ const QTextCharFormat ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE));
+ QFont font(textFormat.font());
+
+ const QColor foreground = textFormat.foreground().color();
+ const QColor background = textFormat.background().color();
+ QPalette p = palette();
+ p.setColor(QPalette::Text, foreground);
+ p.setColor(QPalette::Foreground, foreground);
+ p.setColor(QPalette::Base, background);
+ p.setColor(QPalette::Highlight, (selectionFormat.background().style() != Qt::NoBrush) ?
+ selectionFormat.background().color() :
+ QApplication::palette().color(QPalette::Highlight));
+ p.setColor(QPalette::HighlightedText, selectionFormat.foreground().color());
+ p.setBrush(QPalette::Inactive, QPalette::Highlight, p.highlight());
+ p.setBrush(QPalette::Inactive, QPalette::HighlightedText, p.highlightedText());
+ setPalette(p);
+ setFont(font);
+ setTabSettings(d->m_document->tabSettings()); // update tabs, they depend on the font
+
+ // Line numbers
+ QPalette ep = d->m_extraArea->palette();
+ ep.setColor(QPalette::Dark, lineNumberFormat.foreground().color());
+ ep.setColor(QPalette::Background, lineNumberFormat.background().style() != Qt::NoBrush ?
+ lineNumberFormat.background().color() : background);
+ d->m_extraArea->setPalette(ep);
+
+ // Search results
+ d->m_searchResultFormat.setBackground(searchResultFormat.background());
+ d->m_searchScopeFormat.setBackground(searchScopeFormat.background());
+ d->m_currentLineFormat.setBackground(currentLineFormat.background());
+
+ // Matching braces
+ d->m_matchFormat.setForeground(parenthesesFormat.foreground());
+ d->m_rangeFormat.setBackground(parenthesesFormat.background());
+
+ // Disabled code
+ d->m_ifdefedOutFormat.setForeground(ifdefedOutFormat.foreground());
+
+ slotUpdateExtraAreaWidth();
+}
+
+void BaseTextEditor::setStorageSettings(const StorageSettings &storageSettings)
+{
+ d->m_document->setStorageSettings(storageSettings);
+}
+
+//--------- BaseTextEditorPrivate -----------
+
+BaseTextEditorPrivate::BaseTextEditorPrivate()
+ :
+ m_contentsChanged(false),
+ m_document(new BaseTextDocument()),
+ m_parenthesesMatchingEnabled(false),
+ m_extraArea(0),
+ m_marksVisible(false),
+ m_codeFoldingVisible(false),
+ m_revisionsVisible(false),
+ m_lineNumbersVisible(true),
+ m_highlightCurrentLine(true),
+ m_requestMarkEnabled(true),
+ m_lineSeparatorsAllowed(false),
+ m_visibleWrapColumn(0),
+ m_editable(0),
+ m_actionHack(0),
+ m_inBlockSelectionMode(false),
+ m_lastEventWasBlockSelectionEvent(false),
+ m_blockSelectionExtraX(0)
+{
+}
+
+BaseTextEditorPrivate::~BaseTextEditorPrivate()
+{
+}
+
+void BaseTextEditorPrivate::setupDocumentSignals(BaseTextDocument *document)
+{
+ BaseTextDocument *oldDocument = q->baseTextDocument();
+ if (oldDocument) {
+ q->disconnect(oldDocument->document(), 0, q, 0);
+ q->disconnect(oldDocument, 0, q, 0);
+ }
+
+ QTextDocument *doc = document->document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ if (!documentLayout) {
+ QTextOption opt = doc->defaultTextOption();
+ opt.setTextDirection(Qt::LeftToRight);
+ opt.setFlags(opt.flags() | QTextOption::IncludeTrailingSpaces
+ | QTextOption::AddSpaceForLineAndParagraphSeparators
+ );
+ doc->setDefaultTextOption(opt);
+ documentLayout = new TextEditDocumentLayout(doc);
+ doc->setDocumentLayout(documentLayout);
+ }
+
+
+ q->setDocument(doc);
+ QObject::connect(documentLayout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(slotUpdateBlockNotify(QTextBlock)));
+ QObject::connect(q, SIGNAL(requestBlockUpdate(QTextBlock)), documentLayout, SIGNAL(updateBlock(QTextBlock)));
+ QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(changed()));
+ QObject::connect(doc, SIGNAL(contentsChange(int,int,int)), q,
+ SLOT(editorContentsChange(int,int,int)), Qt::DirectConnection);
+ QObject::connect(document, SIGNAL(changed()), q, SIGNAL(changed()));
+ QObject::connect(document, SIGNAL(titleChanged(QString)), q, SLOT(setDisplayName(const QString &)));
+ QObject::connect(document, SIGNAL(aboutToReload()), q, SLOT(memorizeCursorPosition()));
+ QObject::connect(document, SIGNAL(reloaded()), q, SLOT(restoreCursorPosition()));
+ q->slotUpdateExtraAreaWidth();
+}
+
+#ifndef TEXTEDITOR_STANDALONE
+bool BaseTextEditorPrivate::needMakeWritableCheck() const
+{
+ return !m_document->isModified()
+ && !m_document->fileName().isEmpty()
+ && m_document->isReadOnly();
+}
+#endif
+
+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('+')) {
+ ++depth;
+ } else if (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('+')) {
+ if (depth == 0) {
+ result = p.pos;
+ c = p.chr;
+ }
+ ++depth;
+ } else if (p.chr == QLatin1Char('}') || p.chr == QLatin1Char('-')) {
+ if (--depth < 0)
+ depth = 0;
+ result = -1;
+ }
+ }
+ if (result >= 0 && character)
+ *character = c;
+ return result;
+}
+
+
+int TextBlockUserData::collapseAtPos() const
+{
+ return Parenthesis::collapseAtPos(m_parentheses);
+}
+
+
+void TextEditDocumentLayout::setParentheses(const QTextBlock &block, const Parentheses &parentheses)
+{
+ if (parentheses.isEmpty()) {
+ if (TextBlockUserData *userData = testUserData(block))
+ userData->clearParentheses();
+ } else {
+ userData(block)->setParentheses(parentheses);
+ }
+}
+
+Parentheses TextEditDocumentLayout::parentheses(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->parentheses();
+ return Parentheses();
+}
+
+bool TextEditDocumentLayout::hasParentheses(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->hasParentheses();
+ return false;
+}
+
+
+bool TextEditDocumentLayout::setIfdefedOut(const QTextBlock &block)
+{
+ return userData(block)->setIfdefedOut();
+}
+
+bool TextEditDocumentLayout::clearIfdefedOut(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->clearIfdefedOut();
+ return false;
+}
+
+bool TextEditDocumentLayout::ifdefedOut(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->ifdefedOut();
+ return false;
+}
+
+
+TextEditDocumentLayout::TextEditDocumentLayout(QTextDocument *doc)
+ :QPlainTextDocumentLayout(doc) {
+ lastSaveRevision = 0;
+ hasMarks = 0;
+}
+
+TextEditDocumentLayout::~TextEditDocumentLayout()
+{
+}
+
+QRectF TextEditDocumentLayout::blockBoundingRect(const QTextBlock &block) const
+{
+ QRectF r = QPlainTextDocumentLayout::blockBoundingRect(block);
+ return r;
+}
+
+
+bool BaseTextEditor::viewportEvent(QEvent *event)
+{
+ if (event->type() == QEvent::ContextMenu) {
+ const QContextMenuEvent *ce = static_cast<QContextMenuEvent*>(event);
+ if (ce->reason() == QContextMenuEvent::Mouse && !textCursor().hasSelection())
+ setTextCursor(cursorForPosition(ce->pos()));
+ } else if (event->type() == QEvent::ToolTip) {
+ const QHelpEvent *he = static_cast<QHelpEvent*>(event);
+ const QPoint &pos = he->pos();
+
+ // Allow plugins to show tooltips
+ const QTextCursor &c = cursorForPosition(pos);
+ QPoint cursorPos = mapToGlobal(cursorRect(c).bottomRight() + QPoint(1,1));
+ cursorPos.setX(cursorPos.x() + d->m_extraArea->width());
+
+ editableInterface(); // create if necessary
+
+ emit d->m_editable->tooltipRequested(editableInterface(), cursorPos, c.position());
+ return true;
+ }
+ return QPlainTextEdit::viewportEvent(event);
+}
+
+
+void BaseTextEditor::resizeEvent(QResizeEvent *e)
+{
+ QPlainTextEdit::resizeEvent(e);
+ QRect cr = viewport()->rect();
+ d->m_extraArea->setGeometry(
+ QStyle::visualRect(layoutDirection(), cr,
+ QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
+}
+
+QRect BaseTextEditor::collapseBox(const QTextBlock &block)
+{
+ QRectF br = blockBoundingGeometry(block).translated(contentOffset());
+ int collapseBoxWidth = fontMetrics().lineSpacing() + 1;
+ return QRect(d->m_extraArea->width() - collapseBoxWidth + collapseBoxWidth/4,
+ int(br.top()) + collapseBoxWidth/4,
+ 2 * (collapseBoxWidth/4) + 1, 2 * (collapseBoxWidth/4) + 1);
+
+}
+
+QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const {
+ QPointF offset(contentOffset());
+ QTextBlock block = firstVisibleBlock();
+ int top = (int)blockBoundingGeometry(block).translated(offset).top();
+ int bottom = top + (int)blockBoundingRect(block).height();
+
+ int viewportHeight = viewport()->height();
+
+ while (block.isValid() && top <= viewportHeight) {
+ QTextBlock nextBlock = block.next();
+ if (block.isVisible() && bottom >= 0) {
+ if (nextBlock.isValid() && !nextBlock.isVisible()) {
+ QTextLayout *layout = block.layout();
+ QTextLine line = layout->lineAt(layout->lineCount()-1);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ lineRect.adjust(0, 0, -1, -1);
+
+ QRectF collapseRect(lineRect.right() + 12,
+ lineRect.top(),
+ fontMetrics().width(QLatin1String(" {...}; ")),
+ lineRect.height());
+ if (collapseRect.contains(pos)) {
+ QTextBlock result = block;
+ if (box)
+ *box = collapseRect.toAlignedRect();
+ return result;
+ } else {
+ block = nextBlock;
+ while (nextBlock.isValid() && !nextBlock.isVisible()) {
+ block = nextBlock;
+ nextBlock = block.next();
+ }
+ }
+ }
+ }
+
+ block = nextBlock;
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ }
+ return QTextBlock();
+}
+
+void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block,
+ QVector<QTextLayout::FormatRange> *selections)
+{
+ if (m_searchExpr.isEmpty())
+ return;
+
+ QString text = block.text();
+ text.replace(QChar::Nbsp, QLatin1Char(' '));
+ int idx = -1;
+ while (idx < text.length()) {
+ idx = m_searchExpr.indexIn(text, idx + 1);
+ if (idx < 0)
+ break;
+ int l = m_searchExpr.matchedLength();
+ if ((m_findFlags & QTextDocument::FindWholeWords)
+ && ((idx && text.at(idx-1).isLetterOrNumber())
+ || (idx + l < text.length() && text.at(idx + l).isLetterOrNumber())))
+ continue;
+
+ if (m_findScope.isNull()
+ || (block.position() + idx >= m_findScope.selectionStart()
+ && block.position() + idx + l <= m_findScope.selectionEnd())) {
+ QTextLayout::FormatRange selection;
+ selection.start = idx;
+ selection.length = l;
+ selection.format = m_searchResultFormat;
+ selections->append(selection);
+ }
+ }
+}
+
+
+namespace TextEditor {
+ namespace Internal {
+ struct BlockSelectionData {
+ int selectionIndex;
+ int selectionStart;
+ int selectionEnd;
+ int firstColumn;
+ int lastColumn;
+ };
+
+ }
+}
+
+void BaseTextEditorPrivate::clearBlockSelection()
+{
+ if (m_inBlockSelectionMode) {
+ m_inBlockSelectionMode = false;
+ QTextCursor cursor = q->textCursor();
+ cursor.clearSelection();
+ q->setTextCursor(cursor);
+ }
+}
+
+QString BaseTextEditorPrivate::copyBlockSelection()
+{
+ QString text;
+
+ QTextCursor cursor = q->textCursor();
+ if (!cursor.hasSelection())
+ return text;
+
+ QTextDocument *doc = q->document();
+ int start = cursor.selectionStart();
+ int end = cursor.selectionEnd();
+ QTextBlock startBlock = doc->findBlock(start);
+ int columnA = start - startBlock.position();
+ QTextBlock endBlock = doc->findBlock(end);
+ int columnB = end - endBlock.position();
+ int firstColumn = qMin(columnA, columnB);
+ int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX;
+
+ QTextBlock block = startBlock;
+ for (;;) {
+
+ cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn));
+ cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor);
+ text += cursor.selectedText();
+ if (block == endBlock)
+ break;
+ text += QLatin1Char('\n');
+ block = block.next();
+ }
+
+ return text;
+}
+
+void BaseTextEditorPrivate::removeBlockSelection(const QString &text)
+{
+ QTextCursor cursor = q->textCursor();
+ if (!cursor.hasSelection())
+ return;
+
+ QTextDocument *doc = q->document();
+ int start = cursor.selectionStart();
+ int end = cursor.selectionEnd();
+ QTextBlock startBlock = doc->findBlock(start);
+ int columnA = start - startBlock.position();
+ QTextBlock endBlock = doc->findBlock(end);
+ int columnB = end - endBlock.position();
+ int firstColumn = qMin(columnA, columnB);
+ int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX;
+
+ cursor.clearSelection();
+ cursor.beginEditBlock();
+
+ QTextBlock block = startBlock;
+ for (;;) {
+
+ cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn));
+ cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ if (block == endBlock)
+ break;
+ block = block.next();
+ }
+
+ cursor.setPosition(start);
+ if (!text.isEmpty())
+ cursor.insertText(text);
+ cursor.endEditBlock();
+ q->setTextCursor(cursor);
+}
+
+void BaseTextEditor::paintEvent(QPaintEvent *e)
+{
+ /*
+ Here comes an almost verbatim copy of
+ QPlainTextEdit::paintEvent() so we can adjust the extra
+ selections dynamically to indicate all search results.
+ */
+ //begin QPlainTextEdit::paintEvent()
+
+ QPainter painter(viewport());
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QPointF offset(contentOffset());
+
+ QRect er = e->rect();
+ QRect viewportRect = viewport()->rect();
+
+ // keep right margin clean from full-width selection
+ int maxX = offset.x() + qMax((qreal)viewportRect.width(), documentLayout->documentSize().width())
+ - doc->documentMargin();
+ er.setRight(qMin(er.right(), maxX));
+ painter.setClipRect(er);
+
+ bool editable = !isReadOnly();
+
+ QTextBlock block = firstVisibleBlock();
+
+ QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
+
+
+ if (!d->m_findScope.isNull()) {
+ QAbstractTextDocumentLayout::Selection selection;
+ selection.format.setBackground(d->m_searchScopeFormat.background());
+ selection.cursor = d->m_findScope;
+ context.selections.prepend(selection);
+ }
+
+ BlockSelectionData *blockSelection = 0;
+
+ if (d->m_inBlockSelectionMode
+ && context.selections.count() && context.selections.last().cursor == textCursor()) {
+ blockSelection = new BlockSelectionData;
+ blockSelection->selectionIndex = context.selections.size()-1;
+ const QAbstractTextDocumentLayout::Selection &selection = context.selections[blockSelection->selectionIndex];
+ int start = blockSelection->selectionStart = selection.cursor.selectionStart();
+ int end = blockSelection->selectionEnd = selection.cursor.selectionEnd();
+ QTextBlock block = doc->findBlock(start);
+ int columnA = start - block.position();
+ block = doc->findBlock(end);
+ int columnB = end - block.position();
+ blockSelection->firstColumn = qMin(columnA, columnB);
+ blockSelection->lastColumn = qMax(columnA, columnB) + d->m_blockSelectionExtraX;
+ }
+
+ const QColor baseColor = palette().base().color();
+ const int blendBase = (baseColor.value() > 128) ? 0 : 255;
+ // Darker backgrounds may need a bit more contrast
+ // (this calculation is temporary solution until we have a setting for this color)
+ const int blendFactor = (baseColor.value() > 128) ? 8 : 16;
+ const QColor blendColor(
+ (blendBase * blendFactor + baseColor.blue() * (256 - blendFactor)) / 256,
+ (blendBase * blendFactor + baseColor.green() * (256 - blendFactor)) / 256,
+ (blendBase * blendFactor + baseColor.blue() * (256 - blendFactor)) / 256);
+ if (d->m_visibleWrapColumn > 0) {
+ qreal lineX = fontMetrics().averageCharWidth() * d->m_visibleWrapColumn + offset.x() + 4;
+ painter.fillRect(QRectF(lineX, 0, viewportRect.width() - lineX, viewportRect.height()), blendColor);
+ }
+
+ QTextBlock visibleCollapsedBlock;
+ QPointF visibleCollapsedBlockOffset;
+
+ while (block.isValid()) {
+
+ if (!block.isVisible()) {
+ block = block.next();
+ continue;
+ }
+
+ QRectF r = blockBoundingRect(block).translated(offset);
+ QTextLayout *layout = block.layout();
+
+ QTextOption option = layout->textOption();
+ if (TextEditDocumentLayout::ifdefedOut(block)) {
+ option.setFlags(option.flags() | QTextOption::SuppressColors);
+ painter.setPen(d->m_ifdefedOutFormat.foreground().color());
+ } else {
+ option.setFlags(option.flags() & ~QTextOption::SuppressColors);
+ painter.setPen(context.palette.text().color());
+ }
+ layout->setTextOption(option);
+
+ if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
+
+ int blpos = block.position();
+ int bllen = block.length();
+
+ QVector<QTextLayout::FormatRange> selections;
+ QVector<QTextLayout::FormatRange> selectionsWithText;
+
+ for (int i = 0; i < context.selections.size(); ++i) {
+ const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
+ const int selStart = range.cursor.selectionStart() - blpos;
+ const int selEnd = range.cursor.selectionEnd() - blpos;
+ if (selStart < bllen && selEnd > 0
+ && selEnd > selStart) {
+ QTextLayout::FormatRange o;
+ o.start = selStart;
+ o.length = selEnd - selStart;
+ o.format = range.format;
+ if (blockSelection && blockSelection->selectionIndex == i) {
+ o.start = qMin(blockSelection->firstColumn, bllen-1);
+ o.length = qMin(blockSelection->lastColumn, bllen-1) - o.start;
+ }
+ if (o.format.foreground().style() != Qt::NoBrush)
+ selectionsWithText.append(o);
+ else
+ selections.append(o);
+ } else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
+ && block.contains(range.cursor.position())) {
+ // for full width selections we don't require an actual selection, just
+ // a position to specify the line. that's more convenience in usage.
+ QTextLayout::FormatRange o;
+ QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
+ o.start = l.textStart();
+ o.length = l.textLength();
+ if (o.start + o.length == bllen - 1)
+ ++o.length; // include newline
+ o.format = range.format;
+ if (o.format.foreground().style() != Qt::NoBrush)
+ selectionsWithText.append(o);
+ else
+ selections.append(o);
+ }
+ }
+ d->highlightSearchResults(block, &selections);
+ selections += selectionsWithText;
+
+ bool drawCursor = ((editable || true) // we want the cursor in read-only mode
+ && context.cursorPosition >= blpos
+ && context.cursorPosition < blpos + bllen);
+
+ bool drawCursorAsBlock = drawCursor && overwriteMode() ;
+
+ if (drawCursorAsBlock) {
+ if (context.cursorPosition == blpos + bllen - 1) {
+ drawCursorAsBlock = false;
+ } else {
+ QTextLayout::FormatRange o;
+ o.start = context.cursorPosition - blpos;
+ o.length = 1;
+ o.format.setForeground(palette().base());
+ o.format.setBackground(palette().text());
+ selections.append(o);
+ }
+ }
+
+
+ layout->draw(&painter, offset, selections, er);
+
+ if ((drawCursor && !drawCursorAsBlock)
+ || (editable && context.cursorPosition < -1
+ && !layout->preeditAreaText().isEmpty())) {
+ int cpos = context.cursorPosition;
+ if (cpos < -1)
+ cpos = layout->preeditAreaPosition() - (cpos + 2);
+ else
+ cpos -= blpos;
+ layout->drawCursor(&painter, offset, cpos, cursorWidth());
+ }
+ }
+
+ offset.ry() += r.height();
+
+ if (offset.y() > viewportRect.height())
+ break;
+ block = block.next();
+ if (!block.isVisible()) {
+ if (block.blockNumber() == d->visibleCollapsedBlockNumber) {
+ visibleCollapsedBlock = block;
+ visibleCollapsedBlockOffset = offset;
+ }
+
+ // invisible blocks do have zero line count
+ block = doc->findBlockByLineNumber(block.firstLineNumber());
+ }
+
+ }
+
+ if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
+ && (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
+ painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());
+ }
+
+ //end QPlainTextEdit::paintEvent()
+
+ delete blockSelection;
+
+ offset = contentOffset();
+ block = firstVisibleBlock();
+
+ int top = (int)blockBoundingGeometry(block).translated(offset).top();
+ int bottom = top + (int)blockBoundingRect(block).height();
+
+ QTextCursor cursor = textCursor();
+ bool hasSelection = cursor.hasSelection();
+ int selectionStart = cursor.selectionStart();
+ int selectionEnd = cursor.selectionEnd();
+
+
+ while (block.isValid() && top <= e->rect().bottom()) {
+ QTextBlock nextBlock = block.next();
+ QTextBlock nextVisibleBlock = nextBlock;
+
+ if (!nextVisibleBlock.isVisible())
+ // invisible blocks do have zero line count
+ nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
+ if (block.isVisible() && bottom >= e->rect().top()) {
+ if (d->m_displaySettings.m_visualizeWhitespace) {
+ QTextLayout *layout = block.layout();
+ int lineCount = layout->lineCount();
+ if (lineCount >= 2 || !nextBlock.isValid()) {
+ painter.save();
+ painter.setPen(Qt::lightGray);
+ for (int i = 0; i < lineCount-1; ++i) { // paint line wrap indicator
+ QTextLine line = layout->lineAt(i);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ QChar visualArrow((ushort)0x21b5);
+ painter.drawText(static_cast<int>(lineRect.right()),
+ static_cast<int>(lineRect.top() + line.ascent()), visualArrow);
+ }
+ if (!nextBlock.isValid()) { // paint EOF symbol
+ QTextLine line = layout->lineAt(lineCount-1);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ int h = 4;
+ lineRect.adjust(0, 0, -1, -1);
+ QPainterPath path;
+ QPointF pos(lineRect.topRight() + QPointF(h+4, line.ascent()));
+ path.moveTo(pos);
+ path.lineTo(pos + QPointF(-h, -h));
+ path.lineTo(pos + QPointF(0, -2*h));
+ path.lineTo(pos + QPointF(h, -h));
+ path.closeSubpath();
+ painter.setBrush(painter.pen().color());
+ painter.drawPath(path);
+ }
+ painter.restore();
+ }
+ }
+
+ if (nextBlock.isValid() && !nextBlock.isVisible()) {
+
+ bool selectThis = (hasSelection
+ && nextBlock.position() >= selectionStart
+ && nextBlock.position() < selectionEnd);
+ if (selectThis) {
+ painter.save();
+ painter.setBrush(palette().highlight());
+ }
+
+ QTextLayout *layout = block.layout();
+ QTextLine line = layout->lineAt(layout->lineCount()-1);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ lineRect.adjust(0, 0, -1, -1);
+
+ QRectF collapseRect(lineRect.right() + 12,
+ lineRect.top(),
+ fontMetrics().width(QLatin1String(" {...}; ")),
+ lineRect.height());
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.translate(.5, .5);
+ painter.drawRoundedRect(collapseRect.adjusted(0, 0, 0, -1), 3, 3);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ painter.translate(-.5, -.5);
+
+ 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;
+ }
+
+
+ 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 (selectThis)
+ painter.setPen(palette().highlightedText().color());
+ painter.drawText(collapseRect, Qt::AlignCenter, replacement);
+ if (selectThis)
+ painter.restore();
+ }
+ }
+
+ block = nextVisibleBlock;
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ }
+
+ if (visibleCollapsedBlock.isValid() ) {
+ int margin = doc->documentMargin();
+ qreal maxWidth = 0;
+ qreal blockHeight = 0;
+ QTextBlock b = visibleCollapsedBlock;
+
+ while (!b.isVisible() && visibleCollapsedBlockOffset.y() + blockHeight <= e->rect().bottom()) {
+ b.setVisible(true); // make sure block bounding rect works
+ QRectF r = blockBoundingRect(b).translated(visibleCollapsedBlockOffset);
+
+ QTextLayout *layout = b.layout();
+ for (int i = layout->lineCount()-1; i >= 0; --i)
+ maxWidth = qMax(maxWidth, layout->lineAt(i).naturalTextWidth() + margin);
+
+ blockHeight += r.height();
+
+ b.setVisible(false); // restore previous state
+ b = b.next();
+ }
+
+ painter.save();
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.translate(.5, .5);
+ QColor color = blendColor;
+// color.setAlpha(240); // someone thinks alpha blending looks messy
+ painter.setBrush(color);
+ painter.drawRoundedRect(QRectF(visibleCollapsedBlockOffset.x(),
+ visibleCollapsedBlockOffset.y(),
+ maxWidth, blockHeight).adjusted(0, 0, 1, 1), 3, 3);
+ painter.restore();
+
+ QTextBlock end = b;
+ b = visibleCollapsedBlock;
+ while (b != end) {
+ b.setVisible(true); // make sure block bounding rect works
+ QRectF r = blockBoundingRect(b).translated(visibleCollapsedBlockOffset);
+ QTextLayout *layout = b.layout();
+ QVector<QTextLayout::FormatRange> selections;
+ d->highlightSearchResults(b, &selections);
+ layout->draw(&painter, visibleCollapsedBlockOffset, selections, er);
+
+ b.setVisible(false); // restore previous state
+ visibleCollapsedBlockOffset.ry() += r.height();
+ b = b.next();
+ }
+ }
+
+
+ if (d->m_visibleWrapColumn > 0) {
+ qreal lineX = fontMetrics().width('x') * d->m_visibleWrapColumn + offset.x() + 4;
+ const QColor bg = palette().base().color();
+ QColor col = (bg.value() > 128) ? Qt::black : Qt::white;
+ col.setAlpha(32);
+ painter.setPen(QPen(col, 0));
+ painter.drawLine(QPointF(lineX, 0), QPointF(lineX, viewport()->height()));
+ }
+}
+
+void BaseTextEditor::slotUpdateExtraAreaWidth()
+{
+ if (isLeftToRight())
+ setViewportMargins(extraAreaWidth(), 0, 0, 0);
+ else
+ setViewportMargins(0, 0, extraAreaWidth(), 0);
+}
+
+
+QWidget *BaseTextEditor::extraArea() const
+{
+ return d->m_extraArea;
+}
+
+int BaseTextEditor::extraAreaWidth(int *markWidthPtr) const
+{
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
+ if (!documentLayout)
+ return 0;
+
+ if (!d->m_marksVisible && documentLayout->hasMarks)
+ d->m_marksVisible = true;
+
+ int space = 0;
+ const QFontMetrics fm(d->m_extraArea->fontMetrics());
+
+ if (d->m_lineNumbersVisible) {
+ int digits = 2;
+ int max = qMax(1, blockCount());
+ while (max >= 100) {
+ max /= 10;
+ ++digits;
+ }
+ space += fm.width(QLatin1Char('9')) * digits;
+ }
+ int markWidth = 0;
+
+ if (d->m_marksVisible) {
+ markWidth += fm.lineSpacing();
+// if (documentLayout->doubleMarkCount)
+// markWidth += fm.lineSpacing() / 3;
+ space += markWidth;
+ } else {
+ space += 2;
+ }
+
+ if (markWidthPtr)
+ *markWidthPtr = markWidth;
+
+ space += 4;
+
+ if (d->m_codeFoldingVisible)
+ space += fm.lineSpacing();
+ return space;
+}
+
+void BaseTextEditor::slotModificationChanged(bool m)
+{
+ if (m)
+ return;
+
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ int oldLastSaveRevision = documentLayout->lastSaveRevision;
+ documentLayout->lastSaveRevision = doc->revision();
+
+ if (oldLastSaveRevision != documentLayout->lastSaveRevision) {
+ QTextBlock block = doc->begin();
+ while (block.isValid()) {
+ if (block.revision() < 0 || block.revision() != oldLastSaveRevision) {
+ block.setRevision(-documentLayout->lastSaveRevision - 1);
+ } else {
+ block.setRevision(documentLayout->lastSaveRevision);
+ }
+ block = block.next();
+ }
+ }
+ d->m_extraArea->update();
+}
+
+void BaseTextEditor::slotUpdateBlockNotify(const QTextBlock &block)
+{
+ static bool blockRecursion = false;
+ if (blockRecursion)
+ return;
+ if (block.previous().isValid() && block.userState() != block.previous().userState()) {
+ /* 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
+ box which now is invalid.*/
+ blockRecursion = true;
+ emit requestBlockUpdate(block.previous());
+ blockRecursion = false;
+ }
+}
+
+void BaseTextEditor::slotUpdateRequest(const QRect &r, int dy)
+{
+ if (dy)
+ d->m_extraArea->scroll(0, dy);
+ else if (r.width() > 4) { // wider than cursor width, not just cursor blinking
+ d->m_extraArea->update(0, r.y(), d->m_extraArea->width(), r.height());
+ }
+
+ if (r.contains(viewport()->rect()))
+ slotUpdateExtraAreaWidth();
+}
+
+
+void BaseTextEditor::setCollapseIndicatorAlpha(int alpha)
+{
+ d->extraAreaCollapseAlpha = alpha;
+ d->m_extraArea->update();
+}
+
+void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QPalette pal = d->m_extraArea->palette();
+ pal.setCurrentColorGroup(QPalette::Active);
+ QPainter painter(d->m_extraArea);
+ QFontMetrics fm(painter.fontMetrics());
+ int fmLineSpacing = fm.lineSpacing();
+
+ int markWidth = 0;
+ if (d->m_marksVisible)
+ markWidth += fm.lineSpacing();
+// if (documentLayout->doubleMarkCount)
+// markWidth += fm.lineSpacing() / 3;
+
+ const int collapseBoxWidth = d->m_codeFoldingVisible ? fmLineSpacing + 1: 0;
+ const int extraAreaWidth = d->m_extraArea->width() - collapseBoxWidth;
+
+ painter.fillRect(e->rect(), pal.color(QPalette::Base));
+ painter.fillRect(e->rect().intersected(QRect(0, 0, extraAreaWidth, INT_MAX)),
+ pal.color(QPalette::Background));
+
+
+ QTextBlock block = firstVisibleBlock();
+ int blockNumber = block.blockNumber();
+ int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top();
+ int bottom = top;
+
+ int extraAreaHighlightCollapseEndBlockNumber = -1;
+
+ int extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
+ if (extraAreaHighlightCollapseBlockNumber < 0) {
+ extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightFadingBlockNumber;
+ }
+
+ if (extraAreaHighlightCollapseBlockNumber >= 0 ) {
+ QTextBlock highlightBlock = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber);
+ if (highlightBlock.isValid() && highlightBlock.next().isValid() && highlightBlock.next().isVisible())
+ extraAreaHighlightCollapseEndBlockNumber = TextBlockUserData::testCollapse(highlightBlock).blockNumber();
+ else
+ extraAreaHighlightCollapseEndBlockNumber = extraAreaHighlightCollapseBlockNumber;
+ }
+
+
+ while (block.isValid() && top <= e->rect().bottom()) {
+
+ bool collapseThis = false;
+ bool collapseAfter = false;
+ bool hasClosingCollapse = false;
+
+
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ QTextBlock nextBlock = block.next();
+
+ QTextBlock nextVisibleBlock = nextBlock;
+ int nextVisibleBlockNumber = blockNumber + 1;
+
+ if (!nextVisibleBlock.isVisible()) {
+ // invisible blocks do have zero line count
+ nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
+ nextVisibleBlockNumber = nextVisibleBlock.blockNumber();
+ }
+
+ painter.setPen(pal.color(QPalette::Dark));
+
+ if (d->m_codeFoldingVisible || d->m_marksVisible) {
+ painter.save();
+ painter.setRenderHint(QPainter::Antialiasing, false);
+
+ int previousBraceDepth = block.previous().userState();
+ if (previousBraceDepth >= 0)
+ previousBraceDepth >>= 8;
+ else
+ previousBraceDepth = 0;
+
+ int braceDepth = block.userState();
+ if (!nextBlock.isVisible()) {
+ QTextBlock lastInvisibleBlock = nextVisibleBlock.previous();
+ if (!lastInvisibleBlock.isValid())
+ lastInvisibleBlock = doc->lastBlock();
+ braceDepth = lastInvisibleBlock.userState();
+ }
+ if (braceDepth >= 0)
+ braceDepth >>= 8;
+ else
+ braceDepth = 0;
+
+ if (TextBlockUserData *userData = static_cast<TextBlockUserData*>(block.userData())) {
+ if (d->m_marksVisible) {
+ int xoffset = 0;
+ foreach (ITextMark *mrk, userData->marks()) {
+ int x = 0;
+ int radius = fmLineSpacing - 1;
+ QRect r(x + xoffset, top, radius, radius);
+ mrk->icon().paint(&painter, r, Qt::AlignCenter);
+ xoffset += 2;
+ }
+ }
+
+ collapseAfter = (userData->collapseMode() == TextBlockUserData::CollapseAfter);
+ collapseThis = (userData->collapseMode() == TextBlockUserData::CollapseThis);
+ hasClosingCollapse = userData->hasClosingCollapse() && (previousBraceDepth > 0);
+ }
+
+ if (d->m_codeFoldingVisible) {
+ const QRect box(extraAreaWidth + collapseBoxWidth/4, top + collapseBoxWidth/4,
+ 2 * (collapseBoxWidth/4) + 1, 2 * (collapseBoxWidth/4) + 1);
+ const QPoint boxCenter = box.center();
+
+ QColor textColorAlpha = pal.text().color();
+ textColorAlpha.setAlpha(d->extraAreaCollapseAlpha);
+ QColor textColorInactive = pal.text().color();
+ textColorInactive.setAlpha(100);
+ QColor textColor = pal.text().color();
+ textColor.setAlpha(qMax(textColorInactive.alpha(), d->extraAreaCollapseAlpha));
+
+ const QPen pen( (blockNumber >= extraAreaHighlightCollapseBlockNumber
+ && blockNumber <= extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+ const QPen boxPen((blockNumber == extraAreaHighlightCollapseBlockNumber) ?
+ textColor : textColorInactive);
+ const QPen endPen((blockNumber == extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+ const QPen previousPen((blockNumber-1 >= extraAreaHighlightCollapseBlockNumber
+ && blockNumber-1 < extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+ const QPen nextPen((blockNumber+1 > extraAreaHighlightCollapseBlockNumber
+ && blockNumber+1 <= extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+
+ TextBlockUserData *nextBlockUserData = TextEditDocumentLayout::testUserData(nextBlock);
+
+ bool collapseNext = nextBlockUserData
+ && nextBlockUserData->collapseMode()
+ == TextBlockUserData::CollapseThis;
+
+ bool nextHasClosingCollapse = nextBlockUserData
+ && nextBlockUserData->hasClosingCollapseInside();
+
+ bool drawBox = ((collapseAfter || collapseNext) && !nextHasClosingCollapse);
+
+ if (braceDepth || (collapseNext && nextBlock.isVisible())) {
+ painter.setPen((hasClosingCollapse || !nextBlock.isVisible())? nextPen : pen);
+ painter.drawLine(boxCenter.x(), boxCenter.y(), boxCenter.x(), bottom - 1);
+ }
+
+ if (previousBraceDepth || collapseThis) {
+ painter.setPen((collapseAfter || collapseNext) ? previousPen : pen);
+ painter.drawLine(boxCenter.x(), top, boxCenter.x(), boxCenter.y());
+ }
+
+ if (drawBox) {
+ painter.setPen(boxPen);
+ painter.setBrush(pal.base());
+ painter.drawRect(box.adjusted(0, 0, -1, -1));
+ if (!nextBlock.isVisible())
+ painter.drawLine(boxCenter.x(), box.top() + 2, boxCenter.x(), box.bottom() - 2);
+ painter.drawLine(box.left() + 2, boxCenter.y(), box.right() - 2, boxCenter.y());
+ } else if (hasClosingCollapse || collapseAfter || collapseNext) {
+ painter.setPen(endPen);
+ painter.drawLine(boxCenter.x() + 1, boxCenter.y(), box.right() - 1, boxCenter.y());
+ }
+
+ }
+
+ painter.restore();
+ }
+
+
+ if (d->m_revisionsVisible && block.revision() != documentLayout->lastSaveRevision) {
+ painter.save();
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ if (block.revision() < 0)
+ painter.setPen(QPen(Qt::darkGreen, 2));
+ else
+ painter.setPen(QPen(Qt::red, 2));
+ painter.drawLine(extraAreaWidth-1, top, extraAreaWidth-1, bottom-1);
+ painter.restore();
+ }
+
+ if (d->m_lineNumbersVisible) {
+ const QString &number = QString::number(blockNumber + 1);
+ painter.drawText(markWidth, top, extraAreaWidth - markWidth - 4, fm.height(), Qt::AlignRight, number);
+ }
+
+ block = nextVisibleBlock;
+ blockNumber = nextVisibleBlockNumber;
+ }
+}
+
+void BaseTextEditor::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == d->autoScrollTimer.timerId()) {
+ const QPoint globalPos = QCursor::pos();
+ const QPoint pos = d->m_extraArea->mapFromGlobal(globalPos);
+ QRect visible = d->m_extraArea->rect();
+ verticalScrollBar()->triggerAction( pos.y() < visible.center().y() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ extraAreaMouseEvent(&ev);
+ int delta = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
+ if (delta < 7)
+ delta = 7;
+ 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();
+ viewport()->update();
+ }
+ QPlainTextEdit::timerEvent(e);
+}
+
+
+void BaseTextEditorPrivate::clearVisibleCollapsedBlock()
+{
+ if (suggestedVisibleCollapsedBlockNumber) {
+ suggestedVisibleCollapsedBlockNumber = -1;
+ collapsedBlockTimer.stop();
+ }
+ if (visibleCollapsedBlockNumber >= 0) {
+ visibleCollapsedBlockNumber = -1;
+ q->viewport()->update();
+ }
+}
+
+
+void BaseTextEditor::mouseMoveEvent(QMouseEvent *e)
+{
+ d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier);
+ if (e->buttons() == 0) {
+ QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
+ int blockNumber = collapsedBlock.next().blockNumber();
+ if (blockNumber < 0) {
+ d->clearVisibleCollapsedBlock();
+ } else if (blockNumber != d->visibleCollapsedBlockNumber) {
+ d->suggestedVisibleCollapsedBlockNumber = blockNumber;
+ d->collapsedBlockTimer.start(40, this);
+ }
+ viewport()->setCursor(collapsedBlock.isValid() ? Qt::PointingHandCursor : Qt::IBeamCursor);
+ } else {
+ QPlainTextEdit::mouseMoveEvent(e);
+ }
+ if (d->m_lastEventWasBlockSelectionEvent && d->m_inBlockSelectionMode) {
+ if (textCursor().atBlockEnd()) {
+ d->m_blockSelectionExtraX = qMax(0, e->pos().x() - cursorRect().center().x()) / fontMetrics().width(QLatin1Char('x'));
+ } else {
+ d->m_blockSelectionExtraX = 0;
+ }
+ }
+}
+
+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);
+ viewport()->setCursor(Qt::IBeamCursor);
+ }
+ }
+ QPlainTextEdit::mousePressEvent(e);
+}
+
+void BaseTextEditor::extraAreaLeaveEvent(QEvent *)
+{
+ if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
+ d->extraAreaHighlightFadingBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
+ d->extraAreaHighlightCollapseBlockNumber = -1; // missing mouse move event from Qt
+ d->extraAreaTimeLine->setDirection(QTimeLine::Backward);
+ if (d->extraAreaTimeLine->state() != QTimeLine::Running)
+ d->extraAreaTimeLine->start();
+ }
+}
+
+void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
+{
+ QTextCursor cursor = cursorForPosition(QPoint(0, e->pos().y()));
+ cursor.setPosition(cursor.block().position());
+
+ int markWidth;
+ extraAreaWidth(&markWidth);
+
+ if (e->type() == QEvent::MouseMove && e->buttons() == 0) { // mouse tracking
+ int highlightBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
+ d->extraAreaHighlightCollapseBlockNumber = -1;
+ if (TextBlockUserData::canCollapse(cursor.block())
+ && !TextBlockUserData::hasClosingCollapseInside(cursor.block().next())
+ && collapseBox(cursor.block()).contains(e->pos()))
+ d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
+
+ bool hand = (e->pos().x() <= markWidth || d->extraAreaHighlightCollapseBlockNumber >= 0);
+ if (hand != (d->m_extraArea->cursor().shape() == Qt::PointingHandCursor))
+ d->m_extraArea->setCursor(hand ? Qt::PointingHandCursor : Qt::ArrowCursor);
+
+ if (highlightBlockNumber != d->extraAreaHighlightCollapseBlockNumber) {
+ d->extraAreaTimeLine->stop();
+ d->extraAreaTimeLine->setDirection(d->extraAreaHighlightCollapseBlockNumber >= 0?
+ QTimeLine::Forward : QTimeLine::Backward);
+ if (d->extraAreaTimeLine->direction() == QTimeLine::Backward)
+ d->extraAreaHighlightFadingBlockNumber = highlightBlockNumber;
+ else
+ d->extraAreaHighlightFadingBlockNumber = -1;
+ if (d->extraAreaTimeLine->state() != QTimeLine::Running)
+ d->extraAreaTimeLine->start();
+ }
+ }
+
+
+ if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
+ if (e->button() == Qt::LeftButton) {
+ if (TextBlockUserData::canCollapse(cursor.block())
+ && !TextBlockUserData::hasClosingCollapseInside(cursor.block().next())
+ && collapseBox(cursor.block()).contains(e->pos())) {
+ setTextCursor(cursor);
+ toggleBlockVisible(cursor.block());
+ } else if (e->pos().x() > markWidth) {
+ QTextCursor selection = cursor;
+ selection.setVisualNavigation(true);
+ d->extraAreaSelectionAnchorBlockNumber = selection.blockNumber();
+ selection.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ selection.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+ setTextCursor(selection);
+ } else {
+ d->extraAreaToggleMarkBlockNumber = cursor.blockNumber();
+ }
+ }
+ } else if (d->extraAreaSelectionAnchorBlockNumber >= 0) {
+ QTextCursor selection = cursor;
+ selection.setVisualNavigation(true);
+ if (e->type() == QEvent::MouseMove) {
+ QTextBlock anchorBlock = document()->findBlockByNumber(d->extraAreaSelectionAnchorBlockNumber);
+ selection.setPosition(anchorBlock.position());
+ if (cursor.blockNumber() < d->extraAreaSelectionAnchorBlockNumber) {
+ selection.movePosition(QTextCursor::EndOfBlock);
+ selection.movePosition(QTextCursor::Right);
+ }
+ selection.setPosition(cursor.block().position(), QTextCursor::KeepAnchor);
+ if (cursor.blockNumber() >= d->extraAreaSelectionAnchorBlockNumber) {
+ selection.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ selection.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+ }
+
+ if (e->pos().y() >= 0 && e->pos().y() <= d->m_extraArea->height())
+ d->autoScrollTimer.stop();
+ else if (!d->autoScrollTimer.isActive())
+ d->autoScrollTimer.start(100, this);
+
+ } else {
+ d->autoScrollTimer.stop();
+ d->extraAreaSelectionAnchorBlockNumber = -1;
+ return;
+ }
+ setTextCursor(selection);
+ } else if (d->extraAreaToggleMarkBlockNumber >= 0 && d->m_marksVisible && d->m_requestMarkEnabled) {
+ if (e->type() == QEvent::MouseButtonRelease && e->button() == Qt::LeftButton) {
+ int n = d->extraAreaToggleMarkBlockNumber;
+ d->extraAreaToggleMarkBlockNumber = -1;
+ if (cursor.blockNumber() == n) {
+ int line = n + 1;
+ emit markRequested(editableInterface(), line);
+ }
+ }
+ }
+}
+
+void BaseTextEditor::slotCursorPositionChanged()
+{
+ QList<QTextEdit::ExtraSelection> extraSelections;
+
+ if (d->m_highlightCurrentLine) {
+ QTextEdit::ExtraSelection sel;
+ sel.format.setBackground(d->m_currentLineFormat.background());
+ sel.format.setProperty(QTextFormat::FullWidthSelection, true);
+ sel.cursor = textCursor();
+ sel.cursor.clearSelection();
+ extraSelections.append(sel);
+ }
+
+ if (d->m_parenthesesMatchingEnabled)
+ d->m_parenthesesMatchingTimer->start(50);
+
+ d->m_extraSelections = extraSelections;
+ setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections);
+}
+
+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());
+
+}
+
+
+void BaseTextEditor::ensureCursorVisible()
+{
+ QTextBlock block = textCursor().block();
+ if (!block.isVisible()) {
+ while (!block.isVisible() && block.previous().isValid())
+ block = block.previous();
+ toggleBlockVisible(block);
+ }
+ QPlainTextEdit::ensureCursorVisible();
+}
+
+void BaseTextEditor::toggleBlockVisible(const QTextBlock &block)
+{
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ bool visible = block.next().isVisible();
+ TextBlockUserData::doCollapse(block, !visible);
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+}
+
+
+const TabSettings &BaseTextEditor::tabSettings() const
+{
+ return d->m_document->tabSettings();
+}
+
+const DisplaySettings &BaseTextEditor::displaySettings() const
+{
+ return d->m_displaySettings;
+}
+
+
+
+void BaseTextEditor::indentOrUnindent(bool doIndent)
+{
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+
+ int pos = cursor.position();
+ const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings();
+
+
+ QTextDocument *doc = document();
+ if (!cursor.hasSelection()
+ || (doc->findBlock(cursor.selectionStart()) == doc->findBlock(cursor.selectionEnd()) )) {
+ cursor.removeSelectedText();
+ QTextBlock block = cursor.block();
+ QString text = block.text();
+ int indentPosition = (cursor.position() - block.position());;
+ int spaces = tabSettings.spacesLeftFromPosition(text, indentPosition);
+ int startColumn = tabSettings.columnAt(text, indentPosition - spaces);
+ int targetColumn = tabSettings.indentedColumn(tabSettings.columnAt(text, indentPosition), doIndent);
+
+ cursor.setPosition(block.position() + indentPosition);
+ cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ cursor.insertText(tabSettings.indentationString(startColumn, targetColumn));
+ } else {
+ int anchor = cursor.anchor();
+ int start = qMin(anchor, pos);
+ int end = qMax(anchor, pos);
+
+ QTextBlock startBlock = doc->findBlock(start);
+ QTextBlock endBlock = doc->findBlock(end-1).next();
+
+ for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
+ QString text = block.text();
+ int indentPosition = tabSettings.lineIndentPosition(text);
+ if (!doIndent && !indentPosition)
+ indentPosition = tabSettings.firstNonSpace(text);
+ int targetColumn = tabSettings.indentedColumn(tabSettings.columnAt(text, indentPosition), doIndent);
+ cursor.setPosition(block.position() + indentPosition);
+ cursor.insertText(tabSettings.indentationString(0, targetColumn));
+ cursor.setPosition(block.position());
+ cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ }
+ }
+
+ cursor.endEditBlock();
+}
+
+void BaseTextEditor::handleHomeKey(bool anchor)
+{
+ QTextCursor cursor = textCursor();
+ QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
+
+ if (anchor)
+ mode = QTextCursor::KeepAnchor;
+
+ const int initpos = cursor.position();
+ int pos = cursor.block().position();
+ QChar character = characterAt(pos);
+ const QLatin1Char tab = QLatin1Char('\t');
+
+ while (character == tab || character.category() == QChar::Separator_Space) {
+ ++pos;
+ character = characterAt(pos);
+ }
+
+ // Go to the start of the block when we're already at the start of the text
+ if (pos == initpos)
+ pos = cursor.block().position();
+
+ cursor.setPosition(pos, mode);
+ setTextCursor(cursor);
+}
+
+void BaseTextEditor::handleBackspaceKey()
+{
+ QTextCursor cursor = textCursor();
+ Q_ASSERT(!cursor.hasSelection());
+
+ const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings();
+ QTextBlock currentBlock = cursor.block();
+ int positionInBlock = cursor.position() - currentBlock.position();
+ const QString blockText = currentBlock.text();
+ if (cursor.atBlockStart() || tabSettings.firstNonSpace(blockText) < positionInBlock) {
+ cursor.deletePreviousChar();
+ return;
+ }
+
+ int previousIndent = 0;
+ const int indent = tabSettings.columnAt(blockText, positionInBlock);
+
+ for (QTextBlock previousNonEmptyBlock = currentBlock.previous();
+ previousNonEmptyBlock.isValid();
+ previousNonEmptyBlock = previousNonEmptyBlock.previous()) {
+ QString previousNonEmptyBlockText = previousNonEmptyBlock.text();
+ if (previousNonEmptyBlockText.trimmed().isEmpty())
+ continue;
+ previousIndent = tabSettings.columnAt(previousNonEmptyBlockText,
+ tabSettings.firstNonSpace(previousNonEmptyBlockText));
+ if (previousIndent < indent)
+ break;
+ }
+
+ if (previousIndent >= indent)
+ previousIndent = 0;
+
+ cursor.beginEditBlock();
+ cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor);
+ cursor.insertText(tabSettings.indentationString(0, previousIndent));
+ cursor.endEditBlock();
+}
+
+
+void BaseTextEditor::format()
+{
+ QTextCursor cursor = textCursor();
+ indent(document(), cursor, QChar::Null);
+}
+
+void BaseTextEditor::unCommentSelection()
+{
+}
+
+void BaseTextEditor::setTabSettings(const TabSettings &ts)
+{
+ d->m_document->setTabSettings(ts);
+ int charWidth = QFontMetrics(font()).width(QChar(' '));
+ setTabStopWidth(charWidth * ts.m_tabSize);
+}
+
+void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds)
+{
+ setLineWrapMode(ds.m_textWrapping ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap);
+ setLineNumbersVisible(ds.m_displayLineNumbers);
+ setVisibleWrapColumn(ds.m_showWrapColumn ? ds.m_wrapColumn : 0);
+ setCodeFoldingVisible(ds.m_displayFoldingMarkers);
+ setHighlightCurrentLine(ds.m_highlightCurrentLine);
+
+ if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) {
+ if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter())
+ highlighter->rehighlight();
+ QTextOption option = document()->defaultTextOption();
+ if (ds.m_visualizeWhitespace)
+ option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
+ else
+ option.setFlags(option.flags() & ~QTextOption::ShowTabsAndSpaces);
+ option.setFlags(option.flags() | QTextOption::AddSpaceForLineAndParagraphSeparators);
+ document()->setDefaultTextOption(option);
+ }
+
+ d->m_displaySettings = ds;
+}
+
+
+void BaseTextEditor::wheelEvent(QWheelEvent *e)
+{
+ d->clearVisibleCollapsedBlock();
+ if (e->modifiers() & Qt::ControlModifier) {
+ const int delta = e->delta();
+ if (delta < 0)
+ zoomOut();
+ else if (delta > 0)
+ zoomIn();
+ return;
+ }
+ QPlainTextEdit::wheelEvent(e);
+}
+
+void BaseTextEditor::zoomIn(int range)
+{
+ d->clearVisibleCollapsedBlock();
+ QFont f = font();
+ const int newSize = f.pointSize() + range;
+ if (newSize <= 0)
+ return;
+ f.setPointSize(newSize);
+ setFont(f);
+}
+
+void BaseTextEditor::zoomOut(int range)
+{
+ zoomIn(-range);
+}
+
+bool BaseTextEditor::isElectricCharacter(const QChar &) const
+{
+ return false;
+}
+
+void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar)
+{
+}
+
+void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
+{
+ if (cursor.hasSelection()) {
+ QTextBlock block = doc->findBlock(qMin(cursor.selectionStart(), cursor.selectionEnd()));
+ const QTextBlock end = doc->findBlock(qMax(cursor.selectionStart(), cursor.selectionEnd())).next();
+ do {
+ indentBlock(doc, block, typedChar);
+ block = block.next();
+ } while (block.isValid() && block != end);
+ } else {
+ indentBlock(doc, cursor.block(), typedChar);
+ }
+}
+
+void BaseTextEditorPrivate::updateMarksBlock(const QTextBlock &block)
+{
+ if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
+ foreach (ITextMark *mrk, userData->marks()) {
+ mrk->updateBlock(block);
+ }
+}
+
+void BaseTextEditorPrivate::updateMarksLineNumber()
+{
+ QTextDocument *doc = q->document();
+ QTextBlock block = doc->begin();
+ int blockNumber = 0;
+ while (block.isValid()) {
+ if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
+ foreach (ITextMark *mrk, userData->marks()) {
+ mrk->updateLineNumber(blockNumber + 1);
+ }
+ block = block.next();
+ ++blockNumber;
+ }
+}
+
+void BaseTextEditor::markBlocksAsChanged(QList<int> blockNumbers) {
+ QTextBlock block = document()->begin();
+ while (block.isValid()) {
+ if (block.revision() < 0)
+ block.setRevision(-block.revision() - 1);
+ block = block.next();
+ }
+ foreach (const int blockNumber, blockNumbers) {
+ QTextBlock block = document()->findBlockByNumber(blockNumber);
+ if (block.isValid())
+ block.setRevision(-block.revision() - 1);
+ }
+}
+
+
+
+TextBlockUserData::MatchType TextBlockUserData::checkOpenParenthesis(QTextCursor *cursor, QChar c)
+{
+ if (!TextEditDocumentLayout::hasParentheses(cursor->block()))
+ return NoMatch;
+
+ Parentheses parenList = TextEditDocumentLayout::parentheses(cursor->block());
+ Parenthesis openParen, closedParen;
+ QTextBlock closedParenParag = cursor->block();
+
+ const int cursorPos = cursor->position() - closedParenParag.position();
+ int i = 0;
+ int ignore = 0;
+ bool foundOpen = false;
+ for (;;) {
+ if (!foundOpen) {
+ if (i >= parenList.count())
+ return NoMatch;
+ openParen = parenList.at(i);
+ if (openParen.pos != cursorPos) {
+ ++i;
+ continue;
+ } else {
+ foundOpen = true;
+ ++i;
+ }
+ }
+
+ if (i >= parenList.count()) {
+ for (;;) {
+ closedParenParag = closedParenParag.next();
+ if (!closedParenParag.isValid())
+ return NoMatch;
+ if (TextEditDocumentLayout::hasParentheses(closedParenParag)) {
+ parenList = TextEditDocumentLayout::parentheses(closedParenParag);
+ break;
+ }
+ }
+ i = 0;
+ }
+
+ closedParen = parenList.at(i);
+ if (closedParen.type == Parenthesis::Opened) {
+ ignore++;
+ ++i;
+ continue;
+ } else {
+ if (ignore > 0) {
+ ignore--;
+ ++i;
+ continue;
+ }
+
+ cursor->clearSelection();
+ cursor->setPosition(closedParenParag.position() + closedParen.pos + 1, QTextCursor::KeepAnchor);
+
+ if ((c == QLatin1Char('{') && closedParen.chr != QLatin1Char('}'))
+ || (c == QLatin1Char('(') && closedParen.chr != QLatin1Char(')'))
+ || (c == QLatin1Char('[') && closedParen.chr != QLatin1Char(']'))
+ || (c == QLatin1Char('+') && closedParen.chr != QLatin1Char('-'))
+ )
+ return Mismatch;
+
+ return Match;
+ }
+ }
+}
+
+TextBlockUserData::MatchType TextBlockUserData::checkClosedParenthesis(QTextCursor *cursor, QChar c)
+{
+ if (!TextEditDocumentLayout::hasParentheses(cursor->block()))
+ return NoMatch;
+
+ Parentheses parenList = TextEditDocumentLayout::parentheses(cursor->block());
+ Parenthesis openParen, closedParen;
+ QTextBlock openParenParag = cursor->block();
+
+ const int cursorPos = cursor->position() - openParenParag.position();
+ int i = parenList.count() - 1;
+ int ignore = 0;
+ bool foundClosed = false;
+ for (;;) {
+ if (!foundClosed) {
+ if (i < 0)
+ return NoMatch;
+ closedParen = parenList.at(i);
+ if (closedParen.pos != cursorPos - 1) {
+ --i;
+ continue;
+ } else {
+ foundClosed = true;
+ --i;
+ }
+ }
+
+ if (i < 0) {
+ for (;;) {
+ openParenParag = openParenParag.previous();
+ if (!openParenParag.isValid())
+ return NoMatch;
+
+ if (TextEditDocumentLayout::hasParentheses(openParenParag)) {
+ parenList = TextEditDocumentLayout::parentheses(openParenParag);
+ break;
+ }
+ }
+ i = parenList.count() - 1;
+ }
+
+ openParen = parenList.at(i);
+ if (openParen.type == Parenthesis::Closed) {
+ ignore++;
+ --i;
+ continue;
+ } else {
+ if (ignore > 0) {
+ ignore--;
+ --i;
+ continue;
+ }
+
+ cursor->clearSelection();
+ cursor->setPosition(openParenParag.position() + openParen.pos, QTextCursor::KeepAnchor);
+
+ if ((c == '}' && openParen.chr != '{') ||
+ (c == ')' && openParen.chr != '(') ||
+ (c == ']' && openParen.chr != '[') ||
+ (c == '-' && openParen.chr != '+'))
+ return Mismatch;
+
+ return Match;
+ }
+ }
+}
+
+TextBlockUserData::MatchType TextBlockUserData::matchCursorBackward(QTextCursor *cursor)
+{
+ cursor->clearSelection();
+ const QTextBlock block = cursor->block();
+
+ if (!TextEditDocumentLayout::hasParentheses(block))
+ return NoMatch;
+
+ const int relPos = cursor->position() - block.position();
+
+ Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
+ const Parentheses::const_iterator cend = parentheses.constEnd();
+ for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
+ const Parenthesis &paren = *it;
+ if (paren.pos == relPos - 1
+ && paren.type == Parenthesis::Closed) {
+ return checkClosedParenthesis(cursor, paren.chr);
+ }
+ }
+ return NoMatch;
+}
+
+TextBlockUserData::MatchType TextBlockUserData::matchCursorForward(QTextCursor *cursor)
+{
+ cursor->clearSelection();
+ const QTextBlock block = cursor->block();
+
+ if (!TextEditDocumentLayout::hasParentheses(block))
+ return NoMatch;
+
+ const int relPos = cursor->position() - block.position();
+
+ Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
+ const Parentheses::const_iterator cend = parentheses.constEnd();
+ for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
+ const Parenthesis &paren = *it;
+ if (paren.pos == relPos
+ && paren.type == Parenthesis::Opened) {
+ return checkOpenParenthesis(cursor, paren.chr);
+ }
+ }
+ return NoMatch;
+}
+
+
+void BaseTextEditor::highlightSearchResults(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ if (d->m_searchExpr.pattern() == txt)
+ return;
+ d->m_searchExpr.setPattern(txt);
+ d->m_searchExpr.setPatternSyntax(QRegExp::FixedString);
+ d->m_searchExpr.setCaseSensitivity((findFlags & QTextDocument::FindCaseSensitively) ?
+ Qt::CaseSensitive : Qt::CaseInsensitive);
+ d->m_findFlags = findFlags;
+ viewport()->update();
+}
+
+
+void BaseTextEditor::setFindScope(const QTextCursor &scope)
+{
+ if (scope.isNull() != d->m_findScope.isNull()) {
+ d->m_findScope = scope;
+ viewport()->update();
+ }
+}
+
+void BaseTextEditor::_q_matchParentheses()
+{
+ if (isReadOnly())
+ return;
+
+ QTextCursor backwardMatch = textCursor();
+ QTextCursor forwardMatch = textCursor();
+ const TextBlockUserData::MatchType backwardMatchType = TextBlockUserData::matchCursorBackward(&backwardMatch);
+ const TextBlockUserData::MatchType forwardMatchType = TextBlockUserData::matchCursorForward(&forwardMatch);
+
+ if (backwardMatchType == TextBlockUserData::NoMatch && forwardMatchType == TextBlockUserData::NoMatch)
+ return;
+
+ QList<QTextEdit::ExtraSelection> extraSelections = d->m_extraSelections;
+
+ if (backwardMatch.hasSelection()) {
+ QTextEdit::ExtraSelection sel;
+ if (backwardMatchType == TextBlockUserData::Mismatch) {
+ sel.cursor = backwardMatch;
+ sel.format = d->m_mismatchFormat;
+ } else {
+
+ if (d->m_formatRange) {
+ sel.cursor = backwardMatch;
+ sel.format = d->m_rangeFormat;
+ extraSelections.append(sel);
+ }
+
+ sel.cursor = backwardMatch;
+ sel.format = d->m_matchFormat;
+
+ sel.cursor.setPosition(backwardMatch.selectionStart());
+ sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ extraSelections.append(sel);
+
+ sel.cursor.setPosition(backwardMatch.selectionEnd());
+ sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ }
+ extraSelections.append(sel);
+ }
+
+ if (forwardMatch.hasSelection()) {
+ QTextEdit::ExtraSelection sel;
+ if (forwardMatchType == TextBlockUserData::Mismatch) {
+ sel.cursor = forwardMatch;
+ sel.format = d->m_mismatchFormat;
+ } else {
+
+ if (d->m_formatRange) {
+ sel.cursor = forwardMatch;
+ sel.format = d->m_rangeFormat;
+ extraSelections.append(sel);
+ }
+
+ sel.cursor = forwardMatch;
+ sel.format = d->m_matchFormat;
+
+ sel.cursor.setPosition(forwardMatch.selectionStart());
+ sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ extraSelections.append(sel);
+
+ sel.cursor.setPosition(forwardMatch.selectionEnd());
+ sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ }
+ extraSelections.append(sel);
+ }
+ d->m_extraSelections = extraSelections;
+ setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections);
+}
+
+void BaseTextEditor::setActionHack(QObject *hack)
+{
+ d->m_actionHack = hack;
+}
+
+QObject *BaseTextEditor::actionHack() const
+{
+ return d->m_actionHack;
+}
+
+void BaseTextEditor::changeEvent(QEvent *e)
+{
+ QPlainTextEdit::changeEvent(e);
+ if (e->type() == QEvent::ApplicationFontChange
+ || e->type() == QEvent::FontChange) {
+ if (d->m_extraArea) {
+ QFont f = d->m_extraArea->font();
+ f.setPointSize(font().pointSize());
+ d->m_extraArea->setFont(f);
+ slotUpdateExtraAreaWidth();
+ d->m_extraArea->update();
+ }
+ }
+}
+
+// shift+del
+void BaseTextEditor::deleteLine()
+{
+ QTextCursor cursor = textCursor();
+ if (!cursor.hasSelection()) {
+ const QTextBlock &block = cursor.block();
+ if (block.next().isValid()) {
+ cursor.setPosition(block.position());
+ cursor.setPosition(block.next().position(), QTextCursor::KeepAnchor);
+ } else {
+ cursor.movePosition(QTextCursor::EndOfBlock);
+ cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ }
+ setTextCursor(cursor);
+ }
+ cut();
+}
+
+void BaseTextEditor::setExtraExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
+{
+ d->m_extraExtraSelections = selections;
+ setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections);
+}
+
+QList<QTextEdit::ExtraSelection> BaseTextEditor::extraExtraSelections() const
+{
+ return d->m_extraExtraSelections;
+}
+
+
+// the blocks list must be sorted
+void BaseTextEditor::setIfdefedOutBlocks(const QList<BaseTextEditor::BlockRange> &blocks)
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ bool needUpdate = false;
+
+ QTextBlock block = doc->firstBlock();
+
+ int rangeNumber = 0;
+ while (block.isValid()) {
+ if (rangeNumber < blocks.size()) {
+ const BlockRange &range = blocks.at(rangeNumber);
+
+ if (block.position() >= range.first && (block.position() <= range.last || !range.last)) {
+ needUpdate += TextEditDocumentLayout::setIfdefedOut(block);
+ } else {
+ needUpdate += TextEditDocumentLayout::clearIfdefedOut(block);
+ }
+ if (block.contains(range.last))
+ ++rangeNumber;
+ } else {
+ needUpdate |= TextEditDocumentLayout::clearIfdefedOut(block);
+ }
+
+ block = block.next();
+ }
+
+ if (needUpdate)
+ documentLayout->requestUpdate();
+}
+
+
+void BaseTextEditorPrivate::moveCursorVisible()
+{
+ QTextCursor cursor = q->textCursor();
+ if (!cursor.block().isVisible()) {
+ cursor.setVisualNavigation(true);
+ cursor.movePosition(QTextCursor::PreviousBlock);
+ q->setTextCursor(cursor);
+ }
+ q->ensureCursorVisible();
+}
+
+void BaseTextEditor::collapse()
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ QTextBlock block = textCursor().block();
+ while (block.isValid()) {
+ if (TextBlockUserData::canCollapse(block)) {
+ if ((block.next().userState()) >> 8 == (textCursor().block().userState() >> 8))
+ break;
+ }
+ block = block.previous();
+ }
+ if (block.isValid()) {
+ TextBlockUserData::doCollapse(block, false);
+ d->moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+ }
+}
+
+void BaseTextEditor::expand()
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ QTextBlock block = textCursor().block();
+ while (block.isValid() && !block.isVisible())
+ block = block.previous();
+ TextBlockUserData::doCollapse(block, true);
+ d->moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+}
+
+void BaseTextEditor::unCollapseAll()
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QTextBlock block = doc->firstBlock();
+ bool makeVisible = true;
+ while (block.isValid()) {
+ if (block.isVisible() && TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
+ makeVisible = false;
+ break;
+ }
+ block = block.next();
+ }
+
+ block = doc->firstBlock();
+
+ while (block.isValid()) {
+ if (TextBlockUserData::canCollapse(block))
+ TextBlockUserData::doCollapse(block, makeVisible);
+ block = block.next();
+
+ }
+
+ d->moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+}
+
+void BaseTextEditor::setTextCodec(QTextCodec *codec)
+{
+ baseTextDocument()->setCodec(codec);
+}
+
+QTextCodec *BaseTextEditor::textCodec() const
+{
+ return baseTextDocument()->codec();
+}
+
+void BaseTextEditor::setReadOnly(bool b)
+{
+ QPlainTextEdit::setReadOnly(b);
+ if (b)
+ setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard);
+}
+
+void BaseTextEditor::cut()
+{
+ if (d->m_inBlockSelectionMode) {
+ copy();
+ d->removeBlockSelection();
+ return;
+ }
+ QPlainTextEdit::cut();
+}
+
+QMimeData *BaseTextEditor::createMimeDataFromSelection() const
+{
+ if (d->m_inBlockSelectionMode) {
+ QMimeData *mimeData = new QMimeData;
+ QString text = d->copyBlockSelection();
+ mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.blocktext"), text.toUtf8());
+ mimeData->setText(text); // for exchangeability
+ return mimeData;
+ }
+ return QPlainTextEdit::createMimeDataFromSelection();
+}
+
+bool BaseTextEditor::canInsertFromMimeData(const QMimeData *source) const
+{
+ return QPlainTextEdit::canInsertFromMimeData(source);
+}
+
+void BaseTextEditor::insertFromMimeData(const QMimeData *source)
+{
+ if (!isReadOnly() && source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.blocktext"))) {
+ QString text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.blocktext")));
+ if (text.isEmpty())
+ return;
+ QStringList lines = text.split(QLatin1Char('\n'));
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+ int initialCursorPosition = cursor.position();
+ int column = cursor.position() - cursor.block().position();
+ cursor.insertText(lines.first());
+ for (int i = 1; i < lines.count(); ++i) {
+ QTextBlock next = cursor.block().next();
+ if (next.isValid()) {
+ cursor.setPosition(next.position() + qMin(column, next.length()-1));
+ } else {
+ cursor.movePosition(QTextCursor::EndOfBlock);
+ cursor.insertBlock();
+ }
+
+ int actualColumn = cursor.position() - cursor.block().position();
+ if (actualColumn < column)
+ cursor.insertText(QString(column - actualColumn, QLatin1Char(' ')));
+ cursor.insertText(lines.at(i));
+ }
+ cursor.setPosition(initialCursorPosition);
+ cursor.endEditBlock();
+ setTextCursor(cursor);
+ ensureCursorVisible();
+ return;
+ }
+ QPlainTextEdit::insertFromMimeData(source);
+}
+
+BaseTextEditorEditable::BaseTextEditorEditable(BaseTextEditor *editor)
+ : e(editor)
+{
+#ifndef TEXTEDITOR_STANDALONE
+ using namespace Find;
+ Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
+ BaseTextFind *baseTextFind = new BaseTextFind(editor);
+ connect(baseTextFind, SIGNAL(highlightAll(QString, QTextDocument::FindFlags)),
+ editor, SLOT(highlightSearchResults(QString, QTextDocument::FindFlags)));
+ connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor)), editor, SLOT(setFindScope(QTextCursor)));
+ aggregate->add(baseTextFind);
+ aggregate->add(editor);
+#endif
+
+ m_cursorPositionLabel = new Core::Utils::LineColumnLabel;
+
+ QHBoxLayout *l = new QHBoxLayout;
+ QWidget *w = new QWidget;
+ l->setMargin(0);
+ l->setContentsMargins(0, 0, 5, 0);
+ l->addStretch(1);
+ l->addWidget(m_cursorPositionLabel);
+ w->setLayout(l);
+
+ m_toolBar = new QToolBar;
+ m_toolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_toolBar->addWidget(w);
+
+ connect(editor, SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition()));
+}
+
+BaseTextEditorEditable::~BaseTextEditorEditable()
+{
+ delete m_toolBar;
+ delete e;
+}
+
+QToolBar *BaseTextEditorEditable::toolBar()
+{
+ return m_toolBar;
+}
+
+int BaseTextEditorEditable::find(const QString &) const
+{
+ return 0;
+}
+
+int BaseTextEditorEditable::currentLine() const
+{
+ return e->textCursor().blockNumber() + 1;
+}
+
+int BaseTextEditorEditable::currentColumn() const
+{
+ QTextCursor cursor = e->textCursor();
+ return cursor.position() - cursor.block().position() + 1;
+}
+
+QRect BaseTextEditorEditable::cursorRect(int pos) const
+{
+ QTextCursor tc = e->textCursor();
+ if (pos >= 0)
+ tc.setPosition(pos);
+ QRect result = e->cursorRect(tc);
+ result.moveTo(e->viewport()->mapToGlobal(result.topLeft()));
+ return result;
+}
+
+QString BaseTextEditorEditable::contents() const
+{
+ return e->toPlainText();
+}
+
+QString BaseTextEditorEditable::selectedText() const
+{
+ if (e->textCursor().hasSelection())
+ return e->textCursor().selectedText();
+ return QString();
+}
+
+QString BaseTextEditorEditable::textAt(int pos, int length) const
+{
+ QTextCursor c = e->textCursor();
+
+ if (pos < 0)
+ pos = 0;
+ c.movePosition(QTextCursor::End);
+ if (pos + length > c.position())
+ length = c.position() - pos;
+
+ c.setPosition(pos);
+ c.setPosition(pos + length, QTextCursor::KeepAnchor);
+
+ return c.selectedText();
+}
+
+void BaseTextEditorEditable::remove(int length)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
+ tc.removeSelectedText();
+}
+
+void BaseTextEditorEditable::insert(const QString &string)
+{
+ QTextCursor tc = e->textCursor();
+ tc.insertText(string);
+}
+
+void BaseTextEditorEditable::replace(int length, const QString &string)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
+ tc.insertText(string);
+}
+
+void BaseTextEditorEditable::setCurPos(int pos)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(pos);
+ e->setTextCursor(tc);
+}
+
+void BaseTextEditorEditable::select(int toPos)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(toPos, QTextCursor::KeepAnchor);
+ e->setTextCursor(tc);
+}
+
+void BaseTextEditorEditable::updateCursorPosition()
+{
+ const QTextCursor cursor = e->textCursor();
+ const QTextBlock block = cursor.block();
+ const int line = block.blockNumber() + 1;
+ const int column = cursor.position() - block.position() + 1;
+ m_cursorPositionLabel->setText(QString("Line: %1, Col: %2").arg(line).arg(column),
+ QString("Line: %1, Col: 999").arg(e->blockCount()));
+ m_contextHelpId.clear();
+
+ if (!block.isVisible())
+ e->ensureCursorVisible();
+
+}
+
+QString BaseTextEditorEditable::contextHelpId() const
+{
+ if (m_contextHelpId.isEmpty())
+ emit const_cast<BaseTextEditorEditable*>(this)->contextHelpIdRequested(e->editableInterface(),
+ e->textCursor().position());
+ return m_contextHelpId;
+}
+
+
+TextBlockUserData::~TextBlockUserData()
+{
+ TextMarks marks = m_marks;
+ m_marks.clear();
+ foreach (ITextMark *mrk, marks) {
+ mrk->removedFromEditor();
+ }
+}
+
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
new file mode 100644
index 0000000000..f41e26b2b0
--- /dev/null
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -0,0 +1,513 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTEDITOR_H
+#define BASETEXTEDITOR_H
+
+#include "displaysettings.h"
+#include "tabsettings.h"
+#include "itexteditable.h"
+
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QLabel>
+#include <QtGui/QKeyEvent>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QTextCharFormat;
+class QToolBar;
+QT_END_NAMESPACE
+
+namespace Core {
+ namespace Utils {
+ class LineColumnLabel;
+ }
+}
+
+namespace TextEditor {
+
+namespace Internal {
+ class BaseTextEditorPrivate;
+}
+
+class ITextMark;
+class ITextMarkable;
+
+class TextEditorActionHandler;
+class BaseTextDocument;
+class FontSettings;
+struct StorageSettings;
+
+struct Parenthesis;
+typedef QVector<Parenthesis> Parentheses;
+struct TEXTEDITOR_EXPORT Parenthesis
+{
+ enum Type { Opened, Closed };
+
+ inline Parenthesis() : type(Opened), pos(-1) {}
+ inline Parenthesis(Type t, QChar c, int position)
+ : type(t), chr(c), pos(position) {}
+ 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);
+};
+
+
+
+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) {}
+ ~TextBlockUserData();
+
+ inline TextMarks marks() const { return m_marks; }
+ inline void addMark(ITextMark *mark) { m_marks += mark; }
+ inline bool removeMark(ITextMark *mark) { return m_marks.removeAll(mark); }
+ inline bool hasMark(ITextMark *mark) const { return m_marks.contains(mark); }
+ 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 setParentheses(const Parentheses &parentheses) { m_parentheses = parentheses; }
+ inline void clearParentheses() { m_parentheses.clear(); }
+ inline const Parentheses &parentheses() const { return m_parentheses; }
+ inline bool hasParentheses() const { return !m_parentheses.isEmpty(); }
+
+ inline bool setIfdefedOut() { bool result = m_ifdefedOut; m_ifdefedOut = true; return !result; }
+ 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;
+ }
+ return data;
+ }
+
+ 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() const;
+
+ enum MatchType { NoMatch, Match, Mismatch };
+ static MatchType checkOpenParenthesis(QTextCursor *cursor, QChar c);
+ static MatchType checkClosedParenthesis(QTextCursor *cursor, QChar c);
+ static MatchType matchCursorBackward(QTextCursor *cursor);
+ static MatchType matchCursorForward(QTextCursor *cursor);
+
+
+private:
+ TextMarks m_marks;
+ uint m_collapseIncludesClosure : 1;
+ uint m_collapseMode : 4;
+ uint m_closingCollapseMode : 4;
+ uint m_collapsed : 1;
+ uint m_ifdefedOut : 1;
+ Parentheses m_parentheses;
+};
+
+
+class TEXTEDITOR_EXPORT TextEditDocumentLayout : public QPlainTextDocumentLayout
+{
+ Q_OBJECT
+
+public:
+ TextEditDocumentLayout(QTextDocument *doc);
+ ~TextEditDocumentLayout();
+
+ QRectF blockBoundingRect(const QTextBlock &block) const;
+
+ static void setParentheses(const QTextBlock &block, const Parentheses &parentheses);
+ static void clearParentheses(const QTextBlock &block) { setParentheses(block, Parentheses());}
+ static Parentheses parentheses(const QTextBlock &block);
+ static bool hasParentheses(const QTextBlock &block);
+ static bool setIfdefedOut(const QTextBlock &block);
+ static bool clearIfdefedOut(const QTextBlock &block);
+ static bool ifdefedOut(const QTextBlock &block);
+
+ static TextBlockUserData *testUserData(const QTextBlock &block) {
+ return static_cast<TextBlockUserData*>(block.userData());
+ }
+ static TextBlockUserData *userData(const QTextBlock &block) {
+ TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
+ if (!data && block.isValid())
+ const_cast<QTextBlock &>(block).setUserData((data = new TextBlockUserData));
+ return data;
+ }
+
+
+ void emitDocumentSizeChanged() { emit documentSizeChanged(documentSize()); }
+ int lastSaveRevision;
+ bool hasMarks;
+};
+
+
+class BaseTextEditorEditable;
+
+class TEXTEDITOR_EXPORT BaseTextEditor
+ : public QPlainTextEdit
+{
+ Q_OBJECT
+
+public:
+ BaseTextEditor(QWidget *parent);
+ ~BaseTextEditor();
+
+ static ITextEditor *openEditorAt(const QString &fileName, int line, int column = 0);
+
+ // EditorInterface
+ Core::IFile * file();
+ bool createNew(const QString &contents);
+ bool open(const QString &fileName = QString());
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+ QString displayName() const;
+
+ // ITextEditor
+
+ void gotoLine(int line, int column = 0);
+
+ int position(
+ ITextEditor::PositionOperation posOp = ITextEditor::Current
+ , int at = -1) const;
+ void convertPosition(int pos, int *line, int *column) const;
+
+ ITextEditable *editableInterface() const;
+ ITextMarkable *markableInterface() const;
+
+ virtual void triggerCompletions();
+
+ QChar characterAt(int pos) const;
+
+ void print(QPrinter *);
+
+ void setSuggestedFileName(const QString &suggestedFileName);
+ QString mimeType() const;
+ void setMimeType(const QString &mt);
+
+
+ // Works only in conjunction with a syntax highlighter that puts
+ // parentheses into text block user data
+ void setParenthesesMatchingEnabled(bool b);
+ bool isParenthesesMatchingEnabled() const;
+
+ void setHighlightCurrentLine(bool b);
+ bool highlightCurrentLine() const;
+
+ void setLineNumbersVisible(bool b);
+ bool lineNumbersVisible() const;
+
+ void setMarksVisible(bool b);
+ bool marksVisible() const;
+
+ void setRequestMarkEnabled(bool b);
+ bool requestMarkEnabled() const;
+
+ void setLineSeparatorsAllowed(bool b);
+ bool lineSeparatorsAllowed() const;
+
+ void setCodeFoldingVisible(bool b);
+ bool codeFoldingVisible() const;
+
+ void setRevisionsVisible(bool b);
+ bool revisionsVisible() const;
+
+ void setVisibleWrapColumn(int column);
+ int visibleWrapColumn() const;
+
+ void setActionHack(QObject *);
+ QObject *actionHack() const;
+
+ void setTextCodec(QTextCodec *codec);
+ QTextCodec *textCodec() const;
+
+ void setReadOnly(bool b);
+
+public slots:
+ void setDisplayName(const QString &title);
+ virtual void setFontSettings(const TextEditor::FontSettings &);
+ virtual void format();
+ virtual void unCommentSelection();
+ virtual void setStorageSettings(const TextEditor::StorageSettings &);
+
+ void cut();
+
+ void zoomIn(int range = 1);
+ void zoomOut(int range = 1);
+
+ void deleteLine();
+ void unCollapseAll();
+ void collapse();
+ void expand();
+ void selectEncoding();
+
+signals:
+ void changed();
+
+ // ITextEditor
+ void contentsChanged();
+
+protected:
+ bool event(QEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void wheelEvent(QWheelEvent *e);
+ void changeEvent(QEvent *e);
+
+ // reimplemented to support block selection
+ QMimeData *createMimeDataFromSelection() const;
+ bool canInsertFromMimeData(const QMimeData *source) const;
+ void insertFromMimeData(const QMimeData *source);
+
+public:
+ void duplicateFrom(BaseTextEditor *editor);
+protected:
+ BaseTextDocument *baseTextDocument() const;
+ void setBaseTextDocument(BaseTextDocument *doc);
+
+ void setDefaultPath(const QString &defaultPath);
+
+ virtual BaseTextEditorEditable *createEditableInterface() = 0;
+
+private slots:
+ void editorContentsChange(int position, int charsRemoved, int charsAdded);
+ void memorizeCursorPosition();
+ void restoreCursorPosition();
+ void highlightSearchResults(const QString &txt, QTextDocument::FindFlags findFlags);
+ void setFindScope(const QTextCursor &);
+ void setCollapseIndicatorAlpha(int);
+ void currentEditorChanged(Core::IEditor *editor);
+
+private:
+ Internal::BaseTextEditorPrivate *d;
+ friend class Internal::BaseTextEditorPrivate;
+
+
+public:
+ QWidget *extraArea() const;
+ virtual int extraAreaWidth(int *markWidthPtr = 0) const;
+ virtual void extraAreaPaintEvent(QPaintEvent *);
+ virtual void extraAreaMouseEvent(QMouseEvent *);
+ virtual void extraAreaLeaveEvent(QEvent *);
+
+
+ const TabSettings &tabSettings() const;
+ const DisplaySettings &displaySettings() const;
+
+ void markBlocksAsChanged(QList<int> blockNumbers);
+
+ void ensureCursorVisible();
+
+ void setExtraExtraSelections(const QList<QTextEdit::ExtraSelection> &selections);
+ QList<QTextEdit::ExtraSelection> extraExtraSelections() const;
+
+ struct BlockRange {
+ BlockRange():first(0), last(-1){}
+ BlockRange(int first_position, int last_position):first(first_position), last(last_position){}
+ int first;
+ int last;
+ inline bool isNull() const { return last < first; }
+ };
+
+ // the blocks list must be sorted
+ void setIfdefedOutBlocks(const QList<BaseTextEditor::BlockRange> &blocks);
+
+
+public slots:
+ virtual void setTabSettings(const TextEditor::TabSettings &);
+ virtual void setDisplaySettings(const TextEditor::DisplaySettings &);
+
+protected:
+ bool viewportEvent(QEvent *event);
+
+ void resizeEvent(QResizeEvent *);
+ void paintEvent(QPaintEvent *);
+ void timerEvent(QTimerEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+
+ // Rertuns true if key triggers an indent.
+ virtual bool isElectricCharacter(const QChar &ch) const;
+ // Indent a text block based on previous line. Default does nothing
+ virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+ // Indent at cursor. Calls indentBlock for selection or current line.
+ virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar);
+
+
+protected slots:
+ virtual void slotUpdateExtraAreaWidth();
+ virtual void slotModificationChanged(bool);
+ virtual void slotUpdateRequest(const QRect &r, int dy);
+ virtual void slotCursorPositionChanged();
+ virtual void slotUpdateBlockNotify(const QTextBlock &);
+
+
+
+signals:
+ void markRequested(TextEditor::ITextEditor *editor, int line);
+ void requestBlockUpdate(const QTextBlock &);
+ void requestAutoCompletion(ITextEditable *editor, bool forced);
+
+private:
+ void indentOrUnindent(bool doIndent);
+ void handleHomeKey(bool anchor);
+ void handleBackspaceKey();
+
+ void toggleBlockVisible(const QTextBlock &block);
+ QRect collapseBox(const QTextBlock &block);
+
+ QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const;
+
+ // parentheses matcher
+private slots:
+ void _q_matchParentheses();
+ void slotSelectionChanged();
+};
+
+
+class TEXTEDITOR_EXPORT BaseTextEditorEditable
+ : public ITextEditable
+{
+ Q_OBJECT
+ friend class BaseTextEditor;
+public:
+ BaseTextEditorEditable(BaseTextEditor *editor);
+ ~BaseTextEditorEditable();
+
+ inline BaseTextEditor *editor() const { return e; }
+
+ // EditorInterface
+ inline QWidget *widget() { return e; }
+ inline Core::IFile * file() { return e->file(); }
+ inline bool createNew(const QString &contents) { return e->createNew(contents); }
+ inline bool open(const QString &fileName = QString())
+ {
+ return e->open(fileName);
+ }
+ inline QString displayName() const { return e->displayName(); }
+ inline void setDisplayName(const QString &title) { e->setDisplayName(title); }
+
+ inline QByteArray saveState() const { return e->saveState(); }
+ inline bool restoreState(const QByteArray &state) { return e->restoreState(state); }
+ QToolBar *toolBar();
+
+ // ITextEditor
+ int find(const QString &string) const;
+
+ int currentLine() const;
+ int currentColumn() const;
+ inline void gotoLine(int line, int column = 0) { e->gotoLine(line, column); }
+
+ inline int position(
+ ITextEditor::PositionOperation posOp = ITextEditor::Current
+ , int at = -1) const { return e->position(posOp, at); }
+ inline void convertPosition(int pos, int *line, int *column) const { e->convertPosition(pos, line, column); }
+ QRect cursorRect(int pos = -1) const;
+
+ QString contents() const;
+ QString selectedText() const;
+ QString textAt(int pos, int length) const;
+ inline QChar characterAt(int pos) const { return e->characterAt(pos); }
+
+ inline void triggerCompletions() { e->triggerCompletions(); } // slot?
+ inline ITextMarkable *markableInterface() { return e->markableInterface(); }
+
+ void setContextHelpId(const QString &id) { m_contextHelpId = id; }
+ QString contextHelpId() const; // from IContext
+
+ inline void setTextCodec(QTextCodec *codec) { e->setTextCodec(codec); }
+ inline QTextCodec *textCodec() const { return e->textCodec(); }
+
+
+ // ITextEditable
+ void remove(int length);
+ void insert(const QString &string);
+ void replace(int length, const QString &string);
+ void setCurPos(int pos);
+ void select(int toPos);
+
+private slots:
+ void updateCursorPosition();
+
+private:
+ BaseTextEditor *e;
+ mutable QString m_contextHelpId;
+ QToolBar *m_toolBar;
+ Core::Utils::LineColumnLabel *m_cursorPositionLabel;
+};
+
+} // namespace TextEditor
+
+#endif // BASETEXTEDITOR_H
diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h
new file mode 100644
index 0000000000..4bb0de7070
--- /dev/null
+++ b/src/plugins/texteditor/basetexteditor_p.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTEDITOR_P_H
+#define BASETEXTEDITOR_P_H
+
+#include "basetexteditor.h"
+
+#include <QtCore/QBasicTimer>
+#include <QtCore/QTimeLine>
+#include <QtCore/QSharedData>
+
+#include <QtGui/QTextEdit>
+#include <QtGui/QPixmap>
+
+namespace TextEditor {
+
+class BaseTextDocument;
+
+namespace Internal {
+
+//========== Pointers with reference count ==========
+
+template <class T> class QRefCountData : public QSharedData
+{
+public:
+ QRefCountData(T *data) { m_data = data; }
+
+ ~QRefCountData() { delete m_data; }
+
+ T *m_data;
+};
+
+/* MOSTLY COPIED FROM QSHAREDDATA(-POINTER) */
+template <class T> class QRefCountPointer
+{
+public:
+ inline T &operator*() { return d ? *(d->m_data) : 0; }
+ inline const T &operator*() const { return d ? *(d->m_data) : 0; }
+ inline T *operator->() { return d ? d->m_data : 0; }
+ inline const T *operator->() const { return d ? d->m_data : 0; }
+ inline operator T *() { return d ? d->m_data : 0; }
+ inline operator const T *() const { return d ? d->m_data : 0; }
+
+ inline bool operator==(const QRefCountPointer<T> &other) const { return d == other.d; }
+ inline bool operator!=(const QRefCountPointer<T> &other) const { return d != other.d; }
+
+ inline QRefCountPointer() { d = 0; }
+ inline ~QRefCountPointer() { if (d && !d->ref.deref()) delete d; }
+
+ explicit QRefCountPointer(T *data) {
+ if (data) {
+ d = new QRefCountData<T>(data);
+ d->ref.ref();
+ }
+ else {
+ d = 0;
+ }
+ }
+ inline QRefCountPointer(const QRefCountPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
+ inline QRefCountPointer<T> & operator=(const QRefCountPointer<T> &o) {
+ if (o.d != d) {
+ if (d && !d->ref.deref())
+ delete d;
+ //todo: atomic assign of pointers
+ d = o.d;
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+ }
+ inline QRefCountPointer &operator=(T *o) {
+ if (d == 0 || d->m_data != o) {
+ if (d && !d->ref.deref())
+ delete d;
+ d = new QRefCountData<T>(o);
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+ }
+
+ inline bool operator!() const { return !d; }
+
+private:
+ QRefCountData<T> *d;
+};
+
+//================BaseTextEditorPrivate==============
+
+class BaseTextEditorPrivate
+{
+ BaseTextEditorPrivate(const BaseTextEditorPrivate &);
+ BaseTextEditorPrivate &operator=(const BaseTextEditorPrivate &);
+
+public:
+ BaseTextEditorPrivate();
+ ~BaseTextEditorPrivate();
+
+#ifndef TEXTEDITOR_STANDALONE
+ void setupBasicEditActions(TextEditorActionHandler *actionHandler);
+#endif
+ void setupDocumentSignals(BaseTextDocument *document);
+ void updateLineSelectionColor();
+#ifndef TEXTEDITOR_STANDALONE
+ bool needMakeWritableCheck() const;
+#endif
+
+ void print(QPrinter *printer);
+
+ QTextBlock m_firstVisible;
+ int m_lastScrollPos;
+ int m_lineNumber;
+
+ BaseTextEditor *q;
+ bool m_contentsChanged;
+
+ QList<QTextEdit::ExtraSelection> m_syntaxHighlighterSelections;
+ QTextEdit::ExtraSelection m_lineSelection;
+
+ QRefCountPointer<BaseTextDocument> m_document;
+ QByteArray m_tempState;
+
+ QString m_displayName;
+ bool m_parenthesesMatchingEnabled;
+ QTimer *m_updateTimer;
+
+ // parentheses matcher
+ bool m_formatRange;
+ QTextCharFormat m_matchFormat;
+ QTextCharFormat m_mismatchFormat;
+ QTextCharFormat m_rangeFormat;
+ QTimer *m_parenthesesMatchingTimer;
+ // end parentheses matcher
+
+ QWidget *m_extraArea;
+ DisplaySettings m_displaySettings;
+
+ int extraAreaSelectionAnchorBlockNumber;
+ int extraAreaToggleMarkBlockNumber;
+ int extraAreaHighlightCollapseBlockNumber;
+ int extraAreaCollapseAlpha;
+ int extraAreaHighlightFadingBlockNumber;
+ QTimeLine *extraAreaTimeLine;
+
+ QBasicTimer collapsedBlockTimer;
+ int visibleCollapsedBlockNumber;
+ int suggestedVisibleCollapsedBlockNumber;
+ void clearVisibleCollapsedBlock();
+
+ QBasicTimer autoScrollTimer;
+ void updateMarksLineNumber();
+ void updateMarksBlock(const QTextBlock &block);
+ uint m_marksVisible : 1;
+ uint m_codeFoldingVisible : 1;
+ uint m_revisionsVisible : 1;
+ uint m_lineNumbersVisible : 1;
+ uint m_highlightCurrentLine : 1;
+ uint m_requestMarkEnabled : 1;
+ uint m_lineSeparatorsAllowed : 1;
+ int m_visibleWrapColumn;
+
+ QTextCharFormat m_ifdefedOutFormat;
+
+ QRegExp m_searchExpr;
+ QTextDocument::FindFlags m_findFlags;
+ QTextCharFormat m_searchResultFormat;
+ QTextCharFormat m_searchScopeFormat;
+ QTextCharFormat m_currentLineFormat;
+ void highlightSearchResults(const QTextBlock &block,
+ QVector<QTextLayout::FormatRange> *selections);
+
+ BaseTextEditorEditable *m_editable;
+
+ QObject *m_actionHack;
+
+ QList<QTextEdit::ExtraSelection> m_extraSelections;
+ QList<QTextEdit::ExtraSelection> m_extraExtraSelections;
+
+ // block selection mode
+ bool m_inBlockSelectionMode;
+ bool m_lastEventWasBlockSelectionEvent;
+ int m_blockSelectionExtraX;
+ void clearBlockSelection();
+ QString copyBlockSelection();
+ void removeBlockSelection(const QString &text = QString());
+
+ QTextCursor m_findScope;
+
+ void moveCursorVisible();
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // BASETEXTEDITOR_P_H
diff --git a/src/plugins/texteditor/basetextmark.cpp b/src/plugins/texteditor/basetextmark.cpp
new file mode 100644
index 0000000000..4110480332
--- /dev/null
+++ b/src/plugins/texteditor/basetextmark.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basetextmark.h"
+#include <coreplugin/editormanager/editormanager.h>
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <QtCore/QTimer>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+BaseTextMark::BaseTextMark()
+ : m_markableInterface(0), m_internalMark(0), m_init(false)
+{
+
+}
+
+BaseTextMark::BaseTextMark(const QString &filename, int line)
+ : m_markableInterface(0), m_internalMark(0), m_fileName(filename), m_line(line), m_init(false)
+{
+ // Why is this?
+ QTimer::singleShot(0, this, SLOT(init()));
+}
+
+void BaseTextMark::init()
+{
+ m_init = true;
+ Core::EditorManager *em = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->editorManager();
+ connect(em, SIGNAL(editorOpened(Core::IEditor *)), this, SLOT(editorOpened(Core::IEditor *)));
+
+ foreach(Core::IEditor *editor, em->openedEditors()) {
+ editorOpened(editor);
+ }
+}
+
+void BaseTextMark::editorOpened(Core::IEditor *editor)
+{
+ if (editor->file()->fileName() != m_fileName)
+ return;
+ if (ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor)) {
+ if (m_markableInterface == 0) { // We aren't added to something
+ m_markableInterface = textEditor->markableInterface();
+ m_internalMark = new InternalMark(this);
+ m_markableInterface->addMark(m_internalMark, m_line);
+ }
+ }
+}
+
+void BaseTextMark::childRemovedFromEditor(InternalMark *mark)
+{
+ Q_UNUSED(mark)
+ // m_internalMark was removed from the editor
+ delete m_internalMark;
+ m_markableInterface = 0;
+ m_internalMark = 0;
+ removedFromEditor();
+}
+
+void BaseTextMark::documentClosingFor(InternalMark *mark)
+{
+ Q_UNUSED(mark)
+ // the document is closing
+ delete m_internalMark;
+ m_markableInterface = 0;
+ m_internalMark = 0;
+}
+
+BaseTextMark::~BaseTextMark()
+{
+ // oha we are deleted
+ if (m_markableInterface)
+ m_markableInterface->removeMark(m_internalMark);
+ delete m_internalMark;
+ m_internalMark = 0;
+ m_markableInterface = 0;
+}
+
+//#include <QDebug>
+
+void BaseTextMark::updateMarker()
+{
+ //qDebug()<<"BaseTextMark::updateMarker()"<<m_markableInterface<<m_internalMark;
+ if (m_markableInterface)
+ m_markableInterface->updateMark(m_internalMark);
+}
+
+void BaseTextMark::moveMark(const QString & /* filename */, int /* line */)
+{
+ Core::EditorManager *em = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->editorManager();
+ if (!m_init) {
+ connect(em, SIGNAL(editorOpened(Core::IEditor *)), this, SLOT(editorOpened(Core::IEditor *)));
+ m_init = true;
+ }
+
+
+ if (m_markableInterface)
+ m_markableInterface->removeMark(m_internalMark);
+ m_markableInterface = 0;
+ // This is only necessary since m_internalMark is created in ediorOpened
+ delete m_internalMark;
+ m_internalMark = 0;
+
+ foreach(Core::IEditor *editor, em->openedEditors()) {
+ editorOpened(editor);
+ }
+}
diff --git a/src/plugins/texteditor/basetextmark.h b/src/plugins/texteditor/basetextmark.h
new file mode 100644
index 0000000000..763e3eec47
--- /dev/null
+++ b/src/plugins/texteditor/basetextmark.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTMARK_H
+#define BASETEXTMARK_H
+
+#include "itexteditor.h"
+
+namespace TextEditor {
+
+class ITextMarkable;
+
+namespace Internal {
+class InternalMark;
+}
+
+class TEXTEDITOR_EXPORT BaseTextMark : public QObject
+{
+ friend class Internal::InternalMark;
+ Q_OBJECT
+public:
+ BaseTextMark();
+ BaseTextMark(const QString &filename, int line);
+ ~BaseTextMark();
+
+ // return your icon here
+ virtual QIcon icon() const = 0;
+
+ // called if the linenumber changes
+ virtual void updateLineNumber(int lineNumber) = 0;
+
+ // called whenever the text of the block for the marker changed
+ virtual void updateBlock(const QTextBlock &block) = 0;
+
+ // called if the block containing this mark has been removed
+ // if this also removes your mark call this->deleteLater();
+ virtual void removedFromEditor() = 0;
+ // call this if the icon has changed.
+ void updateMarker();
+ // access to internal data
+ QString fileName() const { return m_fileName; }
+ int lineNumber() const { return m_line; }
+
+ void moveMark(const QString &filename, int line);
+private slots:
+ void editorOpened(Core::IEditor *editor);
+ void init();
+private:
+ void childRemovedFromEditor(Internal::InternalMark *mark);
+ void documentClosingFor(Internal::InternalMark *mark);
+
+ ITextMarkable *m_markableInterface;
+ Internal::InternalMark *m_internalMark;
+
+ QString m_fileName;
+ int m_line;
+ bool m_init;
+};
+
+namespace Internal {
+
+class InternalMark : public ITextMark
+{
+public:
+ InternalMark(BaseTextMark *parent)
+ : m_parent(parent)
+ {
+ }
+
+ ~InternalMark()
+ {
+ }
+
+ virtual QIcon icon() const
+ {
+ return m_parent->icon();
+ }
+
+ virtual void updateLineNumber(int lineNumber)
+ {
+ return m_parent->updateLineNumber(lineNumber);
+ }
+
+ virtual void updateBlock(const QTextBlock &block)
+ {
+ return m_parent->updateBlock(block);
+ }
+
+ virtual void removedFromEditor()
+ {
+ m_parent->childRemovedFromEditor(this);
+ }
+
+ virtual void documentClosing()
+ {
+ m_parent->documentClosingFor(this);
+ }
+private:
+ BaseTextMark *m_parent;
+};
+}
+}
+#endif // BASETEXTMARK_H
diff --git a/src/plugins/texteditor/codecselector.cpp b/src/plugins/texteditor/codecselector.cpp
new file mode 100644
index 0000000000..5893fa5b71
--- /dev/null
+++ b/src/plugins/texteditor/codecselector.cpp
@@ -0,0 +1,179 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "codecselector.h"
+#include "basetextdocument.h"
+
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextCodec>
+#include <QtGui/QPushButton>
+#include <QtGui/QScrollBar>
+#include <QtGui/QVBoxLayout>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+
+namespace TextEditor {
+ namespace Internal {
+
+ /* custom class to make sure the width is wide enough for the
+ * contents. Should be easier with Qt. */
+ class CodecListWidget : public QListWidget {
+ public:
+ CodecListWidget(QWidget *parent):QListWidget(parent){}
+ QSize sizeHint() const {
+ return QListWidget::sizeHint().expandedTo(
+ QSize(sizeHintForColumn(0) + verticalScrollBar()->sizeHint().width() + 4, 0));
+ }
+ };
+ }
+}
+
+CodecSelector::CodecSelector(QWidget *parent, BaseTextDocument *doc)
+ : QDialog(parent)
+{
+ m_hasDecodingError = doc->hasDecodingError();
+ m_isModified = doc->isModified();
+
+ QByteArray buf;
+ if (m_hasDecodingError)
+ buf = doc->decodingErrorSample();
+
+ setWindowTitle(tr("Text Encoding"));
+ m_label = new QLabel(this);
+ QString decodingErrorHint;
+ if (m_hasDecodingError)
+ decodingErrorHint = tr("\nThe following encodings are likely to fit:");
+ m_label->setText(tr("Select encoding for \"%1\".%2").arg(QFileInfo(doc->fileName()).fileName()).arg(decodingErrorHint));
+
+ m_listWidget = new CodecListWidget(this);
+
+ QStringList encodings;
+
+ QList<int> mibs = QTextCodec::availableMibs();
+ qSort(mibs);
+ QList<int> sortedMibs;
+ foreach(int mib, mibs)
+ if (mib >= 0)
+ sortedMibs += mib;
+ foreach(int mib, mibs)
+ if (mib < 0)
+ sortedMibs += mib;
+
+ int currentIndex = -1;
+ foreach(int mib, sortedMibs) {
+ QTextCodec *c = QTextCodec::codecForMib(mib);
+ if (!buf.isEmpty()) {
+
+ // slow, should use a feature from QTextCodec or QTextDecoder (but those are broken currently)
+ QByteArray verifyBuf = c->fromUnicode(c->toUnicode(buf));
+ // the minSize trick lets us ignore unicode headers
+ int minSize = qMin(verifyBuf.size(), buf.size());
+ if (minSize < buf.size() - 4
+ || memcmp(verifyBuf.constData() + verifyBuf.size() - minSize,
+ buf.constData() + buf.size() - minSize, minSize))
+ continue;
+ }
+ QString names = QString::fromLatin1(c->name());
+ foreach(QByteArray alias, c->aliases()) {
+ names += QLatin1String(" / ") + QString::fromLatin1(alias);
+ }
+ if (doc->codec() == c)
+ currentIndex = encodings.count();
+ encodings << names;
+ }
+ m_listWidget->addItems(encodings);
+ if (currentIndex >= 0)
+ m_listWidget->setCurrentRow(currentIndex);
+
+ connect(m_listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
+
+ m_dialogButtonBox = new QDialogButtonBox(this);
+ m_reloadButton = m_dialogButtonBox->addButton(tr("Reload with Encoding"), QDialogButtonBox::DestructiveRole);
+ m_saveButton = m_dialogButtonBox->addButton(tr("Save with Encoding"), QDialogButtonBox::DestructiveRole);
+ m_dialogButtonBox->addButton(QDialogButtonBox::Cancel);
+ connect(m_dialogButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+
+ QVBoxLayout *vbox = new QVBoxLayout(this);
+ vbox->addWidget(m_label);
+ vbox->addWidget(m_listWidget);
+ vbox->addWidget(m_dialogButtonBox);
+
+ updateButtons();
+}
+
+
+
+CodecSelector::~CodecSelector()
+{
+}
+
+void CodecSelector::updateButtons()
+{
+ bool hasCodec = (selectedCodec() != 0);
+ m_reloadButton->setEnabled(!m_isModified && hasCodec);
+ m_saveButton->setEnabled(!m_hasDecodingError && hasCodec);
+}
+
+QTextCodec *CodecSelector::selectedCodec() const
+{
+ if (QListWidgetItem *item = m_listWidget->currentItem()) {
+ if (!item->isSelected())
+ return 0;
+ QString codecName = item->text();
+ if (codecName.contains(QLatin1String(" / ")))
+ codecName = codecName.left(codecName.indexOf(QLatin1String(" / ")));
+ return QTextCodec::codecForName(codecName.toLatin1());
+ }
+ return 0;
+}
+
+
+CodecSelector::Result CodecSelector::exec()
+{
+ return (Result) QDialog::exec();
+}
+
+
+void CodecSelector::buttonClicked(QAbstractButton *button)
+{
+ Result result = Cancel;
+ if (button == m_reloadButton)
+ result = Reload;
+ if (button == m_saveButton)
+ result = Save;
+ done(result);
+}
+
diff --git a/src/plugins/texteditor/codecselector.h b/src/plugins/texteditor/codecselector.h
new file mode 100644
index 0000000000..aa873b3a2b
--- /dev/null
+++ b/src/plugins/texteditor/codecselector.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CODECSELECTOR_H
+#define CODECSELECTOR_H
+
+#include <QtGui/QDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QListWidget>
+
+namespace TextEditor {
+
+class BaseTextDocument;
+
+namespace Internal {
+
+class CodecSelector : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ CodecSelector(QWidget *parent, BaseTextDocument *doc);
+ ~CodecSelector();
+
+ QTextCodec *selectedCodec() const;
+
+ enum Result {
+ Cancel, Reload, Save
+ };
+
+ Result exec();
+
+private slots:
+ void updateButtons();
+ void buttonClicked(QAbstractButton *button);
+
+private:
+ bool m_hasDecodingError;
+ bool m_isModified;
+ QLabel *m_label;
+ QListWidget *m_listWidget;
+ QDialogButtonBox *m_dialogButtonBox;
+ QAbstractButton *m_reloadButton;
+ QAbstractButton *m_saveButton;
+};
+
+
+
+
+
+}
+}
+
+#endif // CODECSELECTOR_H
diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp
new file mode 100644
index 0000000000..6c9972d7eb
--- /dev/null
+++ b/src/plugins/texteditor/completionsupport.cpp
@@ -0,0 +1,171 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "completionsupport.h"
+#include "completionwidget.h"
+#include "icompletioncollector.h"
+
+#include <coreplugin/icore.h>
+#include <texteditor/itexteditable.h>
+
+#include <QString>
+#include <QList>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+
+CompletionSupport *CompletionSupport::instance(Core::ICore *core)
+{
+ static CompletionSupport *m_instance = 0;
+ if (!m_instance) {
+ m_instance = new CompletionSupport(core);
+ }
+ return m_instance;
+}
+
+CompletionSupport::CompletionSupport(Core::ICore *core)
+ : QObject(core),
+ m_completionList(0),
+ m_startPosition(0),
+ m_checkCompletionTrigger(false),
+ m_editor(0)
+{
+ m_completionCollector = core->pluginManager()->getObject<ICompletionCollector>();
+}
+
+void CompletionSupport::performCompletion(const CompletionItem &item)
+{
+ item.m_collector->complete(item);
+ m_checkCompletionTrigger = true;
+}
+
+void CompletionSupport::cleanupCompletions()
+{
+ if (m_completionList)
+ disconnect(m_completionList, SIGNAL(destroyed(QObject*)),
+ this, SLOT(cleanupCompletions()));
+
+ m_completionList = 0;
+ m_completionCollector->cleanup();
+
+ if (m_checkCompletionTrigger) {
+ m_checkCompletionTrigger = false;
+
+ // Only check for completion trigger when some text was entered
+ if (m_editor->position() > m_startPosition)
+ autoComplete(m_editor, false);
+ }
+}
+
+void CompletionSupport::autoComplete(ITextEditable *editor, bool forced)
+{
+ if (!m_completionCollector)
+ return;
+
+ m_editor = editor;
+ QList<CompletionItem> completionItems;
+
+ if (!m_completionList) {
+ if (!forced && !m_completionCollector->triggersCompletion(editor))
+ return;
+
+ m_startPosition = m_completionCollector->startCompletion(editor);
+ completionItems = getCompletions();
+
+ Q_ASSERT(m_startPosition != -1 || completionItems.size() == 0);
+
+ if (completionItems.isEmpty()) {
+ cleanupCompletions();
+ return;
+ }
+
+ m_completionList = new CompletionWidget(this, editor);
+
+ connect(m_completionList, SIGNAL(itemSelected(TextEditor::CompletionItem)),
+ this, SLOT(performCompletion(TextEditor::CompletionItem)));
+ connect(m_completionList, SIGNAL(completionListClosed()),
+ this, SLOT(cleanupCompletions()));
+
+ // Make sure to clean up the completions if the list is destroyed without
+ // emitting completionListClosed (can happen when no focus out event is received,
+ // for example when switching applications on the Mac)
+ connect(m_completionList, SIGNAL(destroyed(QObject*)),
+ this, SLOT(cleanupCompletions()));
+ } else {
+ completionItems = getCompletions();
+
+ if (completionItems.isEmpty()) {
+ m_completionList->closeList();
+ return;
+ }
+ }
+
+ m_completionList->setCompletionItems(completionItems);
+
+ // Partially complete when completion was forced
+ if (forced && m_completionCollector->partiallyComplete(completionItems)) {
+ m_checkCompletionTrigger = true;
+ m_completionList->closeList();
+ } else {
+ m_completionList->showCompletions(m_startPosition);
+ }
+}
+
+static bool completionItemLessThan(const CompletionItem &i1, const CompletionItem &i2)
+{
+ // The order is case-insensitive in principle, but case-sensitive when this would otherwise mean equality
+ const int c = i1.m_text.compare(i2.m_text, Qt::CaseInsensitive);
+ return c ? c < 0 : i1.m_text < i2.m_text;
+}
+
+QList<CompletionItem> CompletionSupport::getCompletions() const
+{
+ QList<CompletionItem> completionItems;
+
+ m_completionCollector->completions(&completionItems);
+
+ qStableSort(completionItems.begin(), completionItems.end(), completionItemLessThan);
+
+ // Remove duplicates
+ QString lastKey;
+ QList<CompletionItem> uniquelist;
+
+ foreach (const CompletionItem item, completionItems) {
+ if (item.m_text != lastKey) {
+ uniquelist.append(item);
+ lastKey = item.m_text;
+ }
+ }
+
+ return uniquelist;
+}
diff --git a/src/plugins/texteditor/completionsupport.h b/src/plugins/texteditor/completionsupport.h
new file mode 100644
index 0000000000..d3083630b6
--- /dev/null
+++ b/src/plugins/texteditor/completionsupport.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPLETIONSUPPORT_H
+#define COMPLETIONSUPPORT_H
+
+#include <texteditor/texteditor_global.h>
+#include <QtCore/QObject>
+
+namespace Core { class ICore; }
+
+namespace TextEditor {
+
+struct CompletionItem;
+class ICompletionCollector;
+class ITextEditable;
+
+namespace Internal {
+
+class CompletionWidget;
+
+/* Completion support is responsible for querying the list of completion collectors
+ and popping up the CompletionWidget with the available completions.
+ */
+class TEXTEDITOR_EXPORT CompletionSupport : public QObject
+{
+ Q_OBJECT
+
+public:
+ CompletionSupport(Core::ICore *core);
+
+ static CompletionSupport *instance(Core::ICore *core);
+public slots:
+ void autoComplete(ITextEditable *editor, bool forced);
+
+private slots:
+ void performCompletion(const TextEditor::CompletionItem &item);
+ void cleanupCompletions();
+
+private:
+ QList<CompletionItem> getCompletions() const;
+
+ CompletionWidget *m_completionList;
+ int m_startPosition;
+ bool m_checkCompletionTrigger; // Whether to check for completion trigger after cleanup
+ ITextEditable *m_editor;
+ ICompletionCollector *m_completionCollector;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // COMPLETIONSUPPORT_H
+
diff --git a/src/plugins/texteditor/completionwidget.cpp b/src/plugins/texteditor/completionwidget.cpp
new file mode 100644
index 0000000000..939123a5cf
--- /dev/null
+++ b/src/plugins/texteditor/completionwidget.cpp
@@ -0,0 +1,264 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "completionwidget.h"
+#include "completionsupport.h"
+#include "icompletioncollector.h"
+
+#include <texteditor/itexteditable.h>
+
+#include <QtCore/QEvent>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QApplication>
+#include <QtGui/QVBoxLayout>
+
+#include <limits.h>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+#define NUMBER_OF_VISIBLE_ITEMS 10
+
+class AutoCompletionModel : public QAbstractListModel
+{
+public:
+ AutoCompletionModel(QObject *parent, const QList<CompletionItem> &items);
+
+ inline const CompletionItem &itemAt(const QModelIndex &index) const
+ { return m_items.at(index.row()); }
+
+ void setItems(const QList<CompletionItem> &items);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+private:
+ QList<CompletionItem> m_items;
+};
+
+AutoCompletionModel::AutoCompletionModel(QObject *parent, const QList<CompletionItem> &items)
+ : QAbstractListModel(parent)
+{
+ m_items = items;
+}
+
+void AutoCompletionModel::setItems(const QList<CompletionItem> &items)
+{
+ m_items = items;
+ reset();
+}
+
+int AutoCompletionModel::rowCount(const QModelIndex &) const
+{
+ return m_items.count();
+}
+
+QVariant AutoCompletionModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() >= m_items.count())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ return itemAt(index).m_text;
+ } else if (role == Qt::DecorationRole) {
+ return itemAt(index).m_icon;
+ } else if (role == Qt::ToolTipRole) {
+ return itemAt(index).m_details;
+ }
+
+ return QVariant();
+}
+
+CompletionWidget::CompletionWidget(CompletionSupport *support, ITextEditable *editor)
+ : QListView(),
+ m_blockFocusOut(false),
+ m_editor(editor),
+ m_editorWidget(editor->widget()),
+ m_model(0),
+ m_support(support)
+{
+ Q_ASSERT(m_editorWidget);
+
+ setUniformItemSizes(true);
+ setSelectionBehavior(QAbstractItemView::SelectItems);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+
+ connect(this, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(completionActivated(const QModelIndex &)));
+
+ // We disable the frame on this list view and use a QFrame around it instead.
+ // This fixes the missing frame on Mac and improves the look with QGTKStyle.
+ m_popupFrame = new QFrame(0, Qt::Popup);
+ m_popupFrame->setFrameStyle(frameStyle());
+ setFrameStyle(QFrame::NoFrame);
+ setParent(m_popupFrame);
+ m_popupFrame->setObjectName("m_popupFrame");
+ m_popupFrame->setAttribute(Qt::WA_DeleteOnClose);
+ QVBoxLayout *layout = new QVBoxLayout(m_popupFrame);
+ layout->setMargin(0);
+ layout->addWidget(this);
+
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+bool CompletionWidget::event(QEvent *e)
+{
+ if (m_blockFocusOut)
+ return QListView::event(e);
+
+ bool forwardKeys = true;
+ if (e->type() == QEvent::FocusOut) {
+ closeList();
+ return true;
+ } else if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+ switch (ke->key()) {
+ case Qt::Key_Escape:
+ closeList();
+ return true;
+ case Qt::Key_Right:
+ case Qt::Key_Left:
+ break;
+ case Qt::Key_Tab:
+ case Qt::Key_Return:
+ //independently from style, accept current entry if return is pressed
+ closeList(currentIndex());
+ return true;
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Enter:
+ case Qt::Key_PageDown:
+ case Qt::Key_PageUp:
+ forwardKeys = false;
+ break;
+ default:
+ break;
+ }
+
+ if (forwardKeys) {
+ m_blockFocusOut = true;
+ QApplication::sendEvent(m_editorWidget, e);
+ m_blockFocusOut = false;
+
+ // Have the completion support update the list of items
+ m_support->autoComplete(m_editor, false);
+
+ return true;
+ }
+ }
+ return QListView::event(e);
+}
+
+void CompletionWidget::keyboardSearch(const QString &search)
+{
+ Q_UNUSED(search);
+}
+
+void CompletionWidget::closeList(const QModelIndex &index)
+{
+ m_blockFocusOut = true;
+ if (index.isValid())
+ emit itemSelected(m_model->itemAt(index));
+
+ close();
+ if (m_popupFrame) {
+ m_popupFrame->close();
+ m_popupFrame = 0;
+ }
+
+ emit completionListClosed();
+
+ m_blockFocusOut = false;
+}
+
+void CompletionWidget::setCompletionItems(const QList<TextEditor::CompletionItem> &completionItems)
+{
+ if (!m_model) {
+ m_model = new AutoCompletionModel(this, completionItems);
+ setModel(m_model);
+ } else {
+ m_model->setItems(completionItems);
+ }
+
+ // Select the first of the most relevant completion items
+ int relevance = INT_MIN;
+ int mostRelevantIndex = 0;
+ for (int i = 0; i < completionItems.size(); ++i) {
+ const CompletionItem &item = completionItems.at(i);
+ if (item.m_relevance > relevance) {
+ relevance = item.m_relevance;
+ mostRelevantIndex = i;
+ }
+ }
+
+ setCurrentIndex(m_model->index(mostRelevantIndex));
+}
+
+void CompletionWidget::showCompletions(int startPos)
+{
+ const QPoint &pos = m_editor->cursorRect(startPos).bottomLeft();
+ m_popupFrame->move(pos.x() - 16, pos.y());
+ m_popupFrame->setMinimumSize(1, 1);
+ setMinimumSize(1, 1);
+
+ updateSize();
+
+ m_popupFrame->show();
+ show();
+ setFocus();
+}
+
+void CompletionWidget::updateSize()
+{
+ int visibleItems = m_model->rowCount();
+ if (visibleItems > NUMBER_OF_VISIBLE_ITEMS)
+ visibleItems = NUMBER_OF_VISIBLE_ITEMS;
+
+ const QStyleOptionViewItem &option = viewOptions();
+
+ QSize shint;
+ for (int i = 0; i < visibleItems; ++i) {
+ QSize tmp = itemDelegate()->sizeHint(option, m_model->index(i));
+ if (shint.width() < tmp.width())
+ shint = tmp;
+ }
+
+ const int width = (shint.width() + (m_popupFrame->frameWidth() * 2) + 30);
+ const int height = (shint.height() * visibleItems) + m_popupFrame->frameWidth() * 2;
+
+ m_popupFrame->resize(width, height);
+}
+
+void CompletionWidget::completionActivated(const QModelIndex &index)
+{
+ closeList(index);
+}
diff --git a/src/plugins/texteditor/completionwidget.h b/src/plugins/texteditor/completionwidget.h
new file mode 100644
index 0000000000..4a41ffad34
--- /dev/null
+++ b/src/plugins/texteditor/completionwidget.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPLETIONWIDGET_H
+#define COMPLETIONWIDGET_H
+
+#include <QtGui/QListView>
+#include <QPointer>
+
+class AutoCompletionModel;
+
+namespace TextEditor {
+
+struct CompletionItem;
+class ITextEditable;
+
+namespace Internal {
+
+class CompletionSupport;
+
+/* The completion widget is responsible for showing a list of possible completions.
+ It is only used by the CompletionSupport.
+ */
+class CompletionWidget : public QListView
+{
+ Q_OBJECT
+
+public:
+ CompletionWidget(CompletionSupport *support, ITextEditable *editor);
+
+ void setCompletionItems(const QList<TextEditor::CompletionItem> &completionitems);
+ void showCompletions(int startPos);
+ void keyboardSearch(const QString &search);
+ void closeList(const QModelIndex &index = QModelIndex());
+
+protected:
+ bool event(QEvent *e);
+
+signals:
+ void itemSelected(const TextEditor::CompletionItem &item);
+ void completionListClosed();
+
+private slots:
+ void completionActivated(const QModelIndex &index);
+
+private:
+ void updateSize();
+
+ QPointer<QFrame> m_popupFrame;
+ bool m_blockFocusOut;
+ ITextEditable *m_editor;
+ QWidget *m_editorWidget;
+ AutoCompletionModel *m_model;
+ CompletionSupport *m_support;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // COMPLETIONWIDGET_H
+
diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp
new file mode 100644
index 0000000000..af74e4b2ab
--- /dev/null
+++ b/src/plugins/texteditor/displaysettings.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "displaysettings.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QString>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextDocument>
+
+static const char * const displayLineNumbersKey = "DisplayLineNumbers";
+static const char * const textWrappingKey = "TextWrapping";
+static const char * const showWrapColumnKey = "ShowWrapColumn";
+static const char * const wrapColumnKey = "WrapColumn";
+static const char * const visualizeWhitespaceKey = "VisualizeWhitespace";
+static const char * const displayFoldingMarkersKey = "DisplayFoldingMarkers";
+static const char * const highlightCurrentLineKey = "HighlightCurrentLineKey";
+static const char * const groupPostfix = "DisplaySettings";
+
+namespace TextEditor {
+
+DisplaySettings::DisplaySettings() :
+ m_displayLineNumbers(true),
+ m_textWrapping(false),
+ m_showWrapColumn(false),
+ m_wrapColumn(80),
+ m_visualizeWhitespace(false),
+ m_displayFoldingMarkers(true),
+ m_highlightCurrentLine(true)
+{
+}
+
+void DisplaySettings::toSettings(const QString &category, QSettings *s) const
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ s->beginGroup(group);
+ s->setValue(QLatin1String(displayLineNumbersKey), m_displayLineNumbers);
+ s->setValue(QLatin1String(textWrappingKey), m_textWrapping);
+ s->setValue(QLatin1String(showWrapColumnKey), m_showWrapColumn);
+ s->setValue(QLatin1String(wrapColumnKey), m_wrapColumn);
+ s->setValue(QLatin1String(visualizeWhitespaceKey), m_visualizeWhitespace);
+ s->setValue(QLatin1String(displayFoldingMarkersKey), m_displayFoldingMarkers);
+ s->setValue(QLatin1String(highlightCurrentLineKey), m_highlightCurrentLine);
+ s->endGroup();
+}
+
+void DisplaySettings::fromSettings(const QString &category, const QSettings *s)
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ group += QLatin1Char('/');
+
+ *this = DisplaySettings(); // Assign defaults
+
+ m_displayLineNumbers = s->value(group + QLatin1String(displayLineNumbersKey), m_displayLineNumbers).toBool();
+ m_textWrapping = s->value(group + QLatin1String(textWrappingKey), m_textWrapping).toBool();
+ m_showWrapColumn = s->value(group + QLatin1String(showWrapColumnKey), m_showWrapColumn).toBool();
+ m_wrapColumn = s->value(group + QLatin1String(wrapColumnKey), m_wrapColumn).toInt();
+ m_visualizeWhitespace = s->value(group + QLatin1String(visualizeWhitespaceKey), m_visualizeWhitespace).toBool();
+ m_displayFoldingMarkers = s->value(group + QLatin1String(displayFoldingMarkersKey), m_displayFoldingMarkers).toBool();
+ m_highlightCurrentLine = s->value(group + QLatin1String(highlightCurrentLineKey), m_highlightCurrentLine).toBool();
+}
+
+bool DisplaySettings::equals(const DisplaySettings &ds) const
+{
+ return m_displayLineNumbers == ds.m_displayLineNumbers
+ && m_textWrapping == ds.m_textWrapping
+ && m_showWrapColumn == ds.m_showWrapColumn
+ && m_wrapColumn == ds.m_wrapColumn
+ && m_visualizeWhitespace == ds.m_visualizeWhitespace
+ && m_displayFoldingMarkers == ds.m_displayFoldingMarkers
+ && m_highlightCurrentLine == ds.m_highlightCurrentLine
+ ;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h
new file mode 100644
index 0000000000..7c70126e5d
--- /dev/null
+++ b/src/plugins/texteditor/displaysettings.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DISPLAYSETTINGS_H
+#define DISPLAYSETTINGS_H
+
+#include "texteditor_global.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+struct TEXTEDITOR_EXPORT DisplaySettings
+{
+ DisplaySettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, const QSettings *s);
+
+ bool m_displayLineNumbers;
+ bool m_textWrapping;
+ bool m_showWrapColumn;
+ int m_wrapColumn;
+ bool m_visualizeWhitespace;
+ bool m_displayFoldingMarkers;
+ bool m_highlightCurrentLine;
+
+ bool equals(const DisplaySettings &ds) const;
+};
+
+inline bool operator==(const DisplaySettings &t1, const DisplaySettings &t2) { return t1.equals(t2); }
+inline bool operator!=(const DisplaySettings &t1, const DisplaySettings &t2) { return !t1.equals(t2); }
+
+} // namespace TextEditor
+
+#endif // DISPLAYSETTINGS_H
diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp
new file mode 100644
index 0000000000..6e11e40017
--- /dev/null
+++ b/src/plugins/texteditor/findinfiles.cpp
@@ -0,0 +1,144 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "findinfiles.h"
+
+#include <QtDebug>
+#include <QtCore/QDirIterator>
+#include <QtGui/QPushButton>
+#include <QtGui/QFileDialog>
+#include <QtGui/QVBoxLayout>
+
+using namespace Find;
+using namespace TextEditor::Internal;
+
+FindInFiles::FindInFiles(Core::ICore *core, SearchResultWindow *resultWindow)
+ : BaseFileFind(core, resultWindow),
+ m_configWidget(0),
+ m_directory(0)
+{
+}
+
+QString FindInFiles::name() const
+{
+ return tr("Files on Disk");
+}
+
+QKeySequence FindInFiles::defaultShortcut() const
+{
+ return QKeySequence();
+}
+
+void FindInFiles::findAll(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ updateComboEntries(m_directory, true);
+ BaseFileFind::findAll(txt, findFlags);
+}
+
+QStringList FindInFiles::files()
+{
+ QStringList fileList;
+ QDirIterator it(m_directory->currentText(),
+ fileNameFilters(),
+ QDir::Files|QDir::Readable,
+ QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ it.next();
+ fileList << it.filePath();
+ }
+ return fileList;
+}
+
+QWidget *FindInFiles::createConfigWidget()
+{
+ if (!m_configWidget) {
+ m_configWidget = new QWidget;
+ QGridLayout * const gridLayout = new QGridLayout(m_configWidget);
+ gridLayout->setMargin(0);
+ m_configWidget->setLayout(gridLayout);
+ gridLayout->addWidget(createRegExpWidget(), 0, 1, 1, 2);
+
+ gridLayout->addWidget(new QLabel(tr("Directory:")), 1, 0, Qt::AlignRight);
+ m_directory = new QComboBox;
+ m_directory->setEditable(true);
+ m_directory->setMaxCount(30);
+ m_directory->setMinimumContentsLength(10);
+ m_directory->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
+ m_directory->setInsertPolicy(QComboBox::InsertAtTop);
+ m_directory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_directory->setModel(&m_directoryStrings);
+ syncComboWithSettings(m_directory, m_directorySetting);
+ gridLayout->addWidget(m_directory, 1, 1);
+ QPushButton *browseButton = new QPushButton(tr("Browse"));
+ gridLayout->addWidget(browseButton, 1, 2);
+ connect(browseButton, SIGNAL(clicked()), this, SLOT(openFileBrowser()));
+
+ QLabel * const filePatternLabel = new QLabel(tr("File pattern:"));
+ filePatternLabel->setMinimumWidth(80);
+ filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ gridLayout->addWidget(filePatternLabel, 2, 0);
+ gridLayout->addWidget(createPatternWidget(), 2, 1, 1, 2);
+ m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ }
+ return m_configWidget;
+}
+
+void FindInFiles::openFileBrowser()
+{
+ if (!m_directory)
+ return;
+ QString dir = QFileDialog::getExistingDirectory(m_configWidget,
+ tr("Directory to search"));
+ if (!dir.isEmpty())
+ m_directory->setEditText(dir);
+}
+
+void FindInFiles::writeSettings(QSettings *settings)
+{
+ settings->beginGroup("FindInFiles");
+ writeCommonSettings(settings);
+ settings->setValue("directories", m_directoryStrings.stringList());
+ if (m_directory)
+ settings->setValue("currentDirectory", m_directory->currentText());
+ settings->endGroup();
+}
+
+void FindInFiles::readSettings(QSettings *settings)
+{
+ settings->beginGroup("FindInFiles");
+ readCommonSettings(settings, "*.cpp,*.h");
+ m_directoryStrings.setStringList(settings->value("directories").toStringList());
+ m_directorySetting = settings->value("currentDirectory").toString();
+ settings->endGroup();
+ syncComboWithSettings(m_directory, m_directorySetting);
+}
diff --git a/src/plugins/texteditor/findinfiles.h b/src/plugins/texteditor/findinfiles.h
new file mode 100644
index 0000000000..3d5bf0c940
--- /dev/null
+++ b/src/plugins/texteditor/findinfiles.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FINDINFILES_H
+#define FINDINFILES_H
+
+#include "basefilefind.h"
+
+#include <coreplugin/icore.h>
+#include <find/ifindfilter.h>
+#include <find/searchresultwindow.h>
+
+#include <QtCore/QPointer>
+#include <QtGui/QLabel>
+#include <QtGui/QComboBox>
+#include <QtGui/QStringListModel>
+
+
+namespace TextEditor {
+namespace Internal {
+
+class FindInFiles : public BaseFileFind
+{
+ Q_OBJECT
+
+public:
+ FindInFiles(Core::ICore *core, Find::SearchResultWindow *resultWindow);
+
+ QString name() const;
+
+ QKeySequence defaultShortcut() const;
+
+ void findAll(const QString &txt, QTextDocument::FindFlags findFlags);
+ QWidget *createConfigWidget();
+ void writeSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+protected:
+ QStringList files();
+
+private slots:
+ void openFileBrowser();
+
+private:
+ QStringListModel m_directoryStrings;
+ QString m_directorySetting;
+ QPointer<QWidget> m_configWidget;
+ QPointer<QComboBox> m_directory;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // FINDINFILES_H
diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp
new file mode 100644
index 0000000000..1ced2cafd6
--- /dev/null
+++ b/src/plugins/texteditor/fontsettings.cpp
@@ -0,0 +1,277 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fontsettings.h"
+#include "fontsettingspage.h"
+
+#include <QtCore/QSettings>
+#include <QtGui/QTextCharFormat>
+
+static const char *fontFamilyKey = "FontFamily";
+static const char *fontSizeKey = "FontSize";
+static const char *trueString = "true";
+static const char *falseString = "false";
+
+namespace {
+#ifdef Q_WS_MAC
+ enum { DEFAULT_FONT_SIZE = 12 };
+ static const char *DEFAULT_FONT_FAMILY = "Monaco";
+#else
+#ifdef Q_OS_UNIX
+ enum { DEFAULT_FONT_SIZE = 9 };
+ static const char *DEFAULT_FONT_FAMILY = "Monospace";
+#else
+ enum { DEFAULT_FONT_SIZE = 10 };
+ static const char *DEFAULT_FONT_FAMILY = "Courier";
+#endif
+#endif
+} // anonymous namespace
+
+namespace TextEditor {
+
+// Format --
+Format::Format() :
+ m_foreground(Qt::black),
+ m_background(Qt::white),
+ m_bold(false),
+ m_italic(false)
+{
+}
+
+void Format::setForeground(const QColor &foreground)
+{
+ m_foreground = foreground;
+}
+
+void Format::setBackground(const QColor &background)
+{
+ m_background = background;
+}
+
+void Format::setBold(bool bold)
+{
+ m_bold = bold;
+}
+
+void Format::setItalic(bool italic)
+{
+ m_italic = italic;
+}
+
+static QString colorToString(const QColor &color) {
+ if (color.isValid())
+ return color.name();
+ return QLatin1String("invalid");
+}
+
+static QColor stringToColor(const QString &string) {
+ if (string == QLatin1String("invalid"))
+ return QColor();
+ return QColor(string);
+}
+
+QString Format::toString() const
+{
+ const QChar delimiter = QLatin1Char(';');
+ QString s = colorToString(m_foreground);
+ s += delimiter;
+ s += colorToString(m_background);
+ s += delimiter;
+ s += m_bold ? QLatin1String(trueString) : QLatin1String(falseString);
+ s += delimiter;
+ s += m_italic ? QLatin1String(trueString) : QLatin1String(falseString);
+ return s;
+}
+
+bool Format::fromString(const QString &str)
+{
+ *this = Format();
+
+ const QStringList lst = str.split(QLatin1Char(';'));
+ if (lst.count() != 4)
+ return false;
+
+ m_foreground = stringToColor(lst.at(0));
+ m_background = stringToColor(lst.at(1));
+ m_bold = lst.at(2) == QLatin1String(trueString);
+ m_italic = lst.at(3) == QLatin1String(trueString);
+ return true;
+}
+
+bool Format::equals(const Format &f) const
+{
+ return m_foreground == f.m_foreground && m_background == f.m_background &&
+ m_bold == f.m_bold && m_italic == f.m_italic;
+}
+// -- FontSettings
+FontSettings::FontSettings(const FormatDescriptions &fd) :
+ m_family(defaultFixedFontFamily()),
+ m_fontSize(DEFAULT_FONT_SIZE)
+{
+}
+
+void FontSettings::clear()
+{
+ m_family = defaultFixedFontFamily();
+ m_fontSize = DEFAULT_FONT_SIZE;
+ qFill(m_formats.begin(), m_formats.end(), Format());
+}
+
+void FontSettings::toSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ QSettings *s) const
+{
+ const int numFormats = m_formats.size();
+ Q_ASSERT(descriptions.size() == numFormats);
+ s->beginGroup(category);
+ if (m_family != defaultFixedFontFamily() || s->contains(QLatin1String(fontFamilyKey)))
+ s->setValue(QLatin1String(fontFamilyKey), m_family);
+
+ if (m_fontSize != DEFAULT_FONT_SIZE || s->contains(QLatin1String(fontSizeKey)))
+ s->setValue(QLatin1String(fontSizeKey), m_fontSize);
+
+ const Format defaultFormat;
+
+ foreach (const FormatDescription &desc, descriptions) {
+ QMap<QString, Format>::const_iterator i = m_formats.find(desc.name());
+ if (i != m_formats.end() && ((*i) != defaultFormat || s->contains(desc.name()))) {
+ s->setValue(desc.name(), (*i).toString());
+ }
+ }
+ s->endGroup();
+}
+
+bool FontSettings::fromSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ const QSettings *s)
+{
+ clear();
+
+ if (!s->childGroups().contains(category))
+ return false;
+
+ QString group = category;
+ group += QLatin1Char('/');
+
+ m_family = s->value(group + QLatin1String(fontFamilyKey), defaultFixedFontFamily()).toString();
+ m_fontSize = s->value(group + QLatin1String(QLatin1String(fontSizeKey)), m_fontSize).toInt();
+
+ foreach (const FormatDescription &desc, descriptions) {
+ const QString name = desc.name();
+ const QString fmt = s->value(group + name, QString()).toString();
+ if (fmt.isEmpty()) {
+ m_formats[name].setForeground(desc.foreground());
+ m_formats[name].setBackground(desc.background());
+ } else {
+ m_formats[name].fromString(fmt);
+ }
+ }
+ return true;
+}
+
+bool FontSettings::equals(const FontSettings &f) const
+{
+ return m_family == f.m_family
+ && m_fontSize == f.m_fontSize
+ && m_formats == f.m_formats;
+}
+
+QTextCharFormat FontSettings::toTextCharFormat(const QString &category) const
+{
+ const Format f = m_formats.value(category);
+ QTextCharFormat tf;
+ if (category == QLatin1String("Text")) {
+ tf.setFontFamily(m_family);
+ tf.setFontPointSize(m_fontSize);
+ }
+
+ if (f.foreground().isValid())
+ tf.setForeground(f.foreground());
+ if (f.background().isValid() && (category == QLatin1String("Text") || f.background() != m_formats.value(QLatin1String("Text")).background()))
+ tf.setBackground(f.background());
+ tf.setFontWeight(f.bold() ? QFont::Bold : QFont::Normal);
+ tf.setFontItalic(f.italic());
+ return tf;
+}
+
+QVector<QTextCharFormat> FontSettings::toTextCharFormats(const QVector<QString> &categories) const
+{
+ QVector<QTextCharFormat> rc;
+ const int size = categories.size();
+ rc.reserve(size);
+ for (int i = 0; i < size; i++)
+ rc.push_back(toTextCharFormat(categories.at(i)));
+ return rc;
+}
+
+QString FontSettings::family() const
+{
+ return m_family;
+}
+
+void FontSettings::setFamily(const QString &family)
+{
+ m_family = family;
+}
+
+int FontSettings::fontSize() const
+{
+ return m_fontSize;
+}
+
+void FontSettings::setFontSize(int size)
+{
+ m_fontSize = size;
+}
+
+Format &FontSettings::formatFor(const QString &category)
+{
+ return m_formats[category];
+}
+
+QString FontSettings::defaultFixedFontFamily()
+{
+ static QString rc;
+ if (rc.isEmpty()) {
+ QFont f(DEFAULT_FONT_FAMILY);
+ f.setStyleHint(QFont::TypeWriter);
+ rc = f.family();
+ }
+ return rc;
+}
+
+int FontSettings::defaultFontSize()
+{
+ return DEFAULT_FONT_SIZE;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/fontsettings.h b/src/plugins/texteditor/fontsettings.h
new file mode 100644
index 0000000000..1b9088b621
--- /dev/null
+++ b/src/plugins/texteditor/fontsettings.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FONTSETTINGS_H
+#define FONTSETTINGS_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QVector>
+#include <QtGui/QColor>
+
+QT_BEGIN_NAMESPACE
+class QTextCharFormat;
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+class FormatDescription;
+
+// Format for a particular piece of text (text/comment, etc).
+class TEXTEDITOR_EXPORT Format
+{
+public:
+ Format();
+
+ QColor foreground() const { return m_foreground; }
+ void setForeground(const QColor &foreground);
+
+ QColor background() const { return m_background; }
+ void setBackground(const QColor &background);
+
+ bool bold() const { return m_bold; }
+ void setBold(bool bold);
+
+ bool italic() const { return m_italic; }
+ void setItalic(bool italic);
+
+ bool equals(const Format &f) const;
+
+ QString toString() const;
+ bool fromString(const QString &str);
+
+private:
+ QColor m_foreground;
+ QColor m_background;
+ bool m_bold;
+ bool m_italic;
+};
+
+inline bool operator==(const Format &f1, const Format &f2) { return f1.equals(f2); }
+inline bool operator!=(const Format &f1, const Format &f2) { return !f1.equals(f2); }
+
+/**
+ * Font settings (default font and enumerated list of formats).
+ */
+class TEXTEDITOR_EXPORT FontSettings
+{
+public:
+ typedef QList<FormatDescription> FormatDescriptions;
+
+ FontSettings(const FormatDescriptions &fd);
+ void clear();
+
+ void toSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ QSettings *s) const;
+
+ bool fromSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ const QSettings *s);
+
+ /**
+ * Returns the list of QTextCharFormats that corresponds to the list of
+ * requested format categories.
+ */
+ QVector<QTextCharFormat> toTextCharFormats(const QVector<QString> &categories) const;
+
+ /**
+ * Returns the QTextCharFormat of the given format category.
+ */
+ QTextCharFormat toTextCharFormat(const QString &category) const;
+
+ /**
+ * Returns the configured font family.
+ */
+ QString family() const;
+ void setFamily(const QString &family);
+
+ /**
+ * Returns the configured font size.
+ */
+ int fontSize() const;
+ void setFontSize(int size);
+
+ /**
+ * Returns the format for the given font category.
+ */
+ Format &formatFor(const QString &category);
+
+ bool equals(const FontSettings &f) const;
+
+ static QString defaultFixedFontFamily();
+ static int defaultFontSize();
+
+private:
+ QString m_family;
+ int m_fontSize;
+ QMap<QString, Format> m_formats;
+};
+
+inline bool operator==(const FontSettings &f1, const FontSettings &f2) { return f1.equals(f2); }
+inline bool operator!=(const FontSettings &f1, const FontSettings &f2) { return !f1.equals(f2); }
+
+} // namespace TextEditor
+
+#endif // FONTSETTINGS_H
diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp
new file mode 100644
index 0000000000..1583328fc2
--- /dev/null
+++ b/src/plugins/texteditor/fontsettingspage.cpp
@@ -0,0 +1,465 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fontsettingspage.h"
+#include "fontsettings.h"
+#include "texteditorconstants.h"
+#include "ui_fontsettingspage.h"
+
+#include <utils/settingsutils.h>
+
+#include <QtCore/QSettings>
+#include <QtCore/QTimer>
+#include <QtGui/QListWidget>
+#include <QtGui/QToolButton>
+#include <QtGui/QPalette>
+#include <QtGui/QCheckBox>
+#include <QtGui/QColorDialog>
+#include <QtGui/QTextEdit>
+#include <QtGui/QTextCharFormat>
+#include <QtGui/QComboBox>
+#include <QtGui/QFontDatabase>
+#include <QtGui/QPalette>
+
+static inline QString colorButtonStyleSheet(const QColor &bgColor)
+{
+ if (bgColor.isValid()) {
+ QString rc = QLatin1String("border: 2px solid black; border-radius: 2px; background:");
+ rc += bgColor.name();
+ return rc;
+ }
+ return QLatin1String("border: 2px dotted black; border-radius: 2px;");
+}
+
+namespace TextEditor {
+namespace Internal {
+
+class FontSettingsPagePrivate
+{
+public:
+ FontSettingsPagePrivate(const TextEditor::FormatDescriptions &fd,
+ const QString &name,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core);
+
+ Core::ICore *m_core;
+ const QString m_name;
+ const QString m_settingsGroup;
+ const QString m_category;
+ const QString m_trCategory;
+
+ TextEditor::FormatDescriptions m_descriptions;
+ FontSettings m_value;
+ FontSettings m_lastValue;
+ int m_curItem;
+ Ui::FontSettingsPage ui;
+};
+
+FontSettingsPagePrivate::FontSettingsPagePrivate(const TextEditor::FormatDescriptions &fd,
+ const QString &name,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core) :
+ m_core(core),
+ m_name(name),
+ m_settingsGroup(Core::Utils::settingsKey(category)),
+ m_category(category),
+ m_trCategory(trCategory),
+ m_descriptions(fd),
+ m_value(fd),
+ m_lastValue(fd),
+ m_curItem(-1)
+{
+ bool settingsFound = false;
+ if (m_core)
+ if (const QSettings *settings = m_core->settings())
+ settingsFound = m_value.fromSettings(m_settingsGroup, m_descriptions, settings);
+ if (!settingsFound) { // Apply defaults
+ foreach (const FormatDescription &f, m_descriptions) {
+ const QString name = f.name();
+ m_lastValue.formatFor(name).setForeground(f.foreground());
+ m_lastValue.formatFor(name).setBackground(f.background());
+ m_value.formatFor(name).setForeground(f.foreground());
+ m_value.formatFor(name).setBackground(f.background());
+ }
+ }
+
+ m_lastValue = m_value;
+}
+
+} // namespace Internal
+} // namespace TextEditor
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+// ------- FormatDescription
+FormatDescription::FormatDescription(const QString &name, const QString &trName, const QColor &color) :
+ m_name(name),
+ m_trName(trName)
+{
+ m_format.setForeground(color);
+}
+
+QString FormatDescription::name() const
+{
+ return m_name;
+}
+
+QString FormatDescription::trName() const
+{
+ return m_trName;
+}
+
+QColor FormatDescription::foreground() const
+{
+ if (m_name == QLatin1String("LineNumber"))
+ return QApplication::palette().dark().color();
+ if (m_name == QLatin1String("Parentheses"))
+ return QColor(Qt::red);
+ return m_format.foreground();
+}
+
+void FormatDescription::setForeground(const QColor &foreground)
+{
+ m_format.setForeground(foreground);
+}
+
+QColor FormatDescription::background() const
+{
+ if (m_name == QLatin1String(Constants::C_TEXT))
+ return Qt::white;
+ else if (m_name == QLatin1String(Constants::C_LINE_NUMBER))
+ return QApplication::palette().background().color();
+ else if (m_name == QLatin1String(Constants::C_SEARCH_RESULT))
+ return QColor(0xffef0b);
+ else if (m_name == QLatin1String(Constants::C_PARENTHESES))
+ return QColor(0xb4, 0xee, 0xb4);
+ else if (m_name == QLatin1String(Constants::C_CURRENT_LINE)
+ || m_name == QLatin1String(Constants::C_SEARCH_SCOPE)) {
+ const QPalette palette = QApplication::palette();
+ const QColor &fg = palette.color(QPalette::Highlight);
+ const QColor &bg = palette.color(QPalette::Base);
+
+ qreal smallRatio;
+ qreal largeRatio;
+ if (m_name == QLatin1String(Constants::C_CURRENT_LINE)) {
+ smallRatio = .15;
+ largeRatio = .3;
+ } else {
+ smallRatio = .05;
+ largeRatio = .4;
+ }
+ const qreal ratio = ((palette.color(QPalette::Text).value() < 128)
+ ^ (palette.color(QPalette::HighlightedText).value() < 128)) ? smallRatio : largeRatio;
+
+ const QColor &col = QColor::fromRgbF(fg.redF() * ratio + bg.redF() * (1 - ratio),
+ fg.greenF() * ratio + bg.greenF() * (1 - ratio),
+ fg.blueF() * ratio + bg.blueF() * (1 - ratio));
+ return col;
+ } else if (m_name == QLatin1String(Constants::C_SELECTION)) {
+ const QPalette palette = QApplication::palette();
+ return palette.color(QPalette::Highlight);
+ }
+ return QColor(); // invalid color
+}
+
+
+// ------------ FontSettingsPage
+FontSettingsPage::FontSettingsPage(const FormatDescriptions &fd,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core,
+ QObject *parent) :
+ Core::IOptionsPage(parent),
+ d_ptr(new FontSettingsPagePrivate(fd, tr("Font & Colors"), category, trCategory, core))
+{
+}
+
+FontSettingsPage::~FontSettingsPage()
+{
+ delete d_ptr;
+}
+
+QString FontSettingsPage::name() const
+{
+ return d_ptr->m_name;
+}
+
+QString FontSettingsPage::category() const
+{
+ return d_ptr->m_category;
+}
+
+QString FontSettingsPage::trCategory() const
+{
+ return d_ptr->m_trCategory;
+}
+
+QWidget *FontSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ d_ptr->ui.setupUi(w);
+
+
+ d_ptr->ui.itemListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ foreach (const FormatDescription &d, d_ptr->m_descriptions)
+ d_ptr->ui.itemListWidget->addItem(d.trName());
+
+ QFontDatabase db;
+ const QStringList families = db.families();
+ d_ptr->ui.familyComboBox->addItems(families);
+ const int idx = families.indexOf(d_ptr->m_value.family());
+ d_ptr->ui.familyComboBox->setCurrentIndex(idx);
+
+ connect(d_ptr->ui.familyComboBox, SIGNAL(activated(int)), this, SLOT(updatePointSizes()));
+ connect(d_ptr->ui.sizeComboBox, SIGNAL(activated(int)), this, SLOT(updatePreview()));
+ connect(d_ptr->ui.itemListWidget, SIGNAL(itemSelectionChanged()),
+ this, SLOT(itemChanged()));
+ connect(d_ptr->ui.foregroundToolButton, SIGNAL(clicked()),
+ this, SLOT(changeForeColor()));
+ connect(d_ptr->ui.backgroundToolButton, SIGNAL(clicked()),
+ this, SLOT(changeBackColor()));
+ connect(d_ptr->ui.eraseBackgroundToolButton, SIGNAL(clicked()),
+ this, SLOT(eraseBackColor()));
+ connect(d_ptr->ui.boldCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkCheckBoxes()));
+ connect(d_ptr->ui.italicCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkCheckBoxes()));
+
+ if (!d_ptr->m_descriptions.empty())
+ d_ptr->ui.itemListWidget->setCurrentRow(0);
+
+ updatePointSizes();
+ d_ptr->m_lastValue = d_ptr->m_value;
+ return w;
+}
+
+void FontSettingsPage::itemChanged()
+{
+ QListWidgetItem *item = d_ptr->ui.itemListWidget->currentItem();
+ if (!item)
+ return;
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ if (d_ptr->m_descriptions[i].trName() == item->text()) {
+ d_ptr->m_curItem = i;
+ const Format &format = d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name());
+ d_ptr->ui.foregroundToolButton->setStyleSheet(colorButtonStyleSheet(format.foreground()));
+ d_ptr->ui.backgroundToolButton->setStyleSheet(colorButtonStyleSheet(format.background()));
+
+ d_ptr->ui.eraseBackgroundToolButton->setEnabled(i > 0 && format.background().isValid());
+
+ const bool boldBlocked = d_ptr->ui.boldCheckBox->blockSignals(true);
+ d_ptr->ui.boldCheckBox->setChecked(format.bold());
+ d_ptr->ui.boldCheckBox->blockSignals(boldBlocked);
+ const bool italicBlocked = d_ptr->ui.italicCheckBox->blockSignals(true);
+ d_ptr->ui.italicCheckBox->setChecked(format.italic());
+ d_ptr->ui.italicCheckBox->blockSignals(italicBlocked);
+ updatePreview();
+ break;
+ }
+ }
+}
+
+void FontSettingsPage::changeForeColor()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ QColor color = d_ptr->m_value.formatFor(d_ptr->m_descriptions[d_ptr->m_curItem].name()).foreground();
+ const QColor newColor = QColorDialog::getColor(color, d_ptr->ui.boldCheckBox->window());
+ if (!newColor.isValid())
+ return;
+ QPalette p = d_ptr->ui.foregroundToolButton->palette();
+ p.setColor(QPalette::Active, QPalette::Button, newColor);
+ d_ptr->ui.foregroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor));
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected())
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setForeground(newColor);
+ }
+
+ updatePreview();
+}
+
+void FontSettingsPage::changeBackColor()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ QColor color = d_ptr->m_value.formatFor(d_ptr->m_descriptions[d_ptr->m_curItem].name()).background();
+ const QColor newColor = QColorDialog::getColor(color, d_ptr->ui.boldCheckBox->window());
+ if (!newColor.isValid())
+ return;
+ d_ptr->ui.backgroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor));
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected())
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setBackground(newColor);
+ }
+
+ updatePreview();
+}
+
+void FontSettingsPage::eraseBackColor()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ QColor newColor;
+ d_ptr->ui.backgroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor));
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected())
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setBackground(newColor);
+ }
+
+ updatePreview();
+}
+
+void FontSettingsPage::checkCheckBoxes()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected()) {
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setBold(d_ptr->ui.boldCheckBox->isChecked());
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setItalic(d_ptr->ui.italicCheckBox->isChecked());
+ }
+ }
+ updatePreview();
+}
+
+void FontSettingsPage::updatePreview()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+
+ const Format &currentFormat = d_ptr->m_value.formatFor(d_ptr->m_descriptions[d_ptr->m_curItem].name());
+ const Format &baseFormat = d_ptr->m_value.formatFor(QLatin1String("Text"));
+
+ QPalette pal = QApplication::palette();
+ if (baseFormat.foreground().isValid()) {
+ pal.setColor(QPalette::Text, baseFormat.foreground());
+ pal.setColor(QPalette::Foreground, baseFormat.foreground());
+ }
+ if (baseFormat.background().isValid())
+ pal.setColor(QPalette::Base, baseFormat.background());
+
+ d_ptr->ui.previewTextEdit->setPalette(pal);
+
+ QTextCharFormat format;
+ if (currentFormat.foreground().isValid())
+ format.setForeground(QBrush(currentFormat.foreground()));
+ if (currentFormat.background().isValid())
+ format.setBackground(QBrush(currentFormat.background()));
+ format.setFontFamily(d_ptr->ui.familyComboBox->currentText());
+ bool ok;
+ int size = d_ptr->ui.sizeComboBox->currentText().toInt(&ok);
+ if (!ok) {
+ size = QFont().pointSize();
+ }
+ format.setFontPointSize(size);
+ format.setFontItalic(currentFormat.italic());
+ if (currentFormat.bold())
+ format.setFontWeight(QFont::Bold);
+ d_ptr->ui.previewTextEdit->setCurrentCharFormat(format);
+
+ d_ptr->ui.previewTextEdit->setPlainText(tr("\n\tThis is only an example."));
+}
+
+void FontSettingsPage::updatePointSizes()
+{
+ const int oldSize = d_ptr->m_value.fontSize();
+ if (d_ptr->ui.sizeComboBox->count()) {
+ const QString curSize = d_ptr->ui.sizeComboBox->currentText();
+ bool ok = true;
+ int oldSize = curSize.toInt(&ok);
+ if (!ok)
+ oldSize = d_ptr->m_value.fontSize();
+ d_ptr->ui.sizeComboBox->clear();
+ }
+ QFontDatabase db;
+ const QList<int> sizeLst = db.pointSizes(d_ptr->ui.familyComboBox->currentText());
+ int idx = 0;
+ int i = 0;
+ for (; i<sizeLst.count(); ++i) {
+ if (idx == 0 && sizeLst.at(i) >= oldSize)
+ idx = i;
+ d_ptr->ui.sizeComboBox->addItem(QString::number(sizeLst.at(i)));
+ }
+ if (d_ptr->ui.sizeComboBox->count())
+ d_ptr->ui.sizeComboBox->setCurrentIndex(idx);
+ updatePreview();
+}
+
+void FontSettingsPage::delayedChange()
+{
+ emit changed(d_ptr->m_value);
+}
+
+void FontSettingsPage::finished(bool accepted)
+{
+ if (!accepted) {
+ d_ptr->m_value = d_ptr->m_lastValue;
+ return;
+ }
+
+ d_ptr->m_value.setFamily(d_ptr->ui.familyComboBox->currentText());
+
+ bool ok = true;
+ const int size = d_ptr->ui.sizeComboBox->currentText().toInt(&ok);
+ if (ok)
+ d_ptr->m_value.setFontSize(size);
+
+
+ if (d_ptr->m_value != d_ptr->m_lastValue) {
+ d_ptr->m_lastValue = d_ptr->m_value;
+ if (d_ptr->m_core)
+ if (QSettings *settings = d_ptr->m_core->settings())
+ d_ptr->m_value.toSettings(d_ptr->m_settingsGroup, d_ptr->m_descriptions, settings);
+
+ QTimer::singleShot(0, this, SLOT(delayedChange()));
+ }
+}
+
+const FontSettings &FontSettingsPage::fontSettings() const
+{
+ return d_ptr->m_value;
+}
diff --git a/src/plugins/texteditor/fontsettingspage.h b/src/plugins/texteditor/fontsettingspage.h
new file mode 100644
index 0000000000..86599e70d4
--- /dev/null
+++ b/src/plugins/texteditor/fontsettingspage.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FONTSETTINGSPAGE_H
+#define FONTSETTINGSPAGE_H
+
+#include "texteditor_global.h"
+
+#include "fontsettings.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtGui/QColor>
+#include <QtGui/QTextCharFormat>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+namespace Internal {
+class FontSettingsPagePrivate;
+} // namespace Internal
+
+// GUI description of a format consisting of name (settings key)
+// and trName to be displayed
+class TEXTEDITOR_EXPORT FormatDescription
+{
+public:
+ FormatDescription(const QString &name, const QString &trName,
+ const QColor &foreground = Qt::black);
+
+ QString name() const;
+
+ QString trName() const;
+
+ QColor foreground() const;
+ void setForeground(const QColor &foreground);
+
+ QColor background() const;
+
+private:
+ QString m_name; // Name of the category
+ QString m_trName; // Displayed name of the category
+ Format m_format; // Default format
+};
+
+typedef QList<FormatDescription> FormatDescriptions;
+
+class TEXTEDITOR_EXPORT FontSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ FontSettingsPage(const FormatDescriptions &fd,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core,
+ QObject *parent = 0);
+
+ ~FontSettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ const FontSettings &fontSettings() const;
+
+signals:
+ void changed(const TextEditor::FontSettings&);
+
+private slots:
+ void delayedChange();
+ void itemChanged();
+ void changeForeColor();
+ void changeBackColor();
+ void eraseBackColor();
+ void checkCheckBoxes();
+ void updatePointSizes();
+ void updatePreview();
+
+private:
+ Internal::FontSettingsPagePrivate *d_ptr;
+};
+
+} // namespace TextEditor
+
+#endif // FONTSETTINGSPAGE_H
diff --git a/src/plugins/texteditor/fontsettingspage.ui b/src/plugins/texteditor/fontsettingspage.ui
new file mode 100644
index 0000000000..770d5e2935
--- /dev/null
+++ b/src/plugins/texteditor/fontsettingspage.ui
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TextEditor::Internal::FontSettingsPage</class>
+ <widget class="QWidget" name="TextEditor::Internal::FontSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>572</width>
+ <height>471</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>General Font Settings</string>
+ </property>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Family:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="familyComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Size:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="sizeComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Item Specific Settings</string>
+ </property>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="itemListWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="boldCheckBox">
+ <property name="text">
+ <string>Bold</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="italicCheckBox">
+ <property name="text">
+ <string>Italic</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QToolButton" name="foregroundToolButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Background:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Foreground:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="backgroundToolButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="eraseBackgroundToolButton">
+ <property name="toolTip">
+ <string>Erase background</string>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::LeftArrow</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Preview:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="previewTextEdit">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/texteditor/generalsettingspage.cpp b/src/plugins/texteditor/generalsettingspage.cpp
new file mode 100644
index 0000000000..7f056d8ca4
--- /dev/null
+++ b/src/plugins/texteditor/generalsettingspage.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "displaysettings.h"
+#include "generalsettingspage.h"
+#include "storagesettings.h"
+#include "tabsettings.h"
+#include "ui_generalsettingspage.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QDebug>
+
+using namespace TextEditor;
+
+struct GeneralSettingsPage::GeneralSettingsPagePrivate {
+ GeneralSettingsPagePrivate(Core::ICore *core,
+ const GeneralSettingsPageParameters &p);
+
+ Core::ICore *m_core;
+ const GeneralSettingsPageParameters m_parameters;
+ Ui::generalSettingsPage m_page;
+ TabSettings m_tabSettings;
+ StorageSettings m_storageSettings;
+ DisplaySettings m_displaySettings;
+};
+
+GeneralSettingsPage::GeneralSettingsPagePrivate::GeneralSettingsPagePrivate(Core::ICore *core,
+ const GeneralSettingsPageParameters &p) :
+ m_core(core),
+ m_parameters(p)
+{
+ if (m_core)
+ if (const QSettings *s = m_core->settings()) {
+ m_tabSettings.fromSettings(m_parameters.settingsPrefix, s);
+ m_storageSettings.fromSettings(m_parameters.settingsPrefix, s);
+ m_displaySettings.fromSettings(m_parameters.settingsPrefix, s);
+ }
+}
+
+GeneralSettingsPage::GeneralSettingsPage(Core::ICore *core,
+ const GeneralSettingsPageParameters &p,
+ QObject *parent) :
+ Core::IOptionsPage(parent),
+ m_d(new GeneralSettingsPagePrivate(core, p))
+{
+}
+
+GeneralSettingsPage::~GeneralSettingsPage()
+{
+ delete m_d;
+}
+
+QString GeneralSettingsPage::name() const
+{
+ return m_d->m_parameters.name;
+}
+
+QString GeneralSettingsPage::category() const
+{
+ return m_d->m_parameters.category;
+}
+
+QString GeneralSettingsPage::trCategory() const
+{
+ return m_d->m_parameters.trCategory;
+}
+
+QWidget *GeneralSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_d->m_page.setupUi(w);
+
+ settingsToUI();
+
+ return w;
+}
+
+void GeneralSettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ TabSettings newTabSettings;
+ StorageSettings newStorageSettings;
+ DisplaySettings newDisplaySettings;
+ settingsFromUI(newTabSettings, newStorageSettings, newDisplaySettings);
+
+ if (newTabSettings != m_d->m_tabSettings) {
+ m_d->m_tabSettings = newTabSettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_tabSettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit tabSettingsChanged(newTabSettings);
+ }
+
+ if (newStorageSettings != m_d->m_storageSettings) {
+ m_d->m_storageSettings = newStorageSettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_storageSettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit storageSettingsChanged(newStorageSettings);
+ }
+
+ if (newDisplaySettings != m_d->m_displaySettings) {
+ m_d->m_displaySettings = newDisplaySettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_displaySettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit displaySettingsChanged(newDisplaySettings);
+ }
+}
+
+void GeneralSettingsPage::settingsFromUI(TabSettings &rc,
+ StorageSettings &storageSettings,
+ DisplaySettings &displaySettings) const
+{
+ rc.m_spacesForTabs = m_d->m_page.insertSpaces->isChecked();
+ rc.m_autoIndent = m_d->m_page.autoIndent->isChecked();
+ rc.m_smartBackspace = m_d->m_page.smartBackspace->isChecked();
+ rc.m_tabSize = m_d->m_page.tabSize->value();
+ rc.m_indentSize = m_d->m_page.indentSize->value();
+
+ storageSettings.m_cleanWhitespace = m_d->m_page.cleanWhitespace->isChecked();
+ storageSettings.m_inEntireDocument = m_d->m_page.inEntireDocument->isChecked();
+ storageSettings.m_addFinalNewLine = m_d->m_page.addFinalNewLine->isChecked();
+
+ displaySettings.m_displayLineNumbers = m_d->m_page.displayLineNumbers->isChecked();
+ displaySettings.m_textWrapping = m_d->m_page.enableTextWrapping->isChecked();
+ displaySettings.m_showWrapColumn = m_d->m_page.showWrapColumn->isChecked();
+ displaySettings.m_wrapColumn = m_d->m_page.wrapColumn->value();
+ displaySettings.m_visualizeWhitespace = m_d->m_page.visualizeWhitespace->isChecked();
+ displaySettings.m_displayFoldingMarkers = m_d->m_page.displayFoldingMarkers->isChecked();
+ displaySettings.m_highlightCurrentLine = m_d->m_page.highlightCurrentLine->isChecked();
+}
+
+void GeneralSettingsPage::settingsToUI()
+{
+ TabSettings rc = m_d->m_tabSettings;
+ m_d->m_page.insertSpaces->setChecked(rc.m_spacesForTabs);
+ m_d->m_page.autoIndent->setChecked(rc.m_autoIndent);
+ m_d->m_page.smartBackspace->setChecked(rc.m_smartBackspace);
+ m_d->m_page.tabSize->setValue(rc.m_tabSize);
+ m_d->m_page.indentSize->setValue(rc.m_indentSize);
+
+ StorageSettings storageSettings = m_d->m_storageSettings;
+ m_d->m_page.cleanWhitespace->setChecked(storageSettings.m_cleanWhitespace);
+ m_d->m_page.inEntireDocument->setChecked(storageSettings.m_inEntireDocument);
+ m_d->m_page.addFinalNewLine->setChecked(storageSettings.m_addFinalNewLine);
+
+ DisplaySettings displaySettings = m_d->m_displaySettings;
+ m_d->m_page.displayLineNumbers->setChecked(displaySettings.m_displayLineNumbers);
+ m_d->m_page.enableTextWrapping->setChecked(displaySettings.m_textWrapping);
+ m_d->m_page.showWrapColumn->setChecked(displaySettings.m_showWrapColumn);
+ m_d->m_page.wrapColumn->setValue(displaySettings.m_wrapColumn);
+ m_d->m_page.visualizeWhitespace->setChecked(displaySettings.m_visualizeWhitespace);
+ m_d->m_page.displayFoldingMarkers->setChecked(displaySettings.m_displayFoldingMarkers);
+ m_d->m_page.highlightCurrentLine->setChecked(displaySettings.m_highlightCurrentLine);
+}
+
+TabSettings GeneralSettingsPage::tabSettings() const
+{
+ return m_d->m_tabSettings;
+}
+
+StorageSettings GeneralSettingsPage::storageSettings() const
+{
+ return m_d->m_storageSettings;
+}
+
+DisplaySettings GeneralSettingsPage::displaySettings() const
+{
+ return m_d->m_displaySettings;
+}
+
+void GeneralSettingsPage::setDisplaySettings(const DisplaySettings &newDisplaySettings)
+{
+ if (newDisplaySettings != m_d->m_displaySettings) {
+ m_d->m_displaySettings = newDisplaySettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_displaySettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit displaySettingsChanged(newDisplaySettings);
+ }
+}
diff --git a/src/plugins/texteditor/generalsettingspage.h b/src/plugins/texteditor/generalsettingspage.h
new file mode 100644
index 0000000000..184e3bace8
--- /dev/null
+++ b/src/plugins/texteditor/generalsettingspage.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GENERALSETTINGSPAGE_H
+#define GENERALSETTINGSPAGE_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtCore/QObject>
+
+namespace TextEditor {
+
+struct TabSettings;
+struct StorageSettings;
+struct DisplaySettings;
+
+struct TEXTEDITOR_EXPORT GeneralSettingsPageParameters {
+ QString name;
+ QString category;
+ QString trCategory;
+ QString settingsPrefix;
+};
+
+class Ui_generalSettingsPage;
+
+class TEXTEDITOR_EXPORT GeneralSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ GeneralSettingsPage(Core::ICore *core,
+ const GeneralSettingsPageParameters &p,
+ QObject *parent);
+ virtual ~GeneralSettingsPage();
+
+ //IOptionsPage
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ TabSettings tabSettings() const;
+ StorageSettings storageSettings() const;
+ DisplaySettings displaySettings() const;
+
+ void setDisplaySettings(const DisplaySettings &);
+
+signals:
+ void tabSettingsChanged(const TextEditor::TabSettings &);
+ void storageSettingsChanged(const TextEditor::StorageSettings &);
+ void displaySettingsChanged(const TextEditor::DisplaySettings &);
+
+private:
+ void settingsFromUI(TabSettings &rc,
+ StorageSettings &storageSettings,
+ DisplaySettings &displaySettings) const;
+ void settingsToUI();
+ struct GeneralSettingsPagePrivate;
+ GeneralSettingsPagePrivate *m_d;
+};
+
+} // namespace TextEditor
+
+#endif // GENERALSETTINGSPAGE_H
diff --git a/src/plugins/texteditor/generalsettingspage.ui b/src/plugins/texteditor/generalsettingspage.ui
new file mode 100644
index 0000000000..11f6b8b997
--- /dev/null
+++ b/src/plugins/texteditor/generalsettingspage.ui
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TextEditor::generalSettingsPage</class>
+ <widget class="QWidget" name="TextEditor::generalSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>514</width>
+ <height>427</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="title">
+ <string>Tab/Indent Settings</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="autoIndent">
+ <property name="text">
+ <string>Enable automatic &amp;indentation</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="labelTabSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Ta&amp;b size:</string>
+ </property>
+ <property name="buddy">
+ <cstring>tabSize</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>5</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="tabSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="insertSpaces">
+ <property name="text">
+ <string>Insert &amp;spaces instead of tabs</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="labelIndentSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Indent size:</string>
+ </property>
+ <property name="buddy">
+ <cstring>indentSize</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>5</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="indentSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="smartBackspace">
+ <property name="text">
+ <string>&amp;Backspace follows indentation</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Storage Settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="cleanWhitespace">
+ <property name="text">
+ <string>&amp;Clean whitespace</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="inEntireDocument">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>In entire &amp;document</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="addFinalNewLine">
+ <property name="text">
+ <string>&amp;Ensure newline at end of file</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Display Settings</string>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="showWrapColumn">
+ <property name="text">
+ <string>Display right &amp;margin at column</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="wrapColumn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximum">
+ <number>999</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="enableTextWrapping">
+ <property name="text">
+ <string>Enable text &amp;wrapping</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="displayLineNumbers">
+ <property name="text">
+ <string>Display line &amp;numbers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="visualizeWhitespace">
+ <property name="text">
+ <string>&amp;Visualize whitespace</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="displayFoldingMarkers">
+ <property name="text">
+ <string>Display &amp;folding markers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="highlightCurrentLine">
+ <property name="text">
+ <string>Highlight current &amp;line</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>351</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cleanWhitespace</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>inEntireDocument</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>47</x>
+ <y>184</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>91</x>
+ <y>212</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>showWrapColumn</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>wrapColumn</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>399</x>
+ <y>308</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>474</x>
+ <y>308</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h
new file mode 100644
index 0000000000..46dc3f8b3d
--- /dev/null
+++ b/src/plugins/texteditor/icompletioncollector.h
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPLETIONCOLLECTORINTERFACE_H
+#define COMPLETIONCOLLECTORINTERFACE_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtGui/QIcon>
+#include <QtGui/QKeyEvent>
+
+namespace TextEditor {
+
+class ICompletionCollector;
+class ITextEditable;
+
+struct CompletionItem
+{
+ CompletionItem(ICompletionCollector *collector = 0)
+ : m_relevance(0),
+ m_collector(collector)
+ { }
+
+ bool isValid() const
+ { return m_collector != 0; }
+
+ operator bool() const
+ { return m_collector != 0; }
+
+ QString m_text;
+ QString m_details;
+ QIcon m_icon;
+ QVariant m_data;
+ int m_relevance;
+ ICompletionCollector *m_collector;
+};
+
+/* Defines the interface to completion collectors. A completion collector tells
+ * the completion support code when a completion is triggered and provides the
+ * list of possible completions. It keeps an internal state so that it can be
+ * polled for the list of completions, which is reset with a call to reset.
+ */
+class TEXTEDITOR_EXPORT ICompletionCollector : public QObject
+{
+ Q_OBJECT
+public:
+ ICompletionCollector(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ICompletionCollector() {}
+
+ /* This method should return whether the cursor is at a position which could
+ * trigger an autocomplete. It will be called each time a character is typed in
+ * the text editor.
+ */
+ virtual bool triggersCompletion(ITextEditable *editor) = 0;
+
+ // returns starting position
+ virtual int startCompletion(ITextEditable *editor) = 0;
+
+ /* This method should add all the completions it wants to show into the list,
+ * based on the given cursor position.
+ */
+ virtual void completions(QList<CompletionItem> *completions) = 0;
+
+ /* This method should complete the given completion item.
+ */
+ virtual void complete(const CompletionItem &item) = 0;
+
+ /* This method gives the completion collector a chance to partially complete
+ * based on a set of items. The general use case is to complete the common
+ * prefix shared by all possible completion items.
+ *
+ * Returns whether the completion popup should be closed.
+ */
+ virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems) = 0;
+
+ /* Called when it's safe to clean up the completion items.
+ */
+ virtual void cleanup() = 0;
+};
+
+} // namespace TextEditor
+
+#endif // COMPLETIONCOLLECTORINTERFACE_H
diff --git a/src/plugins/texteditor/images/finddirectory.png b/src/plugins/texteditor/images/finddirectory.png
new file mode 100644
index 0000000000..f20c7d013e
--- /dev/null
+++ b/src/plugins/texteditor/images/finddirectory.png
Binary files differ
diff --git a/src/plugins/texteditor/images/finddocuments.png b/src/plugins/texteditor/images/finddocuments.png
new file mode 100644
index 0000000000..a637456b58
--- /dev/null
+++ b/src/plugins/texteditor/images/finddocuments.png
Binary files differ
diff --git a/src/plugins/texteditor/itexteditable.h b/src/plugins/texteditor/itexteditable.h
new file mode 100644
index 0000000000..30ec5e1493
--- /dev/null
+++ b/src/plugins/texteditor/itexteditable.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ITEXTEDITABLE_H
+#define ITEXTEDITABLE_H
+
+#include "texteditor_global.h"
+#include "itexteditor.h"
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT ITextEditable : public ITextEditor
+{
+ Q_OBJECT
+public:
+ ITextEditable() {}
+ virtual ~ITextEditable() {}
+
+ /* Removes 'length' characteres to the right of the cursor. */
+ virtual void remove(int length) = 0;
+
+ /* Inserts the given string to the right of the cursor. */
+ virtual void insert(const QString &string) = 0;
+
+ /* Replaces 'length' characters to the right of the cursor with the given string. */
+ virtual void replace(int length, const QString &string) = 0;
+
+ virtual void setCurPos(int pos) = 0;
+
+ virtual void select(int toPos) = 0;
+};
+
+} // namespace TextEditor
+
+#endif // ITEXTEDITABLE_H
diff --git a/src/plugins/texteditor/itexteditor.h b/src/plugins/texteditor/itexteditor.h
new file mode 100644
index 0000000000..ca517577a0
--- /dev/null
+++ b/src/plugins/texteditor/itexteditor.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ITEXTEDITOR_H
+#define ITEXTEDITOR_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtGui/QColor>
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+class ITextEditor;
+
+class TEXTEDITOR_EXPORT ITextMark : public QObject
+{
+ Q_OBJECT
+public:
+ ITextMark(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ITextMark() {}
+
+ virtual QIcon icon() const = 0;
+
+ virtual void updateLineNumber(int lineNumber) = 0;
+ virtual void updateBlock(const QTextBlock &block) = 0;
+ virtual void removedFromEditor() = 0;
+ virtual void documentClosing() = 0;
+};
+
+typedef QList<ITextMark *> TextMarks;
+
+
+class TEXTEDITOR_EXPORT ITextMarkable : public QObject
+{
+ Q_OBJECT
+public:
+ ITextMarkable(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ITextMarkable() {}
+ virtual bool addMark(ITextMark *mark, int line) = 0;
+
+ virtual TextMarks marksAt(int line) const = 0;
+ virtual void removeMark(ITextMark *mark) = 0;
+ virtual bool hasMark(ITextMark *mark) const = 0;
+ virtual void updateMark(ITextMark *mark) = 0;
+};
+
+class TEXTEDITOR_EXPORT ITextEditor : public Core::IEditor
+{
+ Q_OBJECT
+public:
+ enum PositionOperation {
+ Current = 1,
+ EndOfLine = 2,
+ StartOfLine = 3,
+ Anchor = 4,
+ EndOfDoc = 5
+ };
+
+ ITextEditor() {}
+ virtual ~ITextEditor() {}
+
+ virtual int find(const QString &string) const = 0;
+
+ virtual void gotoLine(int line, int column = 0) = 0;
+
+ virtual int position(PositionOperation posOp = Current, int at = -1) const = 0;
+ virtual void convertPosition(int pos, int *line, int *column) const = 0;
+ virtual QRect cursorRect(int pos = -1) const = 0;
+
+ virtual QString contents() const = 0;
+ virtual QString selectedText() const = 0;
+ virtual QString textAt(int pos, int length) const = 0;
+ virtual QChar characterAt(int pos) const = 0;
+
+ virtual void triggerCompletions() = 0;
+
+ virtual ITextMarkable *markableInterface() = 0;
+
+ virtual void setContextHelpId(const QString &) = 0;
+
+ virtual void setTextCodec(QTextCodec *) = 0;
+ virtual QTextCodec *textCodec() const = 0;
+
+
+signals:
+ void contentsChanged();
+ void markRequested(TextEditor::ITextEditor *editor, int line);
+ void tooltipRequested(TextEditor::ITextEditor *editor, const QPoint &globalPos, int position);
+ void contextHelpIdRequested(TextEditor::ITextEditor *editor, int position);
+};
+
+} // namespace TextEditor
+
+#endif // ITEXTEDITOR_H
diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp
new file mode 100644
index 0000000000..ea079196f7
--- /dev/null
+++ b/src/plugins/texteditor/linenumberfilter.cpp
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "linenumberfilter.h"
+#include "itexteditor.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QVariant>
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+LineNumberFilter::LineNumberFilter(EditorManager *editorManager, QObject *parent):
+ IQuickOpenFilter(parent)
+{
+ m_editorManager = editorManager;
+ setShortcutString("l");
+ setIncludedByDefault(true);
+}
+
+QList<FilterEntry> LineNumberFilter::matchesFor(const QString &entry)
+{
+ bool ok;
+ QList<FilterEntry> value;
+ int line = entry.toInt(&ok);
+ if (line > 0 && currentTextEditor())
+ value.append(FilterEntry(this, QString("Line %1").arg(line), QVariant(line)));
+ return value;
+}
+
+void LineNumberFilter::accept(FilterEntry selection) const
+{
+ ITextEditor *editor = currentTextEditor();
+ if (editor) {
+ m_editorManager->ensureEditorManagerVisible();
+ m_editorManager->addCurrentPositionToNavigationHistory(true);
+ editor->gotoLine(selection.internalData.toInt());
+ m_editorManager->addCurrentPositionToNavigationHistory();
+ editor->widget()->setFocus();
+ }
+}
+
+ITextEditor *LineNumberFilter::currentTextEditor() const
+{
+ if (!m_editorManager->currentEditor())
+ return 0;
+ return qobject_cast<TextEditor::ITextEditor*>(m_editorManager->currentEditor());
+}
diff --git a/src/plugins/texteditor/linenumberfilter.h b/src/plugins/texteditor/linenumberfilter.h
new file mode 100644
index 0000000000..f20de8a718
--- /dev/null
+++ b/src/plugins/texteditor/linenumberfilter.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LINENUMBERFILTER_H
+#define LINENUMBERFILTER_H
+
+#include <quickopen/iquickopenfilter.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+#include <QtGui/QWidget>
+
+namespace Core {
+class EditorManager;
+}
+
+namespace TextEditor {
+
+class ITextEditor;
+
+namespace Internal {
+
+class LineNumberFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ LineNumberFilter(Core::EditorManager *editorManager, QObject *parent = 0);
+ QString trName() const { return tr("Line in current document"); }
+ QString name() const { return "Line in current document"; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::High; }
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &) {}
+
+private:
+ ITextEditor *currentTextEditor() const;
+
+ Core::EditorManager *m_editorManager;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // LINENUMBERFILTER_H
diff --git a/src/plugins/texteditor/plaintexteditor.cpp b/src/plugins/texteditor/plaintexteditor.cpp
new file mode 100644
index 0000000000..6019d73b25
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditor.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plaintexteditor.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+PlainTextEditorEditable::PlainTextEditorEditable(PlainTextEditor *editor)
+ :BaseTextEditorEditable(editor)
+{
+ Core::ICore *core = TextEditorPlugin::core();
+ m_context << core->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::K_DEFAULT_TEXT_EDITOR);
+ m_context << core->uniqueIDManager()->
+ uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+}
+
+PlainTextEditor::PlainTextEditor(QWidget *parent) :
+ BaseTextEditor(parent)
+{
+
+ setRevisionsVisible(true);
+ setMarksVisible(true);
+ setRequestMarkEnabled(false);
+ setLineSeparatorsAllowed(true);
+
+ setMimeType(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT));
+}
+
+QList<int> PlainTextEditorEditable::context() const
+{
+ return m_context;
+}
+
+
+Core::IEditor *PlainTextEditorEditable::duplicate(QWidget *parent)
+{
+ PlainTextEditor *newEditor = new PlainTextEditor(parent);
+ newEditor->duplicateFrom(editor());
+ TextEditorPlugin::instance()->initializeEditor(newEditor);
+ return newEditor->editableInterface();
+}
+
+const char *PlainTextEditorEditable::kind() const
+{
+ return Core::Constants::K_DEFAULT_TEXT_EDITOR;
+}
+
+// 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::indentBlock(QTextDocument *doc, QTextBlock block, QChar /* 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 non-alphanumerical characters when determining the indentation
+ // to enable writing bulleted lists whose items span several lines.
+ int i = 0;
+ while (i < previousText.size()) {
+ if (previousText.at(i).isLetterOrNumber()) {
+ const TextEditor::TabSettings &ts = tabSettings();
+ ts.indentLine(block, ts.columnAt(previousText, i));
+ break;
+ }
+ ++i;
+ }
+}
diff --git a/src/plugins/texteditor/plaintexteditor.h b/src/plugins/texteditor/plaintexteditor.h
new file mode 100644
index 0000000000..7641580789
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditor.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLAINTEXTEDITOR_H
+#define PLAINTEXTEDITOR_H
+
+#include "basetexteditor.h"
+
+#include <QtCore/QList>
+
+namespace TextEditor {
+
+class PlainTextEditor;
+
+class TEXTEDITOR_EXPORT PlainTextEditorEditable : public BaseTextEditorEditable
+{
+public:
+ PlainTextEditorEditable(PlainTextEditor *);
+ QList<int> context() const;
+
+ bool duplicateSupported() const { return true; }
+ Core::IEditor *duplicate(QWidget *parent);
+ const char *kind() const;
+private:
+ QList<int> m_context;
+};
+
+class TEXTEDITOR_EXPORT PlainTextEditor : public BaseTextEditor
+{
+ Q_OBJECT
+
+public:
+ PlainTextEditor(QWidget *parent);
+
+protected:
+ BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }
+ // Indent a text block based on previous line.
+ virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+};
+
+} // namespace TextEditor
+
+#endif // PLAINTEXTEDITOR_H
diff --git a/src/plugins/texteditor/plaintexteditorfactory.cpp b/src/plugins/texteditor/plaintexteditorfactory.cpp
new file mode 100644
index 0000000000..24e36bfff6
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditorfactory.cpp
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plaintexteditor.h"
+#include "plaintexteditorfactory.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+#include "texteditoractionhandler.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+PlainTextEditorFactory::PlainTextEditorFactory(QObject *parent) :
+ Core::IEditorFactory(parent),
+ m_kind(Core::Constants::K_DEFAULT_TEXT_EDITOR)
+{
+ m_actionHandler = new TextEditorActionHandler(TextEditorPlugin::core(),
+ QLatin1String(TextEditor::Constants::C_TEXTEDITOR),
+ TextEditorActionHandler::Format);
+ m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT)
+ << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_XML);
+}
+
+PlainTextEditorFactory::~PlainTextEditorFactory()
+{
+ delete m_actionHandler;
+}
+
+QString PlainTextEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *PlainTextEditorFactory::open(const QString &fileName)
+{
+ Core::ICore *core = TextEditorPlugin::core();
+ Core::IEditor *iface = core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *PlainTextEditorFactory::createEditor(QWidget *parent)
+{
+ PlainTextEditor *rc = new PlainTextEditor(parent);
+ TextEditorPlugin::instance()->initializeEditor(rc);
+ return rc->editableInterface();
+}
+
+QStringList PlainTextEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
diff --git a/src/plugins/texteditor/plaintexteditorfactory.h b/src/plugins/texteditor/plaintexteditorfactory.h
new file mode 100644
index 0000000000..0e225c942e
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditorfactory.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLAINTEXTEDITORFACTORY_H
+#define PLAINTEXTEDITORFACTORY_H
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <QtCore/QStringList>
+
+namespace Core {
+class IEditor;
+class IFile;
+}
+
+namespace TextEditor {
+class TextEditorActionHandler;
+namespace Internal {
+
+class PlainTextEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ PlainTextEditorFactory(QObject *parent = 0);
+ virtual ~PlainTextEditorFactory();
+
+ virtual QStringList mimeTypes() const;
+ //Core::IEditorFactory
+ QString kind() const;
+ Core::IFile *open(const QString &fileName);
+ Core::IEditor *createEditor(QWidget *parent);
+
+ TextEditor::TextEditorActionHandler *actionHandler() const { return m_actionHandler; }
+
+private:
+ const QString m_kind;
+ QStringList m_mimeTypes;
+ TextEditor::TextEditorActionHandler *m_actionHandler;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // PLAINTEXTEDITORFACTORY_H
diff --git a/src/plugins/texteditor/storagesettings.cpp b/src/plugins/texteditor/storagesettings.cpp
new file mode 100644
index 0000000000..906215bf81
--- /dev/null
+++ b/src/plugins/texteditor/storagesettings.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "storagesettings.h"
+#include <QSettings>
+#include <QString>
+
+namespace TextEditor {
+
+static const char * const cleanWhitespaceKey = "cleanWhitespace";
+static const char * const inEntireDocumentKey = "inEntireDocument";
+static const char * const addFinalNewLineKey = "addFinalNewLine";
+static const char * const groupPostfix = "StorageSettings";
+
+StorageSettings::StorageSettings()
+ : m_cleanWhitespace(true),
+ m_inEntireDocument(false),
+ m_addFinalNewLine(true)
+{
+}
+
+void StorageSettings::toSettings(const QString &category, QSettings *s) const
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ s->beginGroup(group);
+ s->setValue(QLatin1String(cleanWhitespaceKey), m_cleanWhitespace);
+ s->setValue(QLatin1String(inEntireDocumentKey), m_inEntireDocument);
+ s->setValue(QLatin1String(addFinalNewLineKey), m_addFinalNewLine);
+ s->endGroup();
+}
+
+void StorageSettings::fromSettings(const QString &category, const QSettings *s)
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ group += QLatin1Char('/');
+ m_cleanWhitespace = s->value(group + QLatin1String(cleanWhitespaceKey), m_cleanWhitespace).toBool();
+ m_inEntireDocument = s->value(group + QLatin1String(inEntireDocumentKey), m_inEntireDocument).toBool();
+ m_addFinalNewLine = s->value(group + QLatin1String(addFinalNewLineKey), m_addFinalNewLine).toBool();
+}
+
+bool StorageSettings::equals(const StorageSettings &ts) const
+{
+ return m_addFinalNewLine == ts.m_addFinalNewLine
+ && m_cleanWhitespace == ts.m_cleanWhitespace
+ && m_inEntireDocument == ts.m_inEntireDocument;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/storagesettings.h b/src/plugins/texteditor/storagesettings.h
new file mode 100644
index 0000000000..dc3310094a
--- /dev/null
+++ b/src/plugins/texteditor/storagesettings.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef STORAGESETTINGS_H
+#define STORAGESETTINGS_H
+
+#include "texteditor_global.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+struct TEXTEDITOR_EXPORT StorageSettings {
+ StorageSettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, const QSettings *s);
+
+ bool equals(const StorageSettings &ts) const;
+
+ bool m_cleanWhitespace;
+ bool m_inEntireDocument;
+ bool m_addFinalNewLine;
+};
+
+inline bool operator==(const StorageSettings &t1, const StorageSettings &t2) { return t1.equals(t2); }
+inline bool operator!=(const StorageSettings &t1, const StorageSettings &t2) { return !t1.equals(t2); }
+
+} // namespace TextEditor
+
+#endif // STORAGESETTINGS_H
diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp
new file mode 100644
index 0000000000..daaee1a562
--- /dev/null
+++ b/src/plugins/texteditor/tabsettings.cpp
@@ -0,0 +1,241 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "tabsettings.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QString>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextDocument>
+#include <QDebug>
+
+static const char* spacesForTabsKey = "SpacesForTabs";
+static const char* smartBackspaceKey = "SmartBackspace";
+static const char* autoIndentKey = "AutoIndent";
+static const char* tabSizeKey = "TabSize";
+static const char* indentSizeKey = "IndentSize";
+static const char* groupPostfix = "TabSettings";
+
+namespace TextEditor {
+
+TabSettings::TabSettings() :
+ m_spacesForTabs(true),
+ m_autoIndent(true),
+ m_smartBackspace(false),
+ m_tabSize(8),
+ m_indentSize(4)
+{
+}
+
+void TabSettings::toSettings(const QString &category, QSettings *s) const
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ s->beginGroup(group);
+ s->setValue(QLatin1String(spacesForTabsKey), m_spacesForTabs);
+ s->setValue(QLatin1String(autoIndentKey), m_autoIndent);
+ s->setValue(QLatin1String(smartBackspaceKey), m_smartBackspace);
+ s->setValue(QLatin1String(tabSizeKey), m_tabSize);
+ s->setValue(QLatin1String(indentSizeKey), m_indentSize);
+ s->endGroup();
+}
+
+void TabSettings::fromSettings(const QString &category, const QSettings *s)
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ group += QLatin1Char('/');
+
+ *this = TabSettings(); // Assign defaults
+
+ m_spacesForTabs = s->value(group + QLatin1String(spacesForTabsKey), m_spacesForTabs).toBool();
+ m_autoIndent = s->value(group + QLatin1String(autoIndentKey), m_autoIndent).toBool();
+ m_smartBackspace = s->value(group + QLatin1String(smartBackspaceKey), m_smartBackspace).toBool();
+ m_tabSize = s->value(group + QLatin1String(tabSizeKey), m_tabSize).toInt();
+ m_indentSize = s->value(group + QLatin1String(indentSizeKey), m_indentSize).toInt();
+}
+
+
+
+int TabSettings::lineIndentPosition(const QString &text) const
+{
+ int i = 0;
+ while (i < text.size()) {
+ if (!text.at(i).isSpace())
+ break;
+ ++i;
+ }
+ int column = columnAt(text, i);
+ return i - (column % m_indentSize);
+}
+
+int TabSettings::firstNonSpace(const QString &text) const
+{
+ int i = 0;
+ while (i < text.size()) {
+ if (!text.at(i).isSpace())
+ return i;
+ ++i;
+ }
+ return i;
+}
+
+int TabSettings::trailingWhitespaces(const QString &text) const
+{
+ int i = 0;
+ while (i < text.size()) {
+ if (!text.at(text.size()-1-i).isSpace())
+ return i;
+ ++i;
+ }
+ return i;
+}
+
+bool TabSettings::isIndentationClean(const QString &text) const
+{
+ int i = 0;
+ int spaceCount = 0;
+ while (i < text.size()) {
+ QChar c = text.at(i);
+ if (!c.isSpace())
+ return true;
+
+ if (c == QLatin1Char(' ')) {
+ ++spaceCount;
+ if (spaceCount == m_tabSize)
+ return false;
+ } else if (c == QLatin1Char('\t')) {
+ if (m_spacesForTabs || spaceCount != m_indentSize)
+ return false;
+ spaceCount = 0;
+ }
+ ++i;
+ }
+ return true;
+}
+
+
+int TabSettings::columnAt(const QString &text, int position) const
+{
+ int column = 0;
+ for (int i = 0; i < position; ++i) {
+ if (text.at(i) == QLatin1Char('\t'))
+ column = column - (column % m_tabSize) + m_tabSize;
+ else
+ ++column;
+ }
+ return column;
+}
+
+int TabSettings::spacesLeftFromPosition(const QString &text, int position) const
+{
+ int i = position;
+ while (i > 0) {
+ if (!text.at(i-1).isSpace())
+ break;
+ --i;
+ }
+ return position - i;
+}
+
+int TabSettings::indentedColumn(int column, bool doIndent) const
+{
+ int aligned = (column / m_indentSize) * m_indentSize;
+ if (doIndent)
+ return aligned + m_indentSize;
+ if (aligned < column)
+ return aligned;
+ return qMax(0, aligned - m_indentSize);
+}
+
+QString TabSettings::indentationString(int startColumn, int targetColumn) const
+{
+ targetColumn = qMax(startColumn, targetColumn);
+ if (m_spacesForTabs)
+ return QString(targetColumn - startColumn, QLatin1Char(' '));
+
+ QString s;
+ int alignedStart = startColumn - (startColumn % m_tabSize) + m_tabSize;
+ if (alignedStart > startColumn && alignedStart <= targetColumn) {
+ s += QLatin1Char('\t');
+ startColumn = alignedStart;
+ }
+ if (int columns = targetColumn - startColumn) {
+ int tabs = columns / m_tabSize;
+ s += QString(tabs, QLatin1Char('\t'));
+ s += QString(columns - tabs * m_tabSize, QLatin1Char(' '));
+ }
+ return s;
+}
+
+void TabSettings::indentLine(QTextBlock block, int newIndent) const
+{
+ const QString text = block.text();
+ const int oldBlockLength = text.size();
+
+ // Quickly check whether indenting is required.
+ if (oldBlockLength == 0 && newIndent == 0)
+ return;
+
+ const QString indentString = indentationString(0, newIndent);
+ newIndent = indentString.length();
+
+ if (oldBlockLength == indentString.length() && text == indentString)
+ return;
+
+ if (oldBlockLength > indentString.length() &&
+ text.startsWith(indentString) &&
+ !text.at(indentString.length()).isSpace()) {
+ return;
+ }
+
+ QTextCursor cursor(block);
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::StartOfBlock);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace(text));
+ cursor.removeSelectedText();
+ cursor.insertText(indentString);
+ cursor.endEditBlock();
+}
+
+bool TabSettings::equals(const TabSettings &ts) const
+{
+ return m_spacesForTabs == ts.m_spacesForTabs
+ && m_autoIndent == ts.m_autoIndent
+ && m_smartBackspace == ts.m_smartBackspace
+ && m_tabSize == ts.m_tabSize
+ && m_indentSize == ts.m_indentSize;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h
new file mode 100644
index 0000000000..8b326fadc4
--- /dev/null
+++ b/src/plugins/texteditor/tabsettings.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TABSETTINGS_H
+#define TABSETTINGS_H
+
+#include "texteditor_global.h"
+
+#include <QtGui/QTextBlock>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+// Tab settings: Data type the GeneralSettingsPage acts on
+// with some convenience functions for formatting.
+struct TEXTEDITOR_EXPORT TabSettings
+{
+ TabSettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, const QSettings *s);
+
+
+ int lineIndentPosition(const QString &text) const;
+ int firstNonSpace(const QString &text) const;
+ int columnAt(const QString &text, int position) const;
+ int spacesLeftFromPosition(const QString &text, int position) const;
+ int indentedColumn(int column, bool doIndent = true) const;
+ QString indentationString(int startColumn, int targetColumn) const;
+
+ void indentLine(QTextBlock block, int newIndent) const;
+
+ int trailingWhitespaces(const QString &text) const;
+ bool isIndentationClean(const QString &text) const;
+
+
+ bool m_spacesForTabs;
+ bool m_autoIndent;
+ bool m_smartBackspace;
+ int m_tabSize;
+ int m_indentSize;
+
+ bool equals(const TabSettings &ts) const;
+};
+
+inline bool operator==(const TabSettings &t1, const TabSettings &t2) { return t1.equals(t2); }
+inline bool operator!=(const TabSettings &t1, const TabSettings &t2) { return !t1.equals(t2); }
+
+} // namespace TextEditor
+
+#endif // TABSETTINGS_H
diff --git a/src/plugins/texteditor/textblockiterator.cpp b/src/plugins/texteditor/textblockiterator.cpp
new file mode 100644
index 0000000000..51c894d9fc
--- /dev/null
+++ b/src/plugins/texteditor/textblockiterator.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "textblockiterator.h"
+
+#include <QtGui/QTextDocument>
+
+using namespace TextEditor;
+
+TextBlockIterator::TextBlockIterator()
+ : m_document(0),
+ m_initialized(false)
+{ }
+
+TextBlockIterator::TextBlockIterator(const QTextBlock &block)
+ : m_document(block.document()),
+ m_block(block),
+ m_initialized(false)
+{ }
+
+bool TextBlockIterator::equals(const TextBlockIterator &other) const
+{
+ if (m_document != other.m_document)
+ return false;
+ return m_block == other.m_block;
+}
+
+QString TextBlockIterator::operator*() const
+{
+ if (! m_initialized)
+ read();
+ return m_text;
+}
+
+void TextBlockIterator::read() const
+{
+ m_initialized = true;
+ m_text = m_block.text();
+}
+
+TextBlockIterator &TextBlockIterator::operator++()
+{
+ m_initialized = false;
+ m_block = m_block.next();
+ return *this;
+}
+
+TextBlockIterator &TextBlockIterator::operator--()
+{
+ m_initialized = false;
+ m_block = m_block.previous();
+ return *this;
+}
+
+TextBlockIterator TextBlockIterator::operator++(int)
+{
+ TextBlockIterator prev;
+ ++*this;
+ return prev;
+}
+
+TextBlockIterator TextBlockIterator::operator--(int)
+{
+ TextBlockIterator prev;
+ --*this;
+ return prev;
+}
diff --git a/src/plugins/texteditor/textblockiterator.h b/src/plugins/texteditor/textblockiterator.h
new file mode 100644
index 0000000000..0f9c585a6f
--- /dev/null
+++ b/src/plugins/texteditor/textblockiterator.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef _TEXTBLOCKITERATOR_H
+#define _TEXTBLOCKITERATOR_H
+
+#include "texteditor_global.h"
+
+#include <QtGui/QTextBlock>
+
+namespace TextEditor {
+
+/* Iterator for the text blocks of a document. */
+class TEXTEDITOR_EXPORT TextBlockIterator {
+public:
+ TextBlockIterator();
+ TextBlockIterator(const QTextBlock &block);
+
+ bool equals(const TextBlockIterator &o) const;
+
+ QString operator*() const;
+ TextBlockIterator &operator++();
+ TextBlockIterator &operator--();
+ TextBlockIterator operator++(int);
+ TextBlockIterator operator--(int);
+
+private:
+ void read() const;
+
+private:
+ const QTextDocument *m_document;
+ QTextBlock m_block;
+ mutable QString m_text;
+ mutable bool m_initialized;
+};
+
+inline bool operator==(const TextBlockIterator &i1, const TextBlockIterator &i2) { return i1.equals(i2); }
+inline bool operator!=(const TextBlockIterator &i1, const TextBlockIterator &i2) { return !i1.equals(i2); }
+
+} // namespace TextEditor
+
+#endif // _TEXTBLOCKITERATOR_H
diff --git a/src/plugins/texteditor/texteditor.pri b/src/plugins/texteditor/texteditor.pri
new file mode 100644
index 0000000000..9d3789b825
--- /dev/null
+++ b/src/plugins/texteditor/texteditor.pri
@@ -0,0 +1,3 @@
+include(texteditor_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(TextEditor)
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
new file mode 100644
index 0000000000..59c9cc4bb4
--- /dev/null
+++ b/src/plugins/texteditor/texteditor.pro
@@ -0,0 +1,58 @@
+TEMPLATE = lib
+TARGET = TextEditor
+DEFINES += TEXTEDITOR_LIBRARY
+include(../../qworkbenchplugin.pri)
+include(texteditor_dependencies.pri)
+SOURCES += texteditorplugin.cpp \
+ textfilewizard.cpp \
+ plaintexteditor.cpp \
+ plaintexteditorfactory.cpp \
+ basetextdocument.cpp \
+ basetexteditor.cpp \
+ texteditoractionhandler.cpp \
+ completionsupport.cpp \
+ completionwidget.cpp \
+ fontsettingspage.cpp \
+ tabsettings.cpp \
+ storagesettings.cpp \
+ displaysettings.cpp \
+ fontsettings.cpp \
+ textblockiterator.cpp \
+ linenumberfilter.cpp \
+ generalsettingspage.cpp \
+ basetextmark.cpp \
+ findinfiles.cpp \
+ basefilefind.cpp \
+ texteditorsettings.cpp \
+ codecselector.cpp
+HEADERS += texteditorplugin.h \
+ textfilewizard.h \
+ plaintexteditor.h \
+ plaintexteditorfactory.h \
+ basetexteditor_p.h \
+ basetextdocument.h \
+ completionsupport.h \
+ completionwidget.h \
+ basetexteditor.h \
+ texteditoractionhandler.h \
+ fontsettingspage.h \
+ icompletioncollector.h \
+ texteditorconstants.h \
+ tabsettings.h \
+ storagesettings.h \
+ displaysettings.h \
+ fontsettings.h \
+ textblockiterator.h \
+ itexteditable.h \
+ itexteditor.h \
+ linenumberfilter.h \
+ texteditor_global.h \
+ generalsettingspage.h \
+ basetextmark.h \
+ findinfiles.h \
+ basefilefind.h \
+ texteditorsettings.h \
+ codecselector.h
+FORMS += fontsettingspage.ui \
+ generalsettingspage.ui
+RESOURCES += texteditor.qrc
diff --git a/src/plugins/texteditor/texteditor.qrc b/src/plugins/texteditor/texteditor.qrc
new file mode 100644
index 0000000000..191343ce0e
--- /dev/null
+++ b/src/plugins/texteditor/texteditor.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/texteditor" >
+ <file>images/finddocuments.png</file>
+ <file>images/finddirectory.png</file>
+ <file>TextEditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/texteditor/texteditor_dependencies.pri b/src/plugins/texteditor/texteditor_dependencies.pri
new file mode 100644
index 0000000000..87f23e9eed
--- /dev/null
+++ b/src/plugins/texteditor/texteditor_dependencies.pri
@@ -0,0 +1,4 @@
+include(../../libs/utils/utils.pri)
+include(../../plugins/find/find.pri)
+include(../../plugins/quickopen/quickopen.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/texteditor/texteditor_global.h b/src/plugins/texteditor/texteditor_global.h
new file mode 100644
index 0000000000..ef7f01c641
--- /dev/null
+++ b/src/plugins/texteditor/texteditor_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef TEXTEDITOR_GLOBAL_H
+#define TEXTEDITOR_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(TEXTEDITOR_LIBRARY)
+# define TEXTEDITOR_EXPORT Q_DECL_EXPORT
+#else
+# define TEXTEDITOR_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // TEXTEDITOR_GLOBAL_H
diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp
new file mode 100644
index 0000000000..91246dcc8c
--- /dev/null
+++ b/src/plugins/texteditor/texteditoractionhandler.cpp
@@ -0,0 +1,459 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditoractionhandler.h"
+#include "texteditorconstants.h"
+#include "basetexteditor.h"
+#include "texteditorplugin.h"
+#include "linenumberfilter.h"
+
+#include <quickopen/quickopenmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QSet>
+#include <QtCore/QtDebug>
+#include <QtGui/QAction>
+#include <QtGui/QTextCursor>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+TextEditorActionHandler::TextEditorActionHandler(Core::ICore *core,
+ const QString &context,
+ uint optionalActions) :
+ QObject(core),
+ m_optionalActions(optionalActions),
+ m_currentEditor(0),
+ m_core(core),
+ m_initialized(false)
+{
+ m_undoAction = m_redoAction = m_copyAction = m_cutAction = m_pasteAction
+ = m_selectAllAction = m_gotoAction = m_printAction = m_formatAction
+ = m_visualizeWhitespaceAction = m_textWrappingAction
+ = m_unCommentSelectionAction = m_unCollapseAllAction
+ = m_collapseAction = m_expandAction
+ = m_deleteLineAction = m_selectEncodingAction
+ = m_increaseFontSizeAction = m_decreaseFontSizeAction
+ = 0;
+
+ m_contextId << m_core->uniqueIDManager()->uniqueIdentifier(context);
+
+ connect(m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
+ this, SLOT(updateCurrentEditor(Core::IContext *)));
+}
+
+void TextEditorActionHandler::setupActions(BaseTextEditor *editor)
+{
+ initializeActions();
+ editor->setActionHack(this);
+ QObject::connect(editor, SIGNAL(undoAvailable(bool)), this, SLOT(updateUndoAction()));
+ QObject::connect(editor, SIGNAL(redoAvailable(bool)), this, SLOT(updateRedoAction()));
+ QObject::connect(editor, SIGNAL(copyAvailable(bool)), this, SLOT(updateCopyAction()));
+}
+
+
+void TextEditorActionHandler::initializeActions()
+{
+ if (!m_initialized) {
+ createActions();
+ m_initialized = true;
+ }
+}
+
+void TextEditorActionHandler::createActions()
+{
+ m_undoAction = registerNewAction(QLatin1String(Core::Constants::UNDO), this, SLOT(undoAction()),
+ tr("&Undo"));
+ m_redoAction = registerNewAction(QLatin1String(Core::Constants::REDO), this, SLOT(redoAction()),
+ tr("&Redo"));
+ m_copyAction = registerNewAction(QLatin1String(Core::Constants::COPY), this, SLOT(copyAction()));
+ m_cutAction = registerNewAction(QLatin1String(Core::Constants::CUT), this, SLOT(cutAction()));
+ m_pasteAction = registerNewAction(QLatin1String(Core::Constants::PASTE), this, SLOT(pasteAction()));
+ m_selectAllAction = registerNewAction(QLatin1String(Core::Constants::SELECTALL), this, SLOT(selectAllAction()));
+ m_gotoAction = registerNewAction(QLatin1String(Core::Constants::GOTO), this, SLOT(gotoAction()));
+ m_printAction = registerNewAction(QLatin1String(Core::Constants::PRINT), this, SLOT(printAction()));
+
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ Core::IActionContainer *medit = am->actionContainer(Core::Constants::M_EDIT);
+ Core::IActionContainer *advancedMenu = am->actionContainer(Core::Constants::M_EDIT_ADVANCED);
+
+ m_selectEncodingAction = new QAction(tr("Select Encoding..."), this);
+ Core::ICommand *command = am->registerAction(m_selectEncodingAction, Constants::SELECT_ENCODING, m_contextId);
+ connect(m_selectEncodingAction, SIGNAL(triggered()), this, SLOT(selectEncoding()));
+ medit->addAction(command, Core::Constants::G_EDIT_OTHER);
+
+
+ m_formatAction = new QAction(tr("Auto-&indent Selection"), this);
+ command = am->registerAction(m_formatAction, TextEditor::Constants::AUTO_INDENT_SELECTION, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+I")));
+ advancedMenu->addAction(command);
+ connect(m_formatAction, SIGNAL(triggered(bool)), this, SLOT(formatAction()));
+
+
+ m_visualizeWhitespaceAction = new QAction(tr("Visualize &Whitespace"), this);
+ m_visualizeWhitespaceAction->setCheckable(true);
+ command = am->registerAction(m_visualizeWhitespaceAction,
+ TextEditor::Constants::VISUALIZE_WHITESPACE, m_contextId);
+#ifndef Q_OS_MAC
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+E, Ctrl+V")));
+#endif
+
+ advancedMenu->addAction(command);
+ connect(m_visualizeWhitespaceAction, SIGNAL(triggered(bool)), this, SLOT(setVisualizeWhitespace(bool)));
+
+ m_textWrappingAction = new QAction(tr("Enable Text &Wrapping"), this);
+ m_textWrappingAction->setCheckable(true);
+ command = am->registerAction(m_textWrappingAction,
+ TextEditor::Constants::TEXT_WRAPPING, m_contextId);
+#ifndef Q_OS_MAC
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+E, Ctrl+W")));
+#endif
+ advancedMenu->addAction(command);
+ connect(m_textWrappingAction, SIGNAL(triggered(bool)), this, SLOT(setTextWrapping(bool)));
+
+
+ m_unCommentSelectionAction = new QAction(tr("(Un)Comment &Selection"), this);
+ command = am->registerAction(m_unCommentSelectionAction, Constants::UN_COMMENT_SELECTION, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+/")));
+ connect(m_unCommentSelectionAction, SIGNAL(triggered()), this, SLOT(unCommentSelection()));
+ advancedMenu->addAction(command);
+
+ m_deleteLineAction = new QAction(tr("Delete &Line"), this);
+ command = am->registerAction(m_deleteLineAction, Constants::DELETE_LINE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Shift+Del")));
+ connect(m_deleteLineAction, SIGNAL(triggered()), this, SLOT(deleteLine()));
+
+ m_collapseAction = new QAction(tr("Collapse"), this);
+ command = am->registerAction(m_collapseAction, Constants::COLLAPSE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+<")));
+ connect(m_collapseAction, SIGNAL(triggered()), this, SLOT(collapse()));
+ advancedMenu->addAction(command);
+
+ m_expandAction = new QAction(tr("Expand"), this);
+ command = am->registerAction(m_expandAction, Constants::EXPAND, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+>")));
+ connect(m_expandAction, SIGNAL(triggered()), this, SLOT(expand()));
+ advancedMenu->addAction(command);
+
+ m_unCollapseAllAction = new QAction(tr("(Un)&Collapse All"), this);
+ command = am->registerAction(m_unCollapseAllAction, Constants::UN_COLLAPSE_ALL, m_contextId);
+ connect(m_unCollapseAllAction, SIGNAL(triggered()), this, SLOT(unCollapseAll()));
+ advancedMenu->addAction(command);
+
+ m_increaseFontSizeAction = new QAction(tr("Increase Font Size"), this);
+ command = am->registerAction(m_increaseFontSizeAction, Constants::INCREASE_FONT_SIZE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl++")));
+ connect(m_increaseFontSizeAction, SIGNAL(triggered()), this, SLOT(increaseFontSize()));
+ advancedMenu->addAction(command);
+
+ m_decreaseFontSizeAction = new QAction(tr("Decrease Font Size"), this);
+ command = am->registerAction(m_decreaseFontSizeAction, Constants::DECREASE_FONT_SIZE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+-")));
+ connect(m_decreaseFontSizeAction, SIGNAL(triggered()), this, SLOT(decreaseFontSize()));
+ advancedMenu->addAction(command);
+}
+
+bool TextEditorActionHandler::supportsAction(const QString & /*id */) const
+{
+ return true;
+}
+
+QAction *TextEditorActionHandler::registerNewAction(const QString &id, const QString &title)
+{
+ if (!supportsAction(id))
+ return 0;
+
+ QAction *result = new QAction(title, this);
+ m_core->actionManager()->registerAction(result, id, m_contextId);
+ return result;
+}
+
+QAction *TextEditorActionHandler::registerNewAction(const QString &id,
+ QObject *receiver,
+ const char *slot,
+ const QString &title)
+{
+ QAction *rc = registerNewAction(id, title);
+ if (!rc)
+ return 0;
+
+ connect(rc, SIGNAL(triggered()), receiver, slot);
+ return rc;
+}
+
+TextEditorActionHandler::UpdateMode TextEditorActionHandler::updateMode() const
+{
+ if (!m_currentEditor)
+ return NoEditor;
+ return m_currentEditor->file()->isReadOnly() ? ReadOnlyMode : WriteMode;
+}
+
+void TextEditorActionHandler::updateActions()
+{
+ updateActions(updateMode());
+}
+
+void TextEditorActionHandler::updateActions(UpdateMode um)
+{
+ if (m_pasteAction)
+ m_pasteAction->setEnabled(um != NoEditor);
+ if (m_selectAllAction)
+ m_selectAllAction->setEnabled(um != NoEditor);
+ if (m_gotoAction)
+ m_gotoAction->setEnabled(um != NoEditor);
+ if (m_selectEncodingAction)
+ m_selectEncodingAction->setEnabled(um != NoEditor);
+ if (m_printAction)
+ m_printAction->setEnabled(um != NoEditor);
+ if (m_formatAction)
+ m_formatAction->setEnabled((m_optionalActions & Format) && um != NoEditor);
+ if (m_unCommentSelectionAction)
+ m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection) && um != NoEditor);
+ if (m_collapseAction)
+ m_collapseAction->setEnabled(um != NoEditor);
+ if (m_expandAction)
+ m_expandAction->setEnabled(um != NoEditor);
+ if (m_unCollapseAllAction)
+ m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll) && um != NoEditor);
+ if (m_decreaseFontSizeAction)
+ m_decreaseFontSizeAction->setEnabled(um != NoEditor);
+ if (m_increaseFontSizeAction)
+ m_increaseFontSizeAction->setEnabled(um != NoEditor);
+ if (m_visualizeWhitespaceAction) {
+ m_visualizeWhitespaceAction->setEnabled(um != NoEditor);
+ if (m_currentEditor)
+ m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace);
+ }
+ if (m_textWrappingAction) {
+ m_textWrappingAction->setEnabled(um != NoEditor);
+ if (m_currentEditor)
+ m_textWrappingAction->setChecked(m_currentEditor->displaySettings().m_textWrapping);
+ }
+
+ updateRedoAction();
+ updateUndoAction();
+ updateCopyAction();
+}
+
+void TextEditorActionHandler::updateRedoAction()
+{
+ if (m_redoAction)
+ m_redoAction->setEnabled(m_currentEditor && m_currentEditor->document()->isRedoAvailable());
+}
+
+void TextEditorActionHandler::updateUndoAction()
+{
+ if (m_undoAction)
+ m_undoAction->setEnabled(m_currentEditor && m_currentEditor->document()->isUndoAvailable());
+}
+
+void TextEditorActionHandler::updateCopyAction()
+{
+ const bool hasCopyableText = m_currentEditor && m_currentEditor->textCursor().hasSelection();
+ if (m_cutAction)
+ m_cutAction->setEnabled(hasCopyableText && updateMode() == WriteMode);
+ if (m_copyAction)
+ m_copyAction->setEnabled(hasCopyableText);
+}
+
+void TextEditorActionHandler::undoAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->undo();
+}
+
+void TextEditorActionHandler::redoAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->redo();
+}
+
+void TextEditorActionHandler::copyAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->copy();
+}
+
+void TextEditorActionHandler::cutAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->cut();
+}
+
+void TextEditorActionHandler::pasteAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->paste();
+}
+
+void TextEditorActionHandler::selectAllAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->selectAll();
+}
+
+void TextEditorActionHandler::gotoAction()
+{
+ QuickOpen::QuickOpenManager *quickopen = QuickOpen::QuickOpenManager::instance();
+ Q_ASSERT(quickopen);
+ QString shortcut = TextEditorPlugin::instance()->lineNumberFilter()->shortcutString();
+ quickopen->show(shortcut + " <line number>", 2, 13);
+}
+
+void TextEditorActionHandler::printAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->print(m_core->printer());
+}
+
+void TextEditorActionHandler::formatAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->format();
+}
+
+
+void TextEditorActionHandler::setVisualizeWhitespace(bool checked)
+{
+ if (m_currentEditor) {
+ DisplaySettings ds = m_currentEditor->displaySettings();
+ ds.m_visualizeWhitespace = checked;
+ m_currentEditor->setDisplaySettings(ds);
+ }
+}
+
+void TextEditorActionHandler::setTextWrapping(bool checked)
+{
+ if (m_currentEditor) {
+ DisplaySettings ds = m_currentEditor->displaySettings();
+ ds.m_textWrapping = checked;
+ m_currentEditor->setDisplaySettings(ds);
+ }
+}
+
+void TextEditorActionHandler::unCommentSelection()
+{
+ if (m_currentEditor)
+ m_currentEditor->unCommentSelection();
+}
+
+void TextEditorActionHandler::deleteLine()
+{
+ if (m_currentEditor)
+ m_currentEditor->deleteLine();
+}
+
+void TextEditorActionHandler::unCollapseAll()
+{
+ if (m_currentEditor)
+ m_currentEditor->unCollapseAll();
+}
+
+void TextEditorActionHandler::collapse()
+{
+ if (m_currentEditor)
+ m_currentEditor->collapse();
+}
+
+void TextEditorActionHandler::expand()
+{
+ if (m_currentEditor)
+ m_currentEditor->expand();
+}
+
+void TextEditorActionHandler::selectEncoding()
+{
+ if (m_currentEditor)
+ m_currentEditor->selectEncoding();
+}
+
+void TextEditorActionHandler::increaseFontSize()
+{
+ if (m_currentEditor)
+ m_currentEditor->zoomIn();
+}
+
+void TextEditorActionHandler::decreaseFontSize()
+{
+ if (m_currentEditor)
+ m_currentEditor->zoomOut();
+}
+
+
+void TextEditorActionHandler::updateCurrentEditor(Core::IContext *object)
+{
+ do {
+ if (!object) {
+ if (!m_currentEditor)
+ return;
+
+ m_currentEditor = 0;
+ break;
+ }
+ BaseTextEditor *editor = qobject_cast<BaseTextEditor *>(object->widget());
+ if (!editor) {
+ if (!m_currentEditor)
+ return;
+
+ m_currentEditor = 0;
+ break;
+ }
+
+ if (editor == m_currentEditor)
+ return;
+
+ if (editor->actionHack() != this) {
+ m_currentEditor = 0;
+ break;
+ }
+
+ m_currentEditor = editor;
+
+ } while (false);
+ updateActions();
+}
+
+
+const QPointer<BaseTextEditor> &TextEditorActionHandler::currentEditor() const
+{
+ return m_currentEditor;
+}
+
+Core::ICore *TextEditorActionHandler::core() const
+{
+ return m_core;
+}
+
diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h
new file mode 100644
index 0000000000..d0c222f848
--- /dev/null
+++ b/src/plugins/texteditor/texteditoractionhandler.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORACTIONHANDLER_H
+#define TEXTEDITORACTIONHANDLER_H
+
+#include "texteditor_global.h"
+#include "basetexteditor.h"
+
+#include "coreplugin/icontext.h"
+#include "coreplugin/icore.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtCore/QList>
+
+namespace TextEditor {
+
+class BaseTextEditor;
+
+// Redirects slots from global actions to the respective editor.
+
+class TEXTEDITOR_EXPORT TextEditorActionHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum OptionalActionsMask {
+ None = 0,
+ Format = 1,
+ UnCommentSelection = 2,
+ UnCollapseAll = 4
+ };
+
+ TextEditorActionHandler(Core::ICore *core,
+ const QString &context,
+ uint optionalActions = None);
+ void setupActions(BaseTextEditor *editor);
+
+ void initializeActions();
+
+public slots:
+ void updateActions();
+ void updateRedoAction();
+ void updateUndoAction();
+ void updateCopyAction();
+
+protected:
+ const QPointer<BaseTextEditor> &currentEditor() const;
+ QAction *registerNewAction(const QString &id, const QString &title = QString());
+ QAction *registerNewAction(const QString &id, QObject *receiver, const char *slot,
+ const QString &title = QString());
+ Core::ICore *core() const;
+
+ enum UpdateMode { NoEditor , ReadOnlyMode, WriteMode };
+ UpdateMode updateMode() const;
+
+ virtual void createActions();
+ virtual bool supportsAction(const QString &id) const;
+ virtual void updateActions(UpdateMode um);
+
+private slots:
+ void undoAction();
+ void redoAction();
+ void copyAction();
+ void cutAction();
+ void pasteAction();
+ void selectAllAction();
+ void gotoAction();
+ void printAction();
+ void formatAction();
+ void setVisualizeWhitespace(bool);
+ void setTextWrapping(bool);
+ void unCommentSelection();
+ void unCollapseAll();
+ void collapse();
+ void expand();
+ void deleteLine();
+ void selectEncoding();
+ void increaseFontSize();
+ void decreaseFontSize();
+ void updateCurrentEditor(Core::IContext *object);
+
+private:
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+ QAction *m_copyAction;
+ QAction *m_cutAction;
+ QAction *m_pasteAction;
+ QAction *m_selectAllAction;
+ QAction *m_gotoAction;
+ QAction *m_printAction;
+ QAction *m_formatAction;
+ QAction *m_visualizeWhitespaceAction;
+ QAction *m_textWrappingAction;
+ QAction *m_unCommentSelectionAction;
+ QAction *m_unCollapseAllAction;
+ QAction *m_collapseAction;
+ QAction *m_expandAction;
+ QAction *m_deleteLineAction;
+ QAction *m_selectEncodingAction;
+ QAction *m_increaseFontSizeAction;
+ QAction *m_decreaseFontSizeAction;
+
+ uint m_optionalActions;
+ QPointer<BaseTextEditor> m_currentEditor;
+ Core::ICore *m_core;
+ QList<int> m_contextId;
+ bool m_initialized;
+};
+
+} // namespace TextEditor
+
+#endif // TEXTEDITORACTIONHANDLER_H
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
new file mode 100644
index 0000000000..5133a2c148
--- /dev/null
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORCONSTANTS_H
+#define TEXTEDITORCONSTANTS_H
+
+namespace TextEditor {
+namespace Constants {
+
+const char * const C_TEXTEDITOR = "Text Editor";
+const char * const COMPLETE_THIS = "TextEditor.CompleteThis";
+const char * const VISUALIZE_WHITESPACE = "TextEditor.VisualizeWhitespace";
+const char * const TEXT_WRAPPING = "TextEditor.TextWrapping";
+const char * const UN_COMMENT_SELECTION = "TextEditor.UnCommentSelection";
+const char * const COLLAPSE = "TextEditor.Collapse";
+const char * const EXPAND = "TextEditor.Expand";
+const char * const UN_COLLAPSE_ALL = "TextEditor.UnCollapseAll";
+const char * const AUTO_INDENT_SELECTION = "TextEditor.AutoIndentSelection";
+const char * const INCREASE_FONT_SIZE = "TextEditor.IncreaseFontSize";
+const char * const DECREASE_FONT_SIZE = "TextEditor.DecreaseFontSize";
+const char * const DELETE_LINE = "TextEditor.DeleteLine";
+const char * const DELETE_WORD = "TextEditor.DeleteWord";
+const char * const SELECT_ENCODING = "TextEditor.SelectEncoding";
+const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain";
+const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";
+
+
+// Text color and style categories
+const char * const C_TEXT = "Text";
+
+const char * const C_SELECTION = "Selection";
+const char * const C_LINE_NUMBER = "LineNumber";
+const char * const C_SEARCH_RESULT = "SearchResult";
+const char * const C_SEARCH_SCOPE = "SearchScope";
+const char * const C_PARENTHESES = "Parentheses";
+const char * const C_CURRENT_LINE = "CurrentLine";
+
+const char * const C_NUMBER = "Number";
+const char * const C_STRING = "String";
+const char * const C_TYPE = "Type";
+const char * const C_KEYWORD = "Keyword";
+const char * const C_OPERATOR = "Operator";
+const char * const C_PREPROCESSOR = "Preprocessor";
+const char * const C_LABEL = "Label";
+const char * const C_COMMENT = "Comment";
+const char * const C_DISABLED_CODE = "DisabledCode";
+
+const char * const C_ADDED_LINE = "AddedLine";
+const char * const C_REMOVED_LINE = "RemovedLine";
+const char * const C_DIFF_FILE = "DiffFile";
+const char * const C_DIFF_LOCATION = "DiffLocation";
+
+const char * const C_VARIABLE = "Variable";
+const char * const C_FUNCTION = "Function";
+
+} // namespace Constants
+} // namespace TextEditor
+
+#endif // TEXTEDITORCONSTANTS_H
diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp
new file mode 100644
index 0000000000..5e943bd70c
--- /dev/null
+++ b/src/plugins/texteditor/texteditorplugin.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditorplugin.h"
+
+#include "findinfiles.h"
+#include "fontsettings.h"
+#include "linenumberfilter.h"
+#include "texteditorconstants.h"
+#include "texteditorsettings.h"
+#include "textfilewizard.h"
+#include "plaintexteditorfactory.h"
+#include "plaintexteditor.h"
+#include "storagesettings.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/icommand.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/texteditoractionhandler.h>
+
+#include <QtCore/qplugin.h>
+#include <QtGui/QShortcut>
+#include <QtGui/QMainWindow>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+TextEditorPlugin *TextEditorPlugin::m_instance = 0;
+
+TextEditorPlugin::TextEditorPlugin() :
+ m_core(0),
+ m_settings(0),
+ m_wizard(0),
+ m_editorFactory(0),
+ m_lineNumberFilter(0)
+{
+ Q_ASSERT(!m_instance);
+ m_instance = this;
+}
+
+TextEditorPlugin::~TextEditorPlugin()
+{
+ m_instance = 0;
+}
+
+TextEditorPlugin *TextEditorPlugin::instance()
+{
+ return m_instance;
+}
+
+Core::ICore *TextEditorPlugin::core()
+{
+ return m_instance->m_core;
+}
+
+//ExtensionSystem::PluginInterface
+bool TextEditorPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ if (!m_core->mimeDatabase()->addMimeTypes(QLatin1String(":/texteditor/TextEditor.mimetypes.xml"), errorMessage))
+ return false;
+
+ Core::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+ wizardParameters.setDescription(tr("This creates a new text file (.txt)"));
+ wizardParameters.setName(tr("Text File"));
+ wizardParameters.setCategory(QLatin1String("General"));
+ wizardParameters.setTrCategory(tr("General"));
+ m_wizard = new TextFileWizard(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT),
+ QLatin1String(Core::Constants::K_DEFAULT_TEXT_EDITOR),
+ QLatin1String("text$"),
+ wizardParameters, m_core);
+ // Add text file wizard
+ addAutoReleasedObject(m_wizard);
+
+
+ m_settings = new TextEditorSettings(this, this);
+
+ // Add plain text editor factory
+ m_editorFactory = new PlainTextEditorFactory;
+ addAutoReleasedObject(m_editorFactory);
+
+ // Goto line functionality for quick open
+ m_lineNumberFilter = new LineNumberFilter(m_core->editorManager());
+ addAutoReleasedObject(m_lineNumberFilter);
+
+ int contextId = m_core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+ QList<int> context = QList<int>() << contextId;
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ // Add shortcut for invoking automatic completion
+ QShortcut *completionShortcut = new QShortcut(m_core->mainWindow());
+ completionShortcut->setWhatsThis(tr("Triggers a completion in this scope"));
+ // Make sure the shortcut still works when the completion widget is active
+ completionShortcut->setContext(Qt::ApplicationShortcut);
+ Core::ICommand *command = am->registerShortcut(completionShortcut, Constants::COMPLETE_THIS, context);
+#ifndef Q_OS_MAC
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Space")));
+#else
+ command->setDefaultKeySequence(QKeySequence(tr("Meta+Space")));
+#endif
+ connect(completionShortcut, SIGNAL(activated()), this, SLOT(invokeCompletion()));
+
+ addAutoReleasedObject(new FindInFiles(m_core, m_core->pluginManager()->getObject<Find::SearchResultWindow>()));
+
+ return true;
+}
+
+void TextEditorPlugin::extensionsInitialized()
+{
+ m_editorFactory->actionHandler()->initializeActions();
+}
+
+void TextEditorPlugin::initializeEditor(TextEditor::PlainTextEditor *editor)
+{
+ // common actions
+ m_editorFactory->actionHandler()->setupActions(editor);
+
+ // settings
+ connect(m_settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
+ editor, SLOT(setFontSettings(TextEditor::FontSettings)));
+ connect(m_settings, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
+ editor, SLOT(setTabSettings(TextEditor::TabSettings)));
+ connect(m_settings, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)),
+ editor, SLOT(setStorageSettings(TextEditor::StorageSettings)));
+ connect(m_settings, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)),
+ editor, SLOT(setDisplaySettings(TextEditor::DisplaySettings)));
+
+ // tab settings rely on font settings
+ editor->setFontSettings(m_settings->fontSettings());
+ editor->setTabSettings(m_settings->tabSettings());
+ editor->setStorageSettings(m_settings->storageSettings());
+ editor->setDisplaySettings(m_settings->displaySettings());
+}
+
+void TextEditorPlugin::invokeCompletion()
+{
+ if (!m_core)
+ return;
+
+ Core::IEditor *iface = m_core->editorManager()->currentEditor();
+ ITextEditor *editor = qobject_cast<ITextEditor *>(iface);
+ if (editor)
+ editor->triggerCompletions();
+}
+
+
+Q_EXPORT_PLUGIN(TextEditorPlugin)
diff --git a/src/plugins/texteditor/texteditorplugin.h b/src/plugins/texteditor/texteditorplugin.h
new file mode 100644
index 0000000000..578095f609
--- /dev/null
+++ b/src/plugins/texteditor/texteditorplugin.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORPLUGIN_H
+#define TEXTEDITORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace TextEditor {
+
+class FontSettings;
+class FontSettingsPage;
+class TextEditorSettings;
+class TextFileWizard;
+class PlainTextEditor;
+
+namespace Internal {
+
+class LineNumberFilter;
+class PlainTextEditorFactory;
+
+class TextEditorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ TextEditorPlugin();
+ virtual ~TextEditorPlugin();
+
+ static TextEditorPlugin *instance();
+ static Core::ICore *core();
+
+ // ExtensionSystem::PluginInterface
+ bool initialize(const QStringList &arguments, QString *);
+ void extensionsInitialized();
+
+ void initializeEditor(PlainTextEditor *editor);
+
+ LineNumberFilter *lineNumberFilter() { return m_lineNumberFilter; }
+
+private slots:
+ void invokeCompletion();
+
+private:
+ static TextEditorPlugin *m_instance;
+ Core::ICore *m_core;
+ TextEditorSettings *m_settings;
+ TextFileWizard *m_wizard;
+ PlainTextEditorFactory *m_editorFactory;
+ LineNumberFilter *m_lineNumberFilter;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // TEXTEDITORPLUGIN_H
diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp
new file mode 100644
index 0000000000..0292215f99
--- /dev/null
+++ b/src/plugins/texteditor/texteditorsettings.cpp
@@ -0,0 +1,152 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditorsettings.h"
+
+#include "displaysettings.h"
+#include "generalsettingspage.h"
+#include "fontsettingspage.h"
+#include "storagesettings.h"
+#include "tabsettings.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+
+#include <QApplication>
+
+using namespace TextEditor;
+using namespace TextEditor::Constants;
+
+TextEditorSettings *TextEditorSettings::m_instance = 0;
+
+TextEditorSettings::TextEditorSettings(Internal::TextEditorPlugin *plugin,
+ QObject *parent)
+ : QObject(parent)
+{
+ Q_ASSERT(!m_instance);
+ m_instance = this;
+
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+
+ // Note: default background colors are coming from FormatDescription::background()
+
+ // Add font preference page
+ FormatDescriptions formatDescriptions;
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_TEXT), tr("Text")));
+
+ // Special categories
+ const QPalette p = QApplication::palette();
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_SELECTION), tr("Selection"), p.color(QPalette::HighlightedText)));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_LINE_NUMBER), tr("Line Number")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_SEARCH_RESULT), tr("Search Result")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_SEARCH_SCOPE), tr("Search Scope")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_PARENTHESES), tr("Parentheses")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_CURRENT_LINE), tr("Current Line")));
+
+ // Standard categories
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_NUMBER), tr("Number"), Qt::darkBlue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_STRING), tr("String"), Qt::darkGreen));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_TYPE), tr("Type"), Qt::darkMagenta));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_KEYWORD), tr("Keyword"), Qt::darkYellow));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_OPERATOR), tr("Operator")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_PREPROCESSOR), tr("Preprocessor"), Qt::darkBlue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_LABEL), tr("Label"), Qt::darkRed));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_COMMENT), tr("Comment"), Qt::darkGreen));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_DISABLED_CODE), tr("Disabled Code"), Qt::lightGray));
+
+ // Diff categories
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_ADDED_LINE), tr("Added Line"), Qt::blue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_REMOVED_LINE), tr("Removed Line"), Qt::red));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_DIFF_FILE), tr("Diff File"), Qt::black));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_DIFF_LOCATION), tr("Diff Location"), Qt::green));
+
+ // Pro file categories
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_VARIABLE), tr("Variable"), Qt::blue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_FUNCTION), tr("Function"), Qt::green));
+
+ m_fontSettingsPage = new FontSettingsPage(formatDescriptions,
+ QLatin1String("TextEditor"),
+ tr("Text Editor"),
+ plugin->core());
+ pm->addObject(m_fontSettingsPage);
+
+ // Add the GUI used to configure the tab, storage and display settings
+ TextEditor::GeneralSettingsPageParameters generalSettingsPageParameters;
+ generalSettingsPageParameters.name = tr("General");
+ generalSettingsPageParameters.category = QLatin1String("TextEditor");
+ generalSettingsPageParameters.trCategory = tr("Text Editor");
+ generalSettingsPageParameters.settingsPrefix = QLatin1String("text");
+ m_generalSettingsPage = new GeneralSettingsPage(plugin->core(), generalSettingsPageParameters, this);
+ pm->addObject(m_generalSettingsPage);
+
+ connect(m_fontSettingsPage, SIGNAL(changed(TextEditor::FontSettings)),
+ this, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)));
+ connect(m_generalSettingsPage, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
+ this, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)));
+ connect(m_generalSettingsPage, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)),
+ this, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)));
+ connect(m_generalSettingsPage, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)),
+ this, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)));
+}
+
+TextEditorSettings::~TextEditorSettings()
+{
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ pm->removeObject(m_generalSettingsPage);
+ pm->removeObject(m_fontSettingsPage);
+
+ m_instance = 0;
+}
+
+TextEditorSettings *TextEditorSettings::instance()
+{
+ return m_instance;
+}
+
+FontSettings TextEditorSettings::fontSettings() const
+{
+ return m_fontSettingsPage->fontSettings();
+}
+
+TabSettings TextEditorSettings::tabSettings() const
+{
+ return m_generalSettingsPage->tabSettings();
+}
+
+StorageSettings TextEditorSettings::storageSettings() const
+{
+ return m_generalSettingsPage->storageSettings();
+}
+
+DisplaySettings TextEditorSettings::displaySettings() const
+{
+ return m_generalSettingsPage->displaySettings();
+}
diff --git a/src/plugins/texteditor/texteditorsettings.h b/src/plugins/texteditor/texteditorsettings.h
new file mode 100644
index 0000000000..1b5a08e966
--- /dev/null
+++ b/src/plugins/texteditor/texteditorsettings.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORSETTINGS_H
+#define TEXTEDITORSETTINGS_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QObject>
+
+namespace TextEditor {
+
+class GeneralSettingsPage;
+class FontSettingsPage;
+class FontSettings;
+struct TabSettings;
+struct StorageSettings;
+struct DisplaySettings;
+
+namespace Internal {
+class TextEditorPlugin;
+}
+
+/**
+ * This class provides a central place for basic text editor settings. These
+ * settings include font settings, tab settings, storage settings and display
+ * settings.
+ */
+class TEXTEDITOR_EXPORT TextEditorSettings : public QObject
+{
+ Q_OBJECT
+
+public:
+ TextEditorSettings(Internal::TextEditorPlugin *plugin, QObject *parent);
+ ~TextEditorSettings();
+
+ static TextEditorSettings *instance();
+
+ FontSettings fontSettings() const;
+ TabSettings tabSettings() const;
+ StorageSettings storageSettings() const;
+ DisplaySettings displaySettings() const;
+
+signals:
+ void fontSettingsChanged(const TextEditor::FontSettings &);
+ void tabSettingsChanged(const TextEditor::TabSettings &);
+ void storageSettingsChanged(const TextEditor::StorageSettings &);
+ void displaySettingsChanged(const TextEditor::DisplaySettings &);
+
+private:
+ TextEditor::FontSettingsPage *m_fontSettingsPage;
+ TextEditor::GeneralSettingsPage *m_generalSettingsPage;
+
+ static TextEditorSettings *m_instance;
+};
+
+} // namespace TextEditor
+
+#endif // TEXTEDITORSETTINGS_H
diff --git a/src/plugins/texteditor/textfilewizard.cpp b/src/plugins/texteditor/textfilewizard.cpp
new file mode 100644
index 0000000000..b40201044c
--- /dev/null
+++ b/src/plugins/texteditor/textfilewizard.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "textfilewizard.h"
+#include "basetexteditor.h"
+#include "texteditorconstants.h"
+
+namespace TextEditor {
+
+TextFileWizard::TextFileWizard(const QString &mimeType,
+ const QString &editorKind,
+ const QString &suggestedFileName,
+ const BaseFileWizardParameters &parameters,
+ Core::ICore *core,
+ QObject *parent) :
+ Core::StandardFileWizard(parameters, core, parent),
+ m_mimeType(mimeType),
+ m_editorKind(editorKind),
+ m_suggestedFileName(suggestedFileName)
+{
+}
+
+Core::GeneratedFiles
+ TextFileWizard::generateFilesFromPath(const QString &path, const QString &name,
+ QString * /*errorMessage*/) const
+{
+ const QString suffix = preferredSuffix(m_mimeType);
+ const QString fileName = Core::BaseFileWizard::buildFileName(path, name, suffix);
+ Core::GeneratedFile file(fileName);
+ file.setEditorKind(m_editorKind);
+ return Core::GeneratedFiles() << file;
+}
+
+}
diff --git a/src/plugins/texteditor/textfilewizard.h b/src/plugins/texteditor/textfilewizard.h
new file mode 100644
index 0000000000..a3cb379733
--- /dev/null
+++ b/src/plugins/texteditor/textfilewizard.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTFILEWIZARD_H
+#define TEXTFILEWIZARD_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/basefilewizard.h>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT TextFileWizard : public Core::StandardFileWizard
+{
+ Q_OBJECT
+
+public:
+ typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
+ TextFileWizard(const QString &mimeType,
+ const QString &editorKind,
+ const QString &suggestedFileName,
+ const BaseFileWizardParameters &parameters,
+ Core::ICore *core,
+ QObject *parent = 0);
+
+protected:
+ virtual Core::GeneratedFiles
+ generateFilesFromPath(const QString &path, const QString &name,
+ QString *errorMessage) const;
+private:
+ const QString m_mimeType;
+ const QString m_editorKind;
+ const QString m_suggestedFileName;
+};
+
+} // namespace TextEditor
+
+#endif // TEXTFILEWIZARD_H
diff --git a/src/plugins/vcsbase/README.txt b/src/plugins/vcsbase/README.txt
new file mode 100644
index 0000000000..7b60a23110
--- /dev/null
+++ b/src/plugins/vcsbase/README.txt
@@ -0,0 +1,6 @@
+TODO:
+
+When diffing:
+- Use code from current editor or
+- else from project or
+- System codec
diff --git a/src/plugins/vcsbase/VCSBase.mimetypes.xml b/src/plugins/vcsbase/VCSBase.mimetypes.xml
new file mode 100644
index 0000000000..1c97052174
--- /dev/null
+++ b/src/plugins/vcsbase/VCSBase.mimetypes.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="text/x-patch">
+ <sub-class-of type="text/plain"/>
+ <comment>Differences between files</comment>
+ <glob pattern="*.diff"/> <comment xml:lang="bg">Разлики между файлове</comment>
+ <comment xml:lang="ca">diferències entre fitxers</comment>
+ <comment xml:lang="cs">Rozdíly mezi soubory</comment>
+ <comment xml:lang="da">forskel mellem filer</comment>
+ <comment xml:lang="de">Unterschied zwischen Dateien</comment>
+ <comment xml:lang="el">διαφοÏές Î¼ÎµÏ„Î±Î¾Ï Î±Ïχείων</comment>
+ <comment xml:lang="eo">diferencoj inter dosieroj</comment>
+ <comment xml:lang="es">diferencias entre ficheros</comment>
+ <comment xml:lang="eu">fitxategien arteko ezberdintasunak</comment>
+ <comment xml:lang="fi">tiedostojen väliset erot</comment>
+ <comment xml:lang="fr">différences entre fichiers</comment>
+ <comment xml:lang="hu">diff-különbségfájl</comment>
+ <comment xml:lang="it">Differenze tra file</comment>
+ <comment xml:lang="ja">ファイル間差分</comment>
+ <comment xml:lang="ko">파ì¼ì‚¬ì´ì˜ ë°”ë€ì </comment>
+ <comment xml:lang="lt">skirtumai tarp rinkmenų</comment>
+ <comment xml:lang="ms">Perbezaan antara fail</comment>
+ <comment xml:lang="nb">forskjeller mellom filer</comment>
+ <comment xml:lang="nl">verschillen tussen bestanden</comment>
+ <comment xml:lang="nn">skilnader mellom filer</comment>
+ <comment xml:lang="pl">różnica pomiędzy plikami</comment>
+ <comment xml:lang="pt">diferenças entre ficheiros</comment>
+ <comment xml:lang="pt_BR">Diferenças entre arquivos</comment>
+ <comment xml:lang="ru">Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ файлами</comment>
+ <comment xml:lang="sq">diferenca midis files</comment>
+ <comment xml:lang="sr">разлике међу датотекама</comment>
+ <comment xml:lang="sv">skillnader mellan filer</comment>
+ <comment xml:lang="uk">Ñ€Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð¼Ñ–Ð¶ файлами</comment>
+ <comment xml:lang="vi">khác biệt giữa nhiá»u tập tin</comment>
+ <comment xml:lang="zh_CN">文件的区别</comment>
+ <comment xml:lang="zh_TW">檔案內容差異</comment>
+ <glob pattern="*.patch"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/vcsbase/VCSBase.pluginspec b/src/plugins/vcsbase/VCSBase.pluginspec
new file mode 100644
index 0000000000..da0b618d26
--- /dev/null
+++ b/src/plugins/vcsbase/VCSBase.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="VCSBase" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Version Control System Base Plugin</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/vcsbase/baseannotationhighlighter.cpp b/src/plugins/vcsbase/baseannotationhighlighter.cpp
new file mode 100644
index 0000000000..e287718d71
--- /dev/null
+++ b/src/plugins/vcsbase/baseannotationhighlighter.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "baseannotationhighlighter.h"
+
+#include <math.h>
+#include <QtCore/QSet>
+#include <QtCore/QDebug>
+#include <QtGui/QColor>
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextEdit>
+#include <QtGui/QTextCharFormat>
+
+typedef QMap<QString, QTextCharFormat> ChangeNumberFormatMap;
+
+namespace VCSBase {
+
+struct BaseAnnotationHighlighterPrivate {
+ ChangeNumberFormatMap m_changeNumberMap;
+};
+
+BaseAnnotationHighlighter::BaseAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ QSyntaxHighlighter(document),
+ m_d(new BaseAnnotationHighlighterPrivate)
+{
+ setChangeNumbers(changeNumbers);
+}
+
+BaseAnnotationHighlighter::~BaseAnnotationHighlighter()
+{
+ delete m_d;
+}
+
+void BaseAnnotationHighlighter::setChangeNumbers(const ChangeNumbers &changeNumbers)
+{
+ m_d->m_changeNumberMap.clear();
+ if (!changeNumbers.isEmpty()) {
+ // Assign a color gradient to annotation change numbers. Give
+ // each change number a unique color.
+ const double oneThird = 1.0 / 3.0;
+ const int step = qRound(ceil(pow(changeNumbers.count(), oneThird)));
+ QList<QColor> colors;
+ const int factor = 255 / step;
+ for (int i=0; i<step; ++i)
+ for (int j=0; j<step; ++j)
+ for (int k=0; k<step; ++k)
+ colors.append(QColor(i*factor, j*factor, k*factor));
+
+ int m = 0;
+ const int cstep = colors.count() / changeNumbers.count();
+ const ChangeNumbers::const_iterator cend = changeNumbers.constEnd();
+ for (ChangeNumbers::const_iterator it = changeNumbers.constBegin(); it != cend; ++it) {
+ QTextCharFormat format;
+ format.setForeground(colors.at(m));
+ m_d->m_changeNumberMap.insert(*it, format);
+ m += cstep;
+ }
+ }
+}
+
+void BaseAnnotationHighlighter::highlightBlock(const QString &text)
+{
+ if (text.isEmpty() || m_d->m_changeNumberMap.empty())
+ return;
+ const QString change = changeNumber(text);
+ const ChangeNumberFormatMap::const_iterator it = m_d->m_changeNumberMap.constFind(change);
+ if (it != m_d->m_changeNumberMap.constEnd())
+ setFormat(0, text.length(), it.value());
+}
+
+}
+
diff --git a/src/plugins/vcsbase/baseannotationhighlighter.h b/src/plugins/vcsbase/baseannotationhighlighter.h
new file mode 100644
index 0000000000..ee5808b7b0
--- /dev/null
+++ b/src/plugins/vcsbase/baseannotationhighlighter.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEANNOTATIONHIGHLIGHTER_H
+#define BASEANNOTATIONHIGHLIGHTER_H
+
+#include "vcsbase_global.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCharFormat>
+
+namespace VCSBase {
+
+struct BaseAnnotationHighlighterPrivate;
+
+// Base for a highlighter for annotation lines of the form
+// 'changenumber:XXXX'. The change numbers are assigned a color gradient.
+// Example:
+// 112: text1 <color 1>
+// 113: text2 <color 2>
+// 112: text3 <color 1>
+class VCSBASE_EXPORT BaseAnnotationHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ typedef QSet<QString> ChangeNumbers;
+
+ explicit BaseAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = 0);
+ virtual ~BaseAnnotationHighlighter();
+
+ void setChangeNumbers(const ChangeNumbers &changeNumbers);
+
+ virtual void highlightBlock(const QString &text);
+
+private:
+ // Implement this to return the change number of a line
+ virtual QString changeNumber(const QString &block) const = 0;
+
+ BaseAnnotationHighlighterPrivate *m_d;
+};
+
+} //namespace Internal
+
+#endif
diff --git a/src/plugins/vcsbase/basevcseditorfactory.cpp b/src/plugins/vcsbase/basevcseditorfactory.cpp
new file mode 100644
index 0000000000..459a6683e6
--- /dev/null
+++ b/src/plugins/vcsbase/basevcseditorfactory.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basevcseditorfactory.h"
+#include "vcsbaseplugin.h"
+#include "vcsbaseeditor.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditoractionhandler.h>
+#include <texteditor/texteditorsettings.h>
+
+namespace VCSBase {
+
+struct BaseVCSEditorFactoryPrivate {
+ BaseVCSEditorFactoryPrivate(const VCSBaseEditorParameters *t, Core::ICore *core);
+
+ const VCSBaseEditorParameters *m_type;
+ const QString m_kind;
+ const QStringList m_mimeTypes;
+ Core::ICore *m_core;
+ TextEditor::TextEditorActionHandler *m_editorHandler;
+};
+
+BaseVCSEditorFactoryPrivate::BaseVCSEditorFactoryPrivate(const VCSBaseEditorParameters *t, Core::ICore *core) :
+ m_type(t),
+ m_kind(QLatin1String(t->kind)),
+ m_mimeTypes(QStringList(QLatin1String(t->mimeType))),
+ m_core(core),
+ m_editorHandler(new TextEditor::TextEditorActionHandler(core, t->kind))
+{
+}
+
+BaseVCSEditorFactory::BaseVCSEditorFactory(const VCSBaseEditorParameters *t,
+ Core::ICore *core) :
+ m_d(new BaseVCSEditorFactoryPrivate(t, core))
+{
+}
+
+BaseVCSEditorFactory::~BaseVCSEditorFactory()
+{
+ delete m_d;
+}
+
+QStringList BaseVCSEditorFactory::mimeTypes() const
+{
+ return m_d->m_mimeTypes;
+}
+
+QString BaseVCSEditorFactory::kind() const
+{
+ return m_d->m_kind;
+}
+
+Core::IFile *BaseVCSEditorFactory::open(const QString &fileName)
+{
+ Core::IEditor *iface = m_d->m_core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *BaseVCSEditorFactory::createEditor(QWidget *parent)
+{
+ VCSBaseEditor *vcsEditor = createVCSBaseEditor(m_d->m_type, parent);
+
+ vcsEditor ->setMimeType(m_d->m_mimeTypes.front());
+ m_d->m_editorHandler->setupActions(vcsEditor);
+
+ // Wire font settings and set initial values
+ TextEditor::TextEditorSettings *settings = TextEditor::TextEditorSettings::instance();
+ connect(settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
+ vcsEditor, SLOT(setFontSettings(TextEditor::FontSettings)));
+ vcsEditor->setFontSettings(settings->fontSettings());
+ return vcsEditor->editableInterface();
+}
+
+} // namespace VCSBase
diff --git a/src/plugins/vcsbase/basevcseditorfactory.h b/src/plugins/vcsbase/basevcseditorfactory.h
new file mode 100644
index 0000000000..1fb9408c8c
--- /dev/null
+++ b/src/plugins/vcsbase/basevcseditorfactory.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEVCSEDITORFACTORY_H
+#define BASEVCSEDITORFACTORY_H
+
+#include "vcsbase_global.h"
+#include "vcsbaseeditor.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+#include <QtCore/QStringList>
+
+namespace TextEditor {
+ class TextEditorActionHandler;
+}
+
+namespace Core {
+ class ICore;
+}
+
+namespace VCSBase {
+struct BaseVCSEditorFactoryPrivate;
+
+// Base class for editor factories creating instances of VCSBaseEditor
+// subclasses.
+class VCSBASE_EXPORT BaseVCSEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+public:
+ explicit BaseVCSEditorFactory(const VCSBaseEditorParameters *type,
+ Core::ICore *core);
+ virtual ~BaseVCSEditorFactory();
+
+ virtual QStringList mimeTypes() const;
+ // IEditorFactory
+
+ virtual QString kind() const;
+ virtual Core::IFile *open(const QString &fileName);
+ virtual Core::IEditor *createEditor(QWidget *parent);
+
+private:
+ // Implement to create and initialize (call init()) a
+ // VCSBaseEditor subclass
+ virtual VCSBaseEditor *createVCSBaseEditor(const VCSBaseEditorParameters *type,
+ QWidget *parent) = 0;
+
+ BaseVCSEditorFactoryPrivate *m_d;
+};
+
+// Utility template to create an editor.
+template <class Editor>
+class VCSEditorFactory : public BaseVCSEditorFactory
+{
+public:
+ explicit VCSEditorFactory(const VCSBaseEditorParameters *type,
+ Core::ICore *core,
+ QObject *describeReceiver = 0,
+ const char *describeSlot = 0);
+
+private:
+ virtual VCSBaseEditor *createVCSBaseEditor(const VCSBaseEditorParameters *type,
+ QWidget *parent);
+ QObject *m_describeReceiver;
+ const char *m_describeSlot;
+};
+
+template <class Editor>
+VCSEditorFactory<Editor>::VCSEditorFactory(const VCSBaseEditorParameters *type,
+ Core::ICore *core,
+ QObject *describeReceiver,
+ const char *describeSlot) :
+ BaseVCSEditorFactory(type, core),
+ m_describeReceiver(describeReceiver),
+ m_describeSlot(describeSlot)
+{
+}
+
+template <class Editor>
+VCSBaseEditor *VCSEditorFactory<Editor>::createVCSBaseEditor(const VCSBaseEditorParameters *type,
+ QWidget *parent)
+{
+ VCSBaseEditor *rc = new Editor(type, parent);
+ rc->init();
+ if (m_describeReceiver)
+ connect(rc, SIGNAL(describeRequested(QString,QString)), m_describeReceiver, m_describeSlot);
+ return rc;
+
+}
+}
+#endif
+
diff --git a/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp b/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp
new file mode 100644
index 0000000000..4aff7347fa
--- /dev/null
+++ b/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basevcssubmiteditorfactory.h"
+#include "vcsbasesubmiteditor.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+namespace VCSBase {
+
+struct BaseVCSSubmitEditorFactoryPrivate {
+ BaseVCSSubmitEditorFactoryPrivate(const VCSBaseSubmitEditorParameters *parameters);
+
+ const VCSBaseSubmitEditorParameters *m_parameters;
+ const QString m_kind;
+ const QStringList m_mimeTypes;
+};
+
+BaseVCSSubmitEditorFactoryPrivate::BaseVCSSubmitEditorFactoryPrivate(const VCSBaseSubmitEditorParameters *parameters) :
+ m_parameters(parameters),
+ m_kind(QLatin1String(parameters->kind)),
+ m_mimeTypes(QLatin1String(parameters->mimeType))
+{
+}
+
+BaseVCSSubmitEditorFactory::BaseVCSSubmitEditorFactory(const VCSBaseSubmitEditorParameters *parameters) :
+ m_d(new BaseVCSSubmitEditorFactoryPrivate(parameters))
+{
+}
+
+BaseVCSSubmitEditorFactory::~BaseVCSSubmitEditorFactory()
+{
+ delete m_d;
+}
+
+Core::IEditor *BaseVCSSubmitEditorFactory::createEditor(QWidget *parent)
+{
+ return createBaseSubmitEditor(m_d->m_parameters, parent);
+}
+
+QString BaseVCSSubmitEditorFactory::kind() const
+{
+ return m_d->m_kind;
+}
+
+QStringList BaseVCSSubmitEditorFactory::mimeTypes() const
+{
+ return m_d->m_mimeTypes;
+}
+
+Core::IFile *BaseVCSSubmitEditorFactory::open(const QString &fileName)
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (Core::IEditor *iface = core->editorManager()->openEditor(fileName, kind()))
+ return iface->file();
+ return 0;
+}
+
+}
diff --git a/src/plugins/vcsbase/basevcssubmiteditorfactory.h b/src/plugins/vcsbase/basevcssubmiteditorfactory.h
new file mode 100644
index 0000000000..d258e30571
--- /dev/null
+++ b/src/plugins/vcsbase/basevcssubmiteditorfactory.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSBaseBASEEDITORFACTORY_H
+#define VCSBaseBASEEDITORFACTORY_H
+
+#include "vcsbase_global.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+namespace VCSBase {
+
+class VCSBaseSubmitEditor;
+struct VCSBaseSubmitEditorParameters;
+struct BaseVCSSubmitEditorFactoryPrivate;
+
+// Parametrizable base class for editor factories creating instances of
+// VCSBaseSubmitEditor subclasses.
+class VCSBASE_EXPORT BaseVCSSubmitEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+protected:
+ explicit BaseVCSSubmitEditorFactory(const VCSBaseSubmitEditorParameters *parameters);
+
+public:
+ virtual ~BaseVCSSubmitEditorFactory();
+
+ virtual Core::IEditor *createEditor(QWidget *parent);
+ virtual QString kind() const;
+ virtual QStringList mimeTypes() const;
+ Core::IFile *open(const QString &fileName);
+
+private:
+ virtual VCSBaseSubmitEditor
+ *createBaseSubmitEditor(const VCSBaseSubmitEditorParameters *parameters,
+ QWidget *parent) = 0;
+
+ BaseVCSSubmitEditorFactoryPrivate *m_d;
+};
+
+// Utility template to create an editor that has a constructor taking the
+// parameter struct and a parent widget.
+
+template <class Editor>
+class VCSSubmitEditorFactory : public BaseVCSSubmitEditorFactory
+{
+public:
+ explicit VCSSubmitEditorFactory(const VCSBaseSubmitEditorParameters *parameters);
+
+private:
+ virtual VCSBaseSubmitEditor
+ *createBaseSubmitEditor(const VCSBaseSubmitEditorParameters *parameters,
+ QWidget *parent);
+};
+
+template <class Editor>
+VCSSubmitEditorFactory<Editor>::VCSSubmitEditorFactory(const VCSBaseSubmitEditorParameters *parameters) :
+ BaseVCSSubmitEditorFactory(parameters)
+{
+}
+
+template <class Editor>
+VCSBaseSubmitEditor *VCSSubmitEditorFactory<Editor>::createBaseSubmitEditor(const VCSBaseSubmitEditorParameters *parameters,
+ QWidget *parent)
+{
+ return new Editor(parameters, parent);
+}
+}
+
+#endif // VCSBaseBASEEDITOR_H
diff --git a/src/plugins/vcsbase/diffhighlighter.cpp b/src/plugins/vcsbase/diffhighlighter.cpp
new file mode 100644
index 0000000000..7da9f6df91
--- /dev/null
+++ b/src/plugins/vcsbase/diffhighlighter.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "diffhighlighter.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QRegExp>
+
+namespace VCSBase {
+
+// Formats used by DiffHighlighter
+enum DiffFormats {
+ DiffTextFormat,
+ DiffInFormat,
+ DiffOutFormat,
+ DiffFileFormat,
+ DiffLocationFormat,
+ NumDiffFormats
+};
+
+// --- DiffHighlighterPrivate
+struct DiffHighlighterPrivate {
+ DiffHighlighterPrivate(const QRegExp &filePattern);
+ inline DiffFormats analyzeLine(const QString &block) const;
+
+ const QRegExp m_filePattern;
+ const QString m_locationIndicator;
+ const QChar m_diffInIndicator;
+ const QChar m_diffOutIndicator;
+ QTextCharFormat m_formats[NumDiffFormats];
+};
+
+DiffHighlighterPrivate::DiffHighlighterPrivate(const QRegExp &filePattern) :
+ m_filePattern(filePattern),
+ m_locationIndicator(QLatin1String("@@")),
+ m_diffInIndicator(QLatin1Char('+')),
+ m_diffOutIndicator(QLatin1Char('-'))
+{
+ Q_ASSERT(filePattern.isValid());
+}
+
+DiffFormats DiffHighlighterPrivate::analyzeLine(const QString &text) const
+{
+ // Do not match on git "--- a/" as a deleted line, check
+ // file first
+ if (m_filePattern.exactMatch(text))
+ return DiffFileFormat;
+ if (text.startsWith(m_diffInIndicator))
+ return DiffInFormat;
+ if (text.startsWith(m_diffOutIndicator))
+ return DiffOutFormat;
+ if (text.startsWith(m_locationIndicator))
+ return DiffLocationFormat;
+ return DiffTextFormat;
+}
+
+// --- DiffHighlighter
+DiffHighlighter::DiffHighlighter(const QRegExp &filePattern,
+ QTextDocument *document) :
+ QSyntaxHighlighter(document),
+ m_d(new DiffHighlighterPrivate(filePattern))
+{
+}
+
+DiffHighlighter::~DiffHighlighter()
+{
+ delete m_d;
+}
+
+void DiffHighlighter::highlightBlock(const QString &text)
+{
+ if (text.isEmpty())
+ return;
+
+ const DiffFormats format = m_d->analyzeLine(text);
+ if (format != DiffTextFormat)
+ setFormat(0, text.length(), m_d->m_formats[format]);
+}
+
+void DiffHighlighter::setFormats(const QVector<QTextCharFormat> &s)
+{
+ if (s.size() == NumDiffFormats) {
+ qCopy(s.constBegin(), s.constEnd(), m_d->m_formats);
+ } else {
+ qWarning("%s: insufficient setting size: %d", Q_FUNC_INFO, s.size());
+ }
+}
+
+} // namespace VCSBase
diff --git a/src/plugins/vcsbase/diffhighlighter.h b/src/plugins/vcsbase/diffhighlighter.h
new file mode 100644
index 0000000000..eae25797bb
--- /dev/null
+++ b/src/plugins/vcsbase/diffhighlighter.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DIFFHIGHLIGHTER_H
+#define DIFFHIGHLIGHTER_H
+
+#include "vcsbase_global.h"
+
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCharFormat>
+#include <QtCore/QVector>
+
+QT_BEGIN_NAMESPACE
+class QRegExp;
+QT_END_NAMESPACE
+
+namespace Core {
+ class ICore;
+}
+namespace TextEditor {
+ class FontSettingsPage;
+}
+
+namespace VCSBase {
+
+struct DiffHighlighterPrivate;
+
+/* A highlighter for diffs. Parametrizable by the file indicator,
+ * which is for example '^====' in case of p4:
+ * \code
+ ==== //depot/research/main/qdynamicmainwindow3/qdynamicdockwidgetlayout_p.h#34 (text) ====
+ * \endcode
+ * Or '--- a/|'+++ b/' in case of git:
+ * \code
+ diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
+ index 9401ee7..ef35c3b 100644
+ --- a/src/plugins/plugins.pro
+ +++ b/src/plugins/plugins.pro
+ @@ -10,6 +10,7 @@ SUBDIRS = plugin_coreplugin \
+ * \endcode
+ * */
+
+class VCSBASE_EXPORT DiffHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ explicit DiffHighlighter(const QRegExp &filePattern,
+ QTextDocument *document = 0);
+ virtual ~DiffHighlighter();
+
+ virtual void highlightBlock(const QString &text);
+
+ // Set formats from a sequence of type QTextCharFormat
+ void setFormats(const QVector<QTextCharFormat> &s);
+
+private:
+ DiffHighlighterPrivate *m_d;
+};
+
+} //namespace VCSBase
+
+#endif // DIFFHIGHLIGHTER_H
diff --git a/src/plugins/vcsbase/submiteditorfile.cpp b/src/plugins/vcsbase/submiteditorfile.cpp
new file mode 100644
index 0000000000..adb8273207
--- /dev/null
+++ b/src/plugins/vcsbase/submiteditorfile.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "submiteditorfile.h"
+
+namespace VCSBase {
+namespace Internal {
+
+SubmitEditorFile::SubmitEditorFile(const QString &mimeType,
+ QObject *parent) :
+ Core::IFile(parent),
+ m_mimeType(mimeType),
+ m_modified(false)
+{
+}
+
+void SubmitEditorFile::setFileName(const QString name)
+{
+ m_fileName = name;
+}
+
+void SubmitEditorFile::setModified(bool modified)
+{
+ if (m_modified == modified)
+ return;
+ m_modified = modified;
+ emit changed();
+}
+
+bool SubmitEditorFile::save(const QString &fileName)
+{
+ emit saveMe(fileName);
+ return true;
+}
+
+QString SubmitEditorFile::mimeType() const
+{
+ return m_mimeType;
+}
+
+}
+}
diff --git a/src/plugins/vcsbase/submiteditorfile.h b/src/plugins/vcsbase/submiteditorfile.h
new file mode 100644
index 0000000000..f1f2183fce
--- /dev/null
+++ b/src/plugins/vcsbase/submiteditorfile.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SUBMITEDITORFILE_H
+#define SUBMITEDITORFILE_H
+
+#include <coreplugin/ifile.h>
+
+namespace VCSBase {
+namespace Internal {
+
+// A non-saveable IFile for submit editor files.
+class SubmitEditorFile : public Core::IFile
+{
+ Q_OBJECT
+public:
+ explicit SubmitEditorFile(const QString &mimeType,
+ QObject *parent = 0);
+
+ QString fileName() const { return m_fileName; }
+ QString defaultPath() const { return QString(); }
+ QString suggestedFileName() const { return QString(); }
+
+ bool isModified() const { return m_modified; }
+ virtual QString mimeType() const;
+ bool isReadOnly() const { return false; }
+ bool isSaveAsAllowed() const { return false; }
+ bool save(const QString &fileName);
+ void modified(ReloadBehavior * /*behavior*/) { return; }
+
+ void setFileName(const QString name);
+ void setModified(bool modified = true);
+
+signals:
+ void changed();
+ void saveMe(const QString &fileName);
+
+private:
+ const QString m_mimeType;
+ bool m_modified;
+ QString m_fileName;
+};
+
+
+} // namespace Internal
+}
+
+#endif // SUBMITEDITORFILE_H
diff --git a/src/plugins/vcsbase/vcsbase.pri b/src/plugins/vcsbase/vcsbase.pri
new file mode 100644
index 0000000000..56f7418c66
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbase.pri
@@ -0,0 +1,3 @@
+include(vcsbase_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(VCSBase)
diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro
new file mode 100644
index 0000000000..329e27b068
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbase.pro
@@ -0,0 +1,31 @@
+TEMPLATE = lib
+TARGET = VCSBase
+
+DEFINES += VCSBASE_LIBRARY
+
+include(../../qworkbenchplugin.pri)
+include(vcsbase_dependencies.pri)
+
+HEADERS += vcsbase_global.h \
+vcsbaseconstants.h \
+vcsbaseplugin.h \
+baseannotationhighlighter.h \
+diffhighlighter.h \
+vcsbasetextdocument.h \
+vcsbaseeditor.h \
+vcsbasesubmiteditor.h \
+basevcseditorfactory.h \
+submiteditorfile.h \
+basevcssubmiteditorfactory.h
+
+SOURCES += vcsbaseplugin.cpp \
+baseannotationhighlighter.cpp \
+diffhighlighter.cpp \
+vcsbasetextdocument.cpp \
+vcsbaseeditor.cpp \
+vcsbasesubmiteditor.cpp \
+basevcseditorfactory.cpp \
+submiteditorfile.cpp \
+basevcssubmiteditorfactory.cpp
+
+RESOURCES=vcsbase.qrc
diff --git a/src/plugins/vcsbase/vcsbase.qrc b/src/plugins/vcsbase/vcsbase.qrc
new file mode 100644
index 0000000000..648425980a
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbase.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/trolltech.vcsbase" >
+ <file>VCSBase.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/vcsbase/vcsbase_dependencies.pri b/src/plugins/vcsbase/vcsbase_dependencies.pri
new file mode 100644
index 0000000000..3a68ac9600
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbase_dependencies.pri
@@ -0,0 +1,4 @@
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/find/find.pri)
diff --git a/src/plugins/vcsbase/vcsbase_global.h b/src/plugins/vcsbase/vcsbase_global.h
new file mode 100644
index 0000000000..191587af6f
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbase_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef VCSBASEGLOBAL_H
+#define VCSBASEGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(VCSBASE_LIBRARY)
+# define VCSBASE_EXPORT Q_DECL_EXPORT
+#else
+# define VCSBASE_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // VCSBASEGLOBAL_H
diff --git a/src/plugins/vcsbase/vcsbaseconstants.h b/src/plugins/vcsbase/vcsbaseconstants.h
new file mode 100644
index 0000000000..bbe6003ed1
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseconstants.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSBaseCONSTANTS_H
+#define VCSBaseCONSTANTS_H
+
+namespace VCSBase {
+ namespace Constants {
+
+ namespace Internal {
+
+ enum { debug = 0 };
+ } // namespace Internal
+ } // namespace Constants
+} // VCSBase
+
+#endif // VCSBaseCONSTANTS_H
diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp
new file mode 100644
index 0000000000..9dfc9b12db
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseeditor.cpp
@@ -0,0 +1,486 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "vcsbaseeditor.h"
+#include "diffhighlighter.h"
+#include "baseannotationhighlighter.h"
+#include "vcsbasetextdocument.h"
+#include "vcsbaseconstants.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorconstants.h>
+
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/session.h>
+#include <projectexplorer/editorconfiguration.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QSet>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+#include <QtCore/QTextCodec>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLayout>
+#include <QtGui/QTextEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QTextCursor>
+#include <QtCore/QProcess>
+
+namespace VCSBase {
+
+// VCSBaseEditorEditable: An editable with no support for duplicates
+class VCSBaseEditorEditable : public TextEditor::BaseTextEditorEditable
+{
+public:
+ VCSBaseEditorEditable(VCSBaseEditor *,
+ const VCSBaseEditorParameters *type,
+ Core::ICore *);
+ QList<int> context() const;
+
+ bool duplicateSupported() const { return false; }
+ Core::IEditor *duplicate(QWidget * /*parent*/) { return 0; }
+ const char *kind() const { return m_kind; }
+
+private:
+ const char *m_kind;
+ QList<int> m_context;
+
+};
+
+VCSBaseEditorEditable::VCSBaseEditorEditable(VCSBaseEditor *editor,
+ const VCSBaseEditorParameters *type,
+ Core::ICore *core) :
+ BaseTextEditorEditable(editor),
+ m_kind(type->kind)
+{
+ m_context << core->uniqueIDManager()->uniqueIdentifier(QLatin1String(type->context))
+ << core->uniqueIDManager()->uniqueIdentifier(QLatin1String(TextEditor::Constants::C_TEXTEDITOR));
+
+}
+
+QList<int> VCSBaseEditorEditable::context() const
+{
+ return m_context;
+}
+
+// ----------- VCSBaseEditorPrivate
+
+struct VCSBaseEditorPrivate {
+ VCSBaseEditorPrivate(const VCSBaseEditorParameters *type, QObject *parent);
+
+ const VCSBaseEditorParameters *m_parameters;
+ QAction *m_describeAction;
+ QString m_currentChange;
+ Core::ICore *m_core;
+ QString m_source;
+};
+
+VCSBaseEditorPrivate::VCSBaseEditorPrivate(const VCSBaseEditorParameters *type, QObject *parent) :
+ m_parameters(type),
+ m_describeAction(new QAction(parent)),
+ m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>())
+{
+}
+
+// ------------ VCSBaseEditor
+VCSBaseEditor::VCSBaseEditor(const VCSBaseEditorParameters *type,
+ QWidget *parent) :
+ BaseTextEditor(parent),
+ m_d(new VCSBaseEditorPrivate(type, this))
+{
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << "VCSBaseEditor::VCSBaseEditor" << type->type << type->kind;
+
+ setReadOnly(true);
+
+ connect(m_d->m_describeAction, SIGNAL(triggered()), this, SLOT(describe()));
+
+ viewport()->setMouseTracking(true);
+
+ setBaseTextDocument(new Internal::VCSBaseTextDocument);
+
+ setMimeType(QLatin1String(m_d->m_parameters->mimeType));
+}
+
+void VCSBaseEditor::init()
+{
+ switch (m_d->m_parameters->type) {
+ case RegularCommandOutput:
+ case LogOutput:
+ case AnnotateOutput:
+ // Annotation highlighting depends on contents, which is set later on
+ connect(this, SIGNAL(textChanged()), this, SLOT(slotActivateAnnotation()));
+ break;
+ case DiffOutput:
+ baseTextDocument()->setSyntaxHighlighter(createDiffHighlighter());
+ break;
+ }
+}
+
+VCSBaseEditor::~VCSBaseEditor()
+{
+ delete m_d;
+}
+
+QString VCSBaseEditor::source() const
+{
+ return m_d->m_source;
+}
+
+void VCSBaseEditor::setSource(const QString &source)
+{
+ m_d->m_source = source;
+}
+
+QTextCodec *VCSBaseEditor::codec() const
+{
+ return baseTextDocument()->codec();
+}
+
+void VCSBaseEditor::setCodec(QTextCodec *c)
+{
+ if (c) {
+ baseTextDocument()->setCodec(c);
+ } else {
+ qWarning("%s: Attempt to set 0 codec.", Q_FUNC_INFO);
+ }
+}
+
+EditorContentType VCSBaseEditor::contentType() const
+{
+ return m_d->m_parameters->type;
+}
+
+bool VCSBaseEditor::isModified() const
+{
+ return false;
+}
+
+TextEditor::BaseTextEditorEditable *VCSBaseEditor::createEditableInterface()
+{
+ return new VCSBaseEditorEditable(this, m_d->m_parameters, m_d->m_core);
+}
+
+void VCSBaseEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+ QMenu *menu = createStandardContextMenu();
+ // 'click on change-interaction'
+ if (m_d->m_parameters->type == LogOutput || m_d->m_parameters->type == AnnotateOutput) {
+ m_d->m_currentChange = changeUnderCursor(cursorForPosition(e->pos()));
+ if (!m_d->m_currentChange.isEmpty()) {
+ m_d->m_describeAction->setText(tr("Describe change %1").arg(m_d->m_currentChange));
+ menu->addSeparator();
+ menu->addAction(m_d->m_describeAction);
+ }
+ }
+ menu->exec(e->globalPos());
+ delete menu;
+}
+
+void VCSBaseEditor::mouseMoveEvent(QMouseEvent *e)
+{
+ if (m_d->m_parameters->type == LogOutput || m_d->m_parameters->type == AnnotateOutput) {
+ // Link emulation behaviour for 'click on change-interaction'
+ QTextCursor cursor = cursorForPosition(e->pos());
+ QString change = changeUnderCursor(cursor);
+ if (!change.isEmpty()) {
+ QTextEdit::ExtraSelection sel;
+ sel.cursor = cursor;
+ sel.cursor.select(QTextCursor::WordUnderCursor);
+ sel.format.setFontUnderline(true);
+ change = changeUnderCursor(cursor);
+ sel.format.setProperty(QTextFormat::UserProperty, change);
+ bool found = false;
+ foreach (QTextEdit::ExtraSelection es, extraSelections()) {
+ if (es.format.stringProperty(QTextFormat::UserProperty) == sel.format.stringProperty(QTextFormat::UserProperty)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ setExtraSelections(QList<QTextEdit::ExtraSelection>() << sel);
+ viewport()->setCursor(Qt::PointingHandCursor);
+ }
+ } else {
+ if (!extraSelections().isEmpty()) {
+ setExtraSelections(QList<QTextEdit::ExtraSelection>());
+ viewport()->setCursor(Qt::IBeamCursor);
+ }
+ }
+ }
+ TextEditor::BaseTextEditor::mouseMoveEvent(e);
+}
+
+void VCSBaseEditor::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (m_d->m_parameters->type == LogOutput || m_d->m_parameters->type == AnnotateOutput) {
+ if (e->button() == Qt::LeftButton &&!(e->modifiers() & Qt::ShiftModifier)) {
+ QTextCursor cursor = cursorForPosition(e->pos());
+ m_d->m_currentChange = changeUnderCursor(cursor);
+ if (!m_d->m_currentChange.isEmpty()) {
+ describe();
+ e->accept();
+ return;
+ }
+ }
+ }
+ TextEditor::BaseTextEditor::mouseReleaseEvent(e);
+}
+
+void VCSBaseEditor::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ if (m_d->m_parameters->type == DiffOutput) {
+ if (e->button() == Qt::LeftButton &&!(e->modifiers() & Qt::ShiftModifier)) {
+ QTextCursor cursor = cursorForPosition(e->pos());
+ jumpToChangeFromDiff(cursor);
+ }
+ }
+ TextEditor::BaseTextEditor::mouseDoubleClickEvent(e);
+}
+
+void VCSBaseEditor::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
+ jumpToChangeFromDiff(textCursor());
+ return;
+ }
+ BaseTextEditor::keyPressEvent(e);
+}
+
+void VCSBaseEditor::describe()
+{
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << "VCSBaseEditor::describe" << m_d->m_currentChange;
+ if (!m_d->m_currentChange.isEmpty())
+ emit describeRequested(m_d->m_source, m_d->m_currentChange);
+}
+
+void VCSBaseEditor::slotActivateAnnotation()
+{
+ // The annotation highlighting depends on contents (change number
+ // set with assigned colors)
+ if (m_d->m_parameters->type != AnnotateOutput)
+ return;
+
+ const QSet<QString> changes = annotationChanges();
+ if (changes.isEmpty())
+ return;
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << "VCSBaseEditor::slotActivateAnnotation(): #" << changes.size();
+
+ disconnect(this, SIGNAL(textChanged()), this, SLOT(slotActivateAnnotation()));
+
+ if (BaseAnnotationHighlighter *ah = qobject_cast<BaseAnnotationHighlighter *>(baseTextDocument()->syntaxHighlighter())) {
+ ah->setChangeNumbers(changes);
+ ah->rehighlight();
+ } else {
+ baseTextDocument()->setSyntaxHighlighter(createAnnotationHighlighter(changes));
+ }
+}
+
+// Check for a change chunk "@@ -91,7 +95,7 @@" and return
+// the modified line number (95).
+// Note that git appends stuff after " @@" (function names, etc.).
+static inline bool checkChunkLine(const QString &line, int *modifiedLineNumber)
+{
+ if (!line.startsWith(QLatin1String("@@ ")))
+ return false;
+ const int endPos = line.indexOf(QLatin1String(" @@"), 3);
+ if (endPos == -1)
+ return false;
+ // the first chunk range applies to the original file, the second one to
+ // the modified file, the one we're interested int
+ const int plusPos = line.indexOf(QLatin1Char('+'), 3);
+ if (plusPos == -1 || plusPos > endPos)
+ return false;
+ const int lineNumberPos = plusPos + 1;
+ const int commaPos = line.indexOf(QLatin1Char(','), lineNumberPos);
+ if (commaPos == -1 || commaPos > endPos)
+ return false;
+ const QString lineNumberStr = line.mid(lineNumberPos, commaPos - lineNumberPos);
+ bool ok;
+ *modifiedLineNumber = lineNumberStr.toInt(&ok);
+ return ok;
+}
+
+void VCSBaseEditor::jumpToChangeFromDiff(QTextCursor cursor)
+{
+ int chunkStart = 0;
+ int lineCount = -1;
+ const QChar deletionIndicator = QLatin1Char('-');
+ // find nearest change hunk
+ QTextBlock block = cursor.block();
+ for ( ; block.isValid() ; block = block.previous()) {
+ const QString line = block.text();
+ if (checkChunkLine(line, &chunkStart)) {
+ break;
+ } else {
+ if (!line.startsWith(deletionIndicator))
+ ++lineCount;
+ }
+ }
+
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << "VCSBaseEditor::jumpToChangeFromDiff()1" << chunkStart << lineCount;
+
+ if (chunkStart == -1 || lineCount < 0 || !block.isValid())
+ return;
+
+ // find the filename in previous line, map depot name back
+ block = block.previous();
+ if (!block.isValid())
+ return;
+ const QString fileName = fileNameFromDiffSpecification(block);
+
+ const bool exists = fileName.isEmpty() ? false : QFile::exists(fileName);
+
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << "VCSBaseEditor::jumpToChangeFromDiff()2" << fileName << "ex=" << exists << "line" << chunkStart << lineCount;
+
+ if (!exists)
+ return;
+
+ Core::IEditor *ediface = m_d->m_core->editorManager()->openEditor(fileName);
+ m_d->m_core->editorManager()->ensureEditorManagerVisible();
+ if (TextEditor::ITextEditor *editor = qobject_cast<TextEditor::ITextEditor *>(ediface))
+ editor->gotoLine(chunkStart + lineCount);
+}
+
+void VCSBaseEditor::setPlainTextData(const QByteArray &data)
+{
+ setPlainText(codec()->toUnicode(data));
+}
+
+void VCSBaseEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ TextEditor::BaseTextEditor::setFontSettings(fs);
+ if (m_d->m_parameters->type == DiffOutput) {
+ if (DiffHighlighter *highlighter = qobject_cast<DiffHighlighter*>(baseTextDocument()->syntaxHighlighter())) {
+ static QVector<QString> categories;
+ if (categories.isEmpty()) {
+ categories << QLatin1String(TextEditor::Constants::C_TEXT)
+ << QLatin1String(TextEditor::Constants::C_ADDED_LINE)
+ << QLatin1String(TextEditor::Constants::C_REMOVED_LINE)
+ << QLatin1String(TextEditor::Constants::C_DIFF_FILE)
+ << QLatin1String(TextEditor::Constants::C_DIFF_LOCATION);
+ }
+ highlighter->setFormats(fs.toTextCharFormats(categories));
+ highlighter->rehighlight();
+ }
+ }
+}
+
+const VCSBaseEditorParameters *VCSBaseEditor::findType(const VCSBaseEditorParameters *array,
+ int arraySize,
+ EditorContentType et)
+{
+ for (int i = 0; i < arraySize; i++)
+ if (array[i].type == et)
+ return array + i;
+ return 0;
+}
+
+// Find the codec used for a file querying the editor.
+static QTextCodec *findFileCodec(const Core::ICore *core, const QString &source)
+{
+ typedef QList<Core::IEditor *> EditorList;
+
+ const EditorList editors = core->editorManager()->editorsForFileName(source);
+ if (!editors.empty()) {
+ const EditorList::const_iterator ecend = editors.constEnd();
+ for (EditorList::const_iterator it = editors.constBegin(); it != ecend; ++it)
+ if (const TextEditor::BaseTextEditorEditable *be = qobject_cast<const TextEditor::BaseTextEditorEditable *>(*it)) {
+ QTextCodec *codec = be->editor()->textCodec();
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << Q_FUNC_INFO << source << codec->name();
+ return codec;
+ }
+ }
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << Q_FUNC_INFO << source << "not found";
+ return 0;
+}
+
+// Find the codec by checking the projects (root dir of project file)
+static QTextCodec *findProjectCodec(const QString &dir)
+{
+ typedef QList<ProjectExplorer::Project*> ProjectList;
+ // Try to find a project under which file tree the file is.
+ const ProjectExplorer::SessionManager *sm = ProjectExplorer::ProjectExplorerPlugin::instance()->session();
+ const ProjectList projects = sm->projects();
+ if (!projects.empty()) {
+ const ProjectList::const_iterator pcend = projects.constEnd();
+ for (ProjectList::const_iterator it = projects.constBegin(); it != pcend; ++it)
+ if (const Core::IFile *file = (*it)->file())
+ if (file->fileName().startsWith(dir)) {
+ QTextCodec *codec = (*it)->editorConfiguration()->defaultTextCodec();
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << Q_FUNC_INFO << dir << (*it)->name() << codec->name();
+ return codec;
+ }
+ }
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << Q_FUNC_INFO << dir << "not found";
+ return 0;
+}
+
+QTextCodec *VCSBaseEditor::getCodec(const Core::ICore *core, const QString &source)
+{
+ if (!source.isEmpty()) {
+ // Check file
+ const QFileInfo sourceFi(source);
+ if (sourceFi.isFile())
+ if (QTextCodec *fc = findFileCodec(core, source))
+ return fc;
+ // Find by project via directory
+ if (QTextCodec *pc = findProjectCodec(sourceFi.isFile() ? sourceFi.absolutePath() : source))
+ return pc;
+ }
+ QTextCodec *sys = QTextCodec::codecForLocale();
+ if (VCSBase::Constants::Internal::debug)
+ qDebug() << Q_FUNC_INFO << source << "defaulting to " << sys->name();
+ return sys;
+}
+
+VCSBaseEditor *VCSBaseEditor::getVcsBaseEditor(const Core::IEditor *editor)
+{
+ if (const TextEditor::BaseTextEditorEditable *be = qobject_cast<const TextEditor::BaseTextEditorEditable *>(editor))
+ return qobject_cast<VCSBaseEditor *>(be->editor());
+ return 0;
+}
+
+}
diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h
new file mode 100644
index 0000000000..364a9fb7e9
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseeditor.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSBaseBASEEDITOR_H
+#define VCSBaseBASEEDITOR_H
+
+#include "vcsbase_global.h"
+
+#include <texteditor/basetexteditor.h>
+
+#include <QtCore/QSet>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QTextCodec;
+class QTextCursor;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace VCSBase {
+
+struct VCSBaseEditorPrivate;
+class DiffHighlighter;
+class BaseAnnotationHighlighter;
+
+// Contents of a VCSBaseEditor
+enum EditorContentType {
+ // No special handling.
+ RegularCommandOutput,
+ // Log of a file under revision control. Provide 'click on change'
+ // description.
+ LogOutput,
+ // <change description>: file line
+ // Color per change number and provide 'click on change' description.
+ AnnotateOutput,
+ // Diff output. Might includes describe output, which consists of a
+ // header and diffs. Interaction is 'double click in hunk' which
+ // opens the file
+ DiffOutput
+};
+
+// Helper struct used to parametrize an editor with mime type, context
+// and kind. The extension is currently only a suggestion when running
+// VCS commands with redirection.
+struct VCSBASE_EXPORT VCSBaseEditorParameters {
+ EditorContentType type;
+ const char *kind;
+ const char *context;
+ const char *mimeType;
+ const char *extension;
+};
+
+// Base class for editors showing version control system output
+// of the type enumerated by EditorContentType.
+// The source property should contain the file or directory the log
+// refers to and will be emitted with describeRequested().
+// This is for VCS that need a current directory.
+class VCSBASE_EXPORT VCSBaseEditor : public TextEditor::BaseTextEditor
+{
+ Q_PROPERTY(QString source READ source WRITE setSource);
+ Q_PROPERTY(QTextCodec *codec READ codec WRITE setCodec);
+ Q_OBJECT
+protected:
+ // Initialization requires calling init() (which in turns calls
+ // virtual functions).
+ explicit VCSBaseEditor(const VCSBaseEditorParameters *type,
+ QWidget *parent);
+public:
+ void init();
+
+ virtual ~VCSBaseEditor();
+
+ QString source() const;
+ void setSource(const QString &source);
+
+ QTextCodec *codec() const;
+ void setCodec(QTextCodec *);
+
+ bool isModified() const;
+
+ EditorContentType contentType() const;
+
+ // Utility to find a parameter set by type in an array.
+ static const VCSBaseEditorParameters *
+ findType(const VCSBaseEditorParameters *array, int arraySize, EditorContentType et);
+
+ // Utility to find the codec for a source (file or directory), querying
+ // the editor manager and the project managers (defaults to system codec).
+ // The codec should be set on editors displaying diff or annotation
+ // output.
+ static QTextCodec *getCodec(const Core::ICore *core, const QString &source);
+
+ // Utility to return the editor from the IEditor returned by the editor
+ // manager which is a BaseTextEditable.
+ static VCSBaseEditor *getVcsBaseEditor(const Core::IEditor *editor);
+
+signals:
+ void describeRequested(const QString &source, const QString &change);
+
+public slots:
+ // Convenience slot to set data read from stdout, will use the
+ // documents' codec to decode
+ void setPlainTextData(const QByteArray &data);
+
+protected:
+ virtual TextEditor::BaseTextEditorEditable *createEditableInterface();
+
+ void contextMenuEvent(QContextMenuEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseDoubleClickEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *);
+
+public slots:
+ void setFontSettings(const TextEditor::FontSettings &);
+
+private slots:
+ void describe();
+ void slotActivateAnnotation();
+
+private:
+ // Implement to return a set of change identifiers in
+ // annotation mode
+ virtual QSet<QString> annotationChanges() const = 0;
+ // Implement to identify a change number at the cursor position
+ virtual QString changeUnderCursor(const QTextCursor &) const = 0;
+ // Factory functions for highlighters
+ virtual DiffHighlighter *createDiffHighlighter() const = 0;
+ virtual BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const = 0;
+ // Implement to return a local file name from the diff file specification
+ // (text cursor at position above change hunk)
+ virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const = 0;
+
+ void jumpToChangeFromDiff(QTextCursor cursor);
+
+ VCSBaseEditorPrivate *m_d;
+};
+
+} // namespace Internal
+
+#endif // VCSBaseBASEEDITOR_H
diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp
new file mode 100644
index 0000000000..7337ba5d31
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseplugin.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "vcsbaseplugin.h"
+#include "diffhighlighter.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/qplugin.h>
+
+namespace VCSBase {
+namespace Internal {
+
+VCSBasePlugin *VCSBasePlugin::m_instance = 0;
+
+VCSBasePlugin::VCSBasePlugin()
+{
+ m_instance = this;
+}
+
+VCSBasePlugin::~VCSBasePlugin()
+{
+ m_instance = 0;
+}
+
+bool VCSBasePlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.vcsbase/VCSBase.mimetypes.xml"), errorMessage))
+ return false;
+
+ return true;
+}
+
+void VCSBasePlugin::extensionsInitialized()
+{
+}
+
+VCSBasePlugin *VCSBasePlugin::instance()
+{
+ return m_instance;
+}
+
+} // namespace Internal
+} // namespace VCSBase
+
+Q_EXPORT_PLUGIN(VCSBase::Internal::VCSBasePlugin)
diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h
new file mode 100644
index 0000000000..c10616ad93
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseplugin.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSBASEPLUGIN_H
+#define VCSBASEPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+
+namespace VCSBase {
+namespace Internal {
+
+class VCSBasePlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ VCSBasePlugin();
+ ~VCSBasePlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+
+ void extensionsInitialized();
+
+ static VCSBasePlugin *instance();
+
+private:
+ static VCSBasePlugin *m_instance;
+};
+
+} // namespace Internal
+} // namespace VCSBase
+
+#endif // VCSBASEPLUGIN_H
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
new file mode 100644
index 0000000000..6d271910e6
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
@@ -0,0 +1,281 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "vcsbasesubmiteditor.h"
+#include "submiteditorfile.h"
+
+#include <coreplugin/ifile.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+
+#include <utils/submiteditorwidget.h>
+#include <find/basetextfind.h>
+
+#include <QtGui/QToolBar>
+#include <QtGui/QStyle>
+#include <QtCore/QPointer>
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+static inline QAction *actionFromId(const Core::ICore *core, const char *id)
+{
+ QAction *rc = 0;
+ if (id)
+ if (const Core::ICommand *cmd = core->actionManager()->command(id))
+ rc = cmd->action();
+ if (debug)
+ qDebug() << Q_FUNC_INFO << id << rc;
+ return rc;
+}
+
+namespace VCSBase {
+
+struct VCSBaseSubmitEditorPrivate {
+ VCSBaseSubmitEditorPrivate(const VCSBaseSubmitEditorParameters *parameters,
+ Core::Utils::SubmitEditorWidget *editorWidget,
+ QObject *q);
+
+ Core::ICore *m_core;
+ Core::Utils::SubmitEditorWidget *m_widget;
+ QToolBar *m_toolWidget;
+ const VCSBaseSubmitEditorParameters *m_parameters;
+ QString m_displayName;
+ VCSBase::Internal::SubmitEditorFile *m_file;
+ QList<int> m_contexts;
+
+ QPointer<QAction> m_undoAction;
+ QPointer<QAction> m_redoAction;
+ QPointer<QAction> m_submitAction;
+ QPointer<QAction> m_diffAction;
+};
+
+VCSBaseSubmitEditorPrivate::VCSBaseSubmitEditorPrivate(const VCSBaseSubmitEditorParameters *parameters,
+ Core::Utils::SubmitEditorWidget *editorWidget,
+ QObject *q) :
+ m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()),
+ m_widget(editorWidget),
+ m_toolWidget(0),
+ m_parameters(parameters),
+ m_file(new VCSBase::Internal::SubmitEditorFile(QLatin1String(m_parameters->mimeType), q)),
+ m_undoAction(actionFromId(m_core, m_parameters->undoActionId)),
+ m_redoAction(actionFromId(m_core, m_parameters->redoActionId)),
+ m_submitAction(actionFromId(m_core, m_parameters->submitActionId)),
+ m_diffAction(actionFromId(m_core, m_parameters->diffActionId))
+{
+ m_contexts << m_core->uniqueIDManager()->uniqueIdentifier(m_parameters->context);
+}
+
+VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *parameters,
+ Core::Utils::SubmitEditorWidget *editorWidget) :
+ m_d(new VCSBaseSubmitEditorPrivate(parameters, editorWidget, this))
+{
+ m_d->m_file->setModified(false);
+ // We are always clean to prevent the editor manager from asking to save.
+ connect(m_d->m_file, SIGNAL(saveMe(QString)), this, SLOT(save(QString)));
+
+ m_d->m_widget->registerActions(m_d->m_undoAction, m_d->m_redoAction, m_d->m_submitAction, m_d->m_diffAction);
+ connect(m_d->m_widget, SIGNAL(diffSelected(QStringList)), this, SLOT(slotDiffSelectedVCSFiles(QStringList)));
+ connect(m_d->m_widget->descriptionEdit(), SIGNAL(textChanged()), this, SLOT(slotDescriptionChanged()));
+
+ Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
+ aggregate->add(new Find::BaseTextFind(m_d->m_widget->descriptionEdit()));
+ aggregate->add(this);
+}
+
+VCSBaseSubmitEditor::~VCSBaseSubmitEditor()
+{
+ delete m_d->m_toolWidget;
+ delete m_d->m_widget;
+ delete m_d;
+}
+
+void VCSBaseSubmitEditor::slotDescriptionChanged()
+{
+}
+
+bool VCSBaseSubmitEditor::createNew(const QString &contents)
+{
+ setFileContents(contents);
+ return true;
+}
+
+bool VCSBaseSubmitEditor::open(const QString &fileName)
+{
+ if (fileName.isEmpty())
+ return false;
+
+ const QFileInfo fi(fileName);
+ if (!fi.isFile() || !fi.isReadable())
+ return false;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ qWarning("Unable to open %s: %s", qPrintable(fileName), qPrintable(file.errorString()));
+ return false;
+ }
+
+ const QString text = QString::fromLocal8Bit(file.readAll());
+ if (!createNew(text))
+ return false;
+
+ m_d->m_file->setFileName(fi.absoluteFilePath());
+ return true;
+}
+
+Core::IFile *VCSBaseSubmitEditor::file()
+{
+ return m_d->m_file;
+}
+
+QString VCSBaseSubmitEditor::displayName() const
+{
+ return m_d->m_displayName;
+}
+
+void VCSBaseSubmitEditor::setDisplayName(const QString &title)
+{
+ m_d->m_displayName = title;
+}
+
+bool VCSBaseSubmitEditor::duplicateSupported() const
+{
+ return false;
+}
+
+Core::IEditor *VCSBaseSubmitEditor::duplicate(QWidget * /*parent*/)
+{
+ return 0;
+}
+
+const char *VCSBaseSubmitEditor::kind() const
+{
+ return m_d->m_parameters->kind;
+}
+
+QToolBar *VCSBaseSubmitEditor::toolBar()
+{
+ if (m_d->m_toolWidget)
+ return m_d->m_toolWidget;
+
+ if (!m_d->m_diffAction && !m_d->m_submitAction)
+ return 0;
+
+ // Create
+ QToolBar *toolBar = new QToolBar;
+ toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ const int size = m_d->m_widget->style()->pixelMetric(QStyle::PM_SmallIconSize);
+ toolBar->setIconSize(QSize(size, size));
+ toolBar->addSeparator();
+
+ if (m_d->m_submitAction)
+ toolBar->addAction(m_d->m_submitAction);
+ if (m_d->m_diffAction)
+ toolBar->addAction(m_d->m_diffAction);
+ m_d->m_toolWidget = toolBar;
+ return toolBar;
+}
+
+QList<int> VCSBaseSubmitEditor::context() const
+{
+ return m_d->m_contexts;
+}
+
+QWidget *VCSBaseSubmitEditor::widget()
+{
+ return m_d->m_widget;
+}
+
+QByteArray VCSBaseSubmitEditor::saveState() const
+{
+ return QByteArray();
+}
+
+bool VCSBaseSubmitEditor::restoreState(const QByteArray &/*state*/)
+{
+ return true;
+}
+
+QStringList VCSBaseSubmitEditor::checkedFiles() const
+{
+ return vcsFileListToFileList(m_d->m_widget->checkedFiles());
+}
+
+void VCSBaseSubmitEditor::setFileList(const QStringList &l)
+{
+ m_d->m_widget->setFileList(l);
+}
+
+void VCSBaseSubmitEditor::addFiles(const QStringList& list, bool checked, bool userCheckable)
+{
+ m_d->m_widget->addFiles(list, checked, userCheckable);
+}
+
+void VCSBaseSubmitEditor::slotDiffSelectedVCSFiles(const QStringList &rawList)
+{
+ emit diffSelectedFiles(vcsFileListToFileList(rawList));
+}
+
+bool VCSBaseSubmitEditor::save(const QString &fileName)
+{
+ const QString fName = fileName.isEmpty() ? m_d->m_file->fileName() : fileName;
+ QFile file(fName);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
+ qWarning("Unable to open %s: %s", qPrintable(fName), qPrintable(file.errorString()));
+ return false;
+ }
+ file.write(fileContents().toLocal8Bit());
+ if (!file.flush())
+ return false;
+ file.close();
+ const QFileInfo fi(fName);
+ m_d->m_file->setFileName(fi.absoluteFilePath());
+ m_d->m_file->setModified(false);
+ return true;
+}
+
+QString VCSBaseSubmitEditor::fileContents() const
+{
+ return m_d->m_widget->trimmedDescriptionText();
+}
+
+bool VCSBaseSubmitEditor::setFileContents(const QString &contents)
+{
+ m_d->m_widget->setDescriptionText(contents);
+ return true;
+}
+
+}
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h
new file mode 100644
index 0000000000..f2ba36b0c9
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h
@@ -0,0 +1,146 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSBaseSUBMITEDITOR_H
+#define VCSBaseSUBMITEDITOR_H
+
+#include "vcsbase_global.h"
+
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QtCore/QList>
+
+namespace Core {
+ namespace Utils {
+ class SubmitEditorWidget;
+ }
+}
+
+namespace VCSBase {
+
+struct VCSBaseSubmitEditorPrivate;
+
+/* Utility struct to parametrize a VCSBaseSubmitEditor. */
+struct VCSBASE_EXPORT VCSBaseSubmitEditorParameters {
+ const char *mimeType;
+ const char *kind;
+ const char *context;
+ const char *undoActionId;
+ const char *redoActionId;
+ const char *submitActionId;
+ const char *diffActionId;
+};
+
+/* Base class for a submit editor based on the Core::Utils::SubmitEditorWidget
+ * that presents the commit message in a text editor and an
+ * checkable list of modified files in a list window. The user can delete
+ * files from the list by pressing unchecking them or diff the selection
+ * by doubleclicking.
+ *
+ * The action matching the the ids (unless 0) of the parameter struct will be
+ * registered with the EditorWidget and submit/diff actions will be added to
+ * a toolbar.
+ *
+ * For the given context, there must be only one instance of the editor
+ * active.
+ * To start a submit, set the submit template on the editor and the output
+ * of the VCS status command listing the modified files as fileList and open
+ * it.
+ * The submit process is started by listening on the editor close
+ * signal and then asking the IFile interface of the editor to save the file
+ * within a IFileManager::blockFileChange() section
+ * and to launch the submit process. In addition, the action registered
+ * for submit should be connected to a slot triggering the close of the
+ * current editor in the editor manager. */
+
+class VCSBASE_EXPORT VCSBaseSubmitEditor : public Core::IEditor
+{
+ Q_OBJECT
+public:
+ typedef QList<int> Context;
+
+protected:
+ explicit VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *parameters,
+ Core::Utils::SubmitEditorWidget *editorWidget);
+
+public:
+ virtual ~VCSBaseSubmitEditor();
+
+ // Core::IEditor
+ virtual bool createNew(const QString &contents);
+ virtual bool open(const QString &fileName);
+ virtual Core::IFile *file();
+ virtual QString displayName() const;
+ virtual void setDisplayName(const QString &title);
+ virtual bool duplicateSupported() const;
+ virtual Core::IEditor *duplicate(QWidget * parent);
+ virtual const char *kind() const;
+
+ virtual QToolBar *toolBar();
+ virtual QList<int> context() const;
+ virtual QWidget *widget();
+
+ virtual QByteArray saveState() const;
+ virtual bool restoreState(const QByteArray &state);
+
+ QStringList checkedFiles() const;
+
+ void setFileList(const QStringList&);
+ void addFiles(const QStringList&, bool checked = true, bool userCheckable = true);
+
+signals:
+ void diffSelectedFiles(const QStringList &files);
+
+private slots:
+ void slotDiffSelectedVCSFiles(const QStringList &rawList);
+ bool save(const QString &fileName);
+ void slotDescriptionChanged();
+
+protected:
+ /* Implemented this to extract the real file list from the status
+ * output of the versioning system as displayed in the file list
+ * for example "M foo.cpp" -> "foo.cpp". */
+ virtual QStringList vcsFileListToFileList(const QStringList &) const = 0;
+
+ /* These hooks allow for modifying the contents that goes to
+ * the file. The default implementation uses the text
+ * of the description editor. */
+ virtual QString fileContents() const;
+ virtual bool setFileContents(const QString &contents);
+
+private:
+ VCSBaseSubmitEditorPrivate *m_d;
+};
+
+}
+
+#endif // VCSBaseSUBMITEDITOR_H
diff --git a/src/plugins/vcsbase/vcsbasetextdocument.cpp b/src/plugins/vcsbase/vcsbasetextdocument.cpp
new file mode 100644
index 0000000000..2e52e56ea0
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbasetextdocument.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "vcsbasetextdocument.h"
+
+namespace VCSBase {
+namespace Internal {
+
+VCSBaseTextDocument::VCSBaseTextDocument()
+{
+}
+
+bool VCSBaseTextDocument::isReadOnly() const
+{
+ return true;
+}
+
+bool VCSBaseTextDocument::isModified() const
+{
+ return false;
+}
+
+}
+}
diff --git a/src/plugins/vcsbase/vcsbasetextdocument.h b/src/plugins/vcsbase/vcsbasetextdocument.h
new file mode 100644
index 0000000000..9c2b2c66c6
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbasetextdocument.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef VCSBASETEXTDOCUMENT_H
+#define VCSBASETEXTDOCUMENT_H
+
+#include <texteditor/basetextdocument.h>
+
+namespace VCSBase {
+namespace Internal {
+
+// A read-only text document.
+class VCSBaseTextDocument : public TextEditor::BaseTextDocument
+{
+ Q_OBJECT
+public:
+ VCSBaseTextDocument();
+
+ bool isReadOnly() const;
+ bool isModified() const;
+};
+
+} // namespace Internal
+} // namespace VCSBase
+
+#endif // VCSBASETEXTDOCUMENT_H
diff --git a/src/qworkbench.pri b/src/qworkbench.pri
new file mode 100644
index 0000000000..d7ac4f34c5
--- /dev/null
+++ b/src/qworkbench.pri
@@ -0,0 +1,41 @@
+IDE_SOURCE_TREE = $$PWD/../
+
+isEmpty(TEST) {
+ CONFIG(debug, debug|release) {
+ TEST = 1
+ }
+}
+
+!isEmpty(TEST) {
+ equals(TEST, 1) {
+ QT +=testlib
+ DEFINES+=WITH_TESTS
+ }
+}
+
+isEmpty(IDE_BUILD_TREE) {
+ error("qworkbench.pri: including file must define IDE_BUILD_TREE (probably a relative path)")
+}
+macx {
+ IDE_APP_TARGET = QtCreator
+ IDE_LIBRARY_PATH = $$IDE_BUILD_TREE/bin/$${IDE_APP_TARGET}.app/Contents/PlugIns
+ contains(QT_CONFIG, ppc):CONFIG += ppc x86
+} else {
+ IDE_APP_TARGET = qtcreator
+ IDE_LIBRARY_PATH = $$IDE_BUILD_TREE/lib
+}
+IDE_APP_PATH = $$IDE_BUILD_TREE/bin
+win32 {
+ IDE_LIBRARY_PATH ~= s|/+|\|
+ IDE_APP_PATH ~= s|/+|\|
+}
+
+INCLUDEPATH += \
+ $$IDE_SOURCE_TREE/src/libs \
+ $$IDE_SOURCE_TREE/tools \
+
+DEPENDPATH += \
+ $$IDE_SOURCE_TREE/src/libs \
+ $$IDE_SOURCE_TREE/tools \
+
+LIBS += -L$$IDE_LIBRARY_PATH
diff --git a/src/qworkbenchlibrary.pri b/src/qworkbenchlibrary.pri
new file mode 100644
index 0000000000..1ef9b3fbec
--- /dev/null
+++ b/src/qworkbenchlibrary.pri
@@ -0,0 +1,22 @@
+IDE_BUILD_TREE = $$OUT_PWD/../../../
+include(qworkbench.pri)
+
+win32 {
+ DLLDESTDIR = $$IDE_APP_PATH
+}
+
+DESTDIR = $$IDE_LIBRARY_PATH
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/
+} else:linux-* {
+ #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ QMAKE_RPATHDIR += \$\$ORIGIN
+ IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":")
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\'
+ QMAKE_RPATHDIR =
+}
+
+TARGET = $$qtLibraryTarget($$TARGET)
+
+contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
diff --git a/src/qworkbenchplugin.pri b/src/qworkbenchplugin.pri
new file mode 100644
index 0000000000..50b667fc71
--- /dev/null
+++ b/src/qworkbenchplugin.pri
@@ -0,0 +1,57 @@
+isEmpty(IDE_BUILD_TREE) {
+ IDE_BUILD_TREE = $$OUT_PWD/../../../
+}
+include(qworkbench.pri)
+
+isEmpty(PROVIDER) {
+ PROVIDER = Nokia
+}
+
+DESTDIR = $$IDE_LIBRARY_PATH/$$PROVIDER/
+LIBS += -L$$DESTDIR
+INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins
+DEPENDPATH += $$IDE_SOURCE_TREE/src/plugins
+
+# copy the plugin spec
+isEmpty(TARGET) {
+ error("qworkbenchplugin.pri: You must provide a TARGET")
+}
+
+# Copy the pluginspec file to the liberary directyory.
+# Note: On Windows/MinGW with some sh.exe in the path,
+# QMAKE_COPY is some cp command that does not understand
+# "\". Force the standard windows copy.
+COPYDEST = $${DESTDIR}
+COPYSRC = $${_PRO_FILE_PWD_}/$${TARGET}.pluginspec
+
+TARGET = $$qtLibraryTarget($$TARGET)
+
+win32 {
+ COPYDEST ~= s|/+|\|
+ COPYSRC ~= s|/+|\|
+ COPY_CMD=xcopy /y
+} else {
+ COPY_CMD=$${QMAKE_COPY}
+}
+
+QMAKE_POST_LINK += $${COPY_CMD} $${COPYSRC} $${COPYDEST}
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/
+} else:linux-* {
+ #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ QMAKE_RPATHDIR += \$\$ORIGIN/..
+ IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":")
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\'
+ QMAKE_RPATHDIR =
+}
+
+
+unix {
+ OBJECTS_DIR = $${OUT_PWD}/.obj/
+ MOC_DIR = $${OUT_PWD}/.moc/
+ RCC_DIR = $${OUT_PWD}/.rcc/
+ UI_DIR = $${OUT_PWD}/.uic/
+}
+
+contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000000..0db231df31
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = \
+ libs \
+ app \
+ plugins
+
+
diff --git a/src/tools/makespy/main.cpp b/src/tools/makespy/main.cpp
new file mode 100644
index 0000000000..bee1a8f0d5
--- /dev/null
+++ b/src/tools/makespy/main.cpp
@@ -0,0 +1,211 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QApplication>
+#include <QDebug>
+#include <QDir>
+#include <QProcess>
+#include <QStringList>
+#include <QTextStream>
+#include <QTextEdit>
+
+class Process : public QProcess
+{
+ Q_OBJECT
+public:
+ Process();
+
+ QString output() const { return m_output; }
+ QString error() const { return m_error; }
+
+private slots:
+ void standardErrorReady();
+ void standardOutputReady();
+
+private:
+ QString m_output;
+ QString m_error;
+};
+
+Process::Process()
+{
+ connect(this, SIGNAL(readyReadStandardError()),
+ this, SLOT(standardErrorReady()));
+ connect(this, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(standardOutputReady()));
+}
+
+void Process::standardErrorReady()
+{
+ m_error += readAllStandardError();
+}
+
+void Process::standardOutputReady()
+{
+ m_output += readAllStandardOutput();
+}
+
+
+class MakeProcess : public Process
+{
+public:
+ void handleOutput();
+
+private:
+ void handleMakeLine(const QString &line);
+ void handleGccLine(const QString &line);
+
+ QStringList m_dirStack;
+
+ QVector<QString> m_options;
+ QStringList m_sourceFiles;
+ QStringList m_headerFiles;
+};
+
+void MakeProcess::handleOutput()
+{
+ QStringList lines = output().split('\n');
+ m_dirStack.clear();
+ m_dirStack.append(workingDirectory());
+ foreach (const QString &line, lines) {
+ qDebug() << "LINE : " << line;
+ if (line.startsWith("make["))
+ handleMakeLine(line);
+ else if (line.startsWith("gcc") || line.startsWith("g++"))
+ handleGccLine(line);
+ else
+ qDebug() << "IGNORE: " << line;
+ }
+}
+
+
+void MakeProcess::handleMakeLine(const QString &line)
+{
+ int pos1 = line.indexOf('`');
+ int pos2 = line.indexOf('\'');
+ if (pos1 >= 0 && pos2 >= 0) {
+ QString dir = line.mid(pos1 + 1, pos2 - pos1 - 1);
+ qDebug() << "MAKE" << pos1 << pos2 << dir;
+ if (line.contains(": Entering directory")) {
+ qDebug() << "ENTER: " << dir;
+ m_dirStack.append(dir);
+ } else if (line.contains(": Leaving directory")) {
+ qDebug() << "LEAVE: " << dir;
+ Q_ASSERT(m_dirStack.last() == dir);
+ (void) m_dirStack.takeLast();
+ }
+ }
+}
+
+QStringList parseLine(const QString &line)
+{
+ QStringList result;
+ QString word;
+ bool quoted = false;
+ bool escaped = false;
+ for (int i = 0; i != line.size(); ++i) {
+ char c = line.at(i).unicode();
+ if (c == '\'') {
+ escaped = true;
+ continue;
+ }
+ if (c == '\"' && !escaped) {
+ quoted = !quoted;
+ } else if (c == ' ' && !quoted) {
+ if (!word.isEmpty())
+ result.append(word);
+ word.clear();
+ } else {
+ word += c;
+ }
+ }
+ if (!word.isEmpty())
+ result.append(word);
+ return result;
+}
+
+void MakeProcess::handleGccLine(const QString &line)
+{
+ QStringList args = parseLine(line);
+ qDebug() << "GCC: " << args;
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QStringList args = app.arguments();
+ QString buildName = ".makespybuild/gdb";
+ //args << "
+
+ QDir oldDir = QDir::current();
+ QDir buildDir("/home/apoenitz/gdb/archer");
+ buildDir.mkdir(buildName);
+ buildDir.cd(buildName);
+ QDir::setCurrent(buildDir.absolutePath());
+
+/*
+ Process configure;
+ configure.setWorkingDirectory(buildDir.absolutePath());
+ configure.start("../configure", QStringList());
+ configure.waitForFinished();
+ qDebug() << configure.errorString();
+ qDebug() << configure.error();
+ qDebug() << configure.output();
+*/
+ MakeProcess make;
+ make.setWorkingDirectory(buildDir.absolutePath());
+ make.start("make", QStringList());
+ make.waitForFinished();
+ make.handleOutput();
+ qDebug() << make.errorString();
+ qDebug() << make.error();
+ qDebug() << make.output();
+
+ Process clean;
+ clean.setWorkingDirectory(buildDir.absolutePath());
+ clean.start("make", QStringList() << "clean");
+ clean.waitForFinished();
+ qDebug() << clean.errorString();
+ qDebug() << clean.error();
+ qDebug() << clean.output();
+
+ QTextEdit edit;
+ edit.setText(make.error() + make.output());
+ edit.resize(800, 600);
+ edit.show();
+
+ return app.exec();
+ return 0;
+}
+
+#include "main.moc"
diff --git a/src/tools/makespy/makespy.pro b/src/tools/makespy/makespy.pro
new file mode 100644
index 0000000000..604f309a26
--- /dev/null
+++ b/src/tools/makespy/makespy.pro
@@ -0,0 +1,6 @@
+TARGET = MakeSpy
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+SOURCES += main.cpp
+HEADERS +=
diff --git a/src/tools/qdebugger/lean.h b/src/tools/qdebugger/lean.h
new file mode 100644
index 0000000000..69935c83ee
--- /dev/null
+++ b/src/tools/qdebugger/lean.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QDBIMPORTS_H
+#define QDBIMPORTS_H
+
+#include <QtCore/QFile>
+#include <QtCore/QList>
+#include <QtGui/QIcon>
+#include <QtGui/QPlainTextEdit>
+
+namespace TextEditor {
+
+class BaseTextMark : public QObject
+{
+// Q_OBJECT
+public:
+ BaseTextMark(const QString &/*filename*/, int /*line*/) {}
+ ~BaseTextMark() {}
+
+ // return your icon here
+ virtual QIcon icon() const { return QIcon(); }
+
+ // called if the linenumber changes
+ virtual void updateLineNumber(int /*lineNumber*/) {}
+
+ // called whenever the text of the block for the marker changed
+ virtual void updateBlock(const QTextBlock &/*block*/) {}
+
+ // called if the block containing this mark has been removed
+ // if this also removes your mark call this->deleteLater();
+ virtual void removedFromEditor() {}
+ // call this if the icon has changed.
+ void updateMarker() {}
+
+public:
+ QString m_fileName;
+ int m_line;
+};
+
+} // namespace TextEditor
+
+
+
+#ifdef USE_BASETEXTEDITOR
+
+#define BASETEXTMARK_H
+#include "../../plugins/texteditor/basetexteditor.h"
+
+
+class Editable : public TextEditor::BaseTextEditorEditable
+{
+ Q_OBJECT
+
+public:
+ Editable(TextEditor::BaseTextEditor *editor)
+ : TextEditor::BaseTextEditorEditable(editor)
+ {}
+
+ // Core::IContext
+ QList<int> context() const { return m_context; }
+
+ // Core::IEditor
+ const char* kind() const { return "MYEDITOR"; }
+ bool duplicateSupported() const { return false; }
+ Core::IEditor* duplicate(QWidget*) { return 0; }
+
+ QList<int> m_context;
+};
+
+
+class TextViewer : public TextEditor::BaseTextEditor
+{
+ Q_OBJECT
+
+public:
+ TextViewer(QWidget *parent)
+ : TextEditor::BaseTextEditor(parent)
+ {
+ setCodeFoldingVisible(true);
+ setMarksVisible(true);
+ setHighlightCurrentLine(true);
+ }
+
+ TextEditor::BaseTextEditorEditable* createEditableInterface()
+ {
+ return new Editable(this);
+ }
+
+ QString fileName() { return file()->fileName(); }
+
+ int currentLine() const { return textCursor().blockNumber() + 1; }
+};
+
+
+#else // defined(USE_BASETEXTEDITOR)
+
+
+class TextViewer : public QPlainTextEdit
+{
+ Q_OBJECT
+
+public:
+ TextViewer(QWidget *parent) : QPlainTextEdit(parent) {}
+ QString fileName() const { return m_fileName; }
+ int currentLine() const { return textCursor().blockNumber() + 1; }
+
+ bool open(const QString &fileName)
+ {
+ m_fileName = fileName;
+ QFile file(fileName);
+ bool result = file.open(QIODevice::ReadOnly);
+ QString contents = file.readAll();
+ setPlainText(contents);
+ return result;
+ }
+
+public:
+ QString m_fileName;
+};
+
+#endif // defined(USE_BASETEXTEDITOR)
+
+#endif // QDBIMPORTS
diff --git a/src/tools/qdebugger/main.cpp b/src/tools/qdebugger/main.cpp
new file mode 100644
index 0000000000..101a046cf2
--- /dev/null
+++ b/src/tools/qdebugger/main.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow mw;
+ mw.show();
+ QStringList args = app.arguments();
+ args.removeFirst(); // program name..
+ mw.loadFiles(args);
+ return app.exec();
+}
+
diff --git a/src/tools/qdebugger/mainwindow.cpp b/src/tools/qdebugger/mainwindow.cpp
new file mode 100644
index 0000000000..e1203b6fac
--- /dev/null
+++ b/src/tools/qdebugger/mainwindow.cpp
@@ -0,0 +1,543 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "mainwindow.h"
+
+#include "gdbdebugger.h"
+#include "gdboutputwindow.h"
+#include "lean.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QPointer>
+#include <QtCore/QSettings>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QComboBox>
+#include <QtGui/QDockWidget>
+#include <QtGui/QFileDialog>
+#include <QtGui/QGridLayout>
+#include <QtGui/QHeaderView>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMenu>
+#include <QtGui/QMenuBar>
+#include <QtGui/QMessageBox>
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QStatusBar>
+#include <QtGui/QTabWidget>
+#include <QtGui/QTextBlock>
+#include <QtGui/QToolBar>
+#include <QtGui/QTreeView>
+#include <QtGui/QWidget>
+
+using namespace GdbDebugger;
+using namespace GdbDebugger::Internal;
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// LocationMark
+//
+///////////////////////////////////////////////////////////////////////
+
+#ifdef USE_BASETEXTEDITOR
+
+class LocationMark : public TextEditor::ITextMark
+{
+public:
+ LocationMark() { m_editor = 0; }
+ ~LocationMark() { qDebug() << "LOCATIONMARK DESTRUCTOR" << m_editor; }
+
+ QIcon icon() const;
+ QColor color() const;
+
+ void contextMenu(const QPoint &/*position*/) {}
+ void toggle() {}
+
+ void updateLineNumber(int /*line*/) {}
+ void removedFromEditor() { m_editor = 0; }
+
+ TextViewer *editor() const { return m_editor.data(); }
+ void setEditor(TextViewer *editor);
+
+ void updateBlock(const QTextBlock &) {}
+ void documentClosing() {}
+
+private:
+ QPointer<TextViewer> m_editor;
+};
+
+void LocationMark::setEditor(TextViewer *editor)
+{
+ if (m_editor)
+ m_editor->markableInterface()->removeMark(this);
+ if (editor)
+ m_editor = editor;
+ else
+ m_editor = 0;
+}
+
+QIcon LocationMark::icon() const
+{
+ static const QIcon icon(":/gdbdebugger/images/location.svg");
+ return icon;
+}
+
+QColor LocationMark::color() const
+{
+ return QColor(255, 255, 0, 20);
+}
+
+LocationMark *theLocationMark()
+{
+ static LocationMark *mark = new LocationMark;
+ return mark;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+//
+// MainWindow
+//
+///////////////////////////////////////////////////////////////////////////
+
+MainWindow::MainWindow()
+{
+ m_manager = new DebuggerManager;
+ m_manager->initialize();
+ m_manager->createDockWidgets();
+ m_manager->setSimpleDockWidgetArrangement();
+ setCentralWidget(m_manager->mainWindow());
+
+ //
+ // Source code view
+ //
+ m_textViewers = new QTabWidget(m_manager->mainWindow());
+ m_textViewers->setObjectName("Editors");
+ m_textViewers->setElideMode(Qt::ElideLeft);
+ //setCentralWidget(m_textViewers);
+ m_manager->mainWindow()->setCentralWidget(m_textViewers);
+ setGeometry(QRect(0, 0, 800, 600));
+
+ //
+ // Actions
+ //
+ m_fileOpenAction = new QAction(tr("Open file"), this);
+ m_fileOpenAction->setShortcut(QKeySequence(tr("Ctrl+O")));
+
+ m_quitAction = new QAction(tr("Quit"), this);
+ m_quitAction->setShortcut(QKeySequence(tr("Ctrl+Q")));
+
+#if 0
+ m_startDebuggerAction = new QAction(tr("Run to main()"), this);
+ m_startDebuggerAction->setShortcut(QKeySequence(tr("Ctrl+F5")));
+ connect(m_startDebuggerAction, SIGNAL(triggered()),
+ this, SLOT(startDebuggerRequest()));
+ connect(m_resetAction, SIGNAL(triggered()),
+ m_manager, SLOT(resetDebugger()));
+ connect(m_watchAction, SIGNAL(triggered()),
+ m_manager, SLOT(addToWatchWindow()));
+ connect(m_breakAction, SIGNAL(triggered()),
+ this, SLOT(toggleBreakpoint()));
+#endif
+
+ m_manager->m_continueAction->setShortcut(QKeySequence(tr("F5")));
+ m_manager->m_stopAction->setShortcut(QKeySequence(tr("Shift+F5")));
+
+ //m_resetAction = new QAction(tr("Reset Debugger"), this);
+ //m_resetAction->setShortcut(QKeySequence(tr("Ctrl+Shift+F5")));
+
+ m_manager->m_nextAction->setShortcut(QKeySequence(tr("F6")));
+ m_manager->m_stepAction->setShortcut(QKeySequence(tr("F7")));
+ m_manager->m_nextIAction->setShortcut(QKeySequence(tr("Shift+F6")));
+ m_manager->m_stepIAction->setShortcut(QKeySequence(tr("Shift+F9")));
+ m_manager->m_stepOutAction->setShortcut(QKeySequence(tr("Shift+F7")));
+ m_manager->m_runToLineAction->setShortcut(QKeySequence(tr("Shift+F8")));
+ //m_manager->m_jumpToLineAction->setShortcut(QKeySequence(tr("Shift+F8")));
+ m_manager->m_breakAction->setShortcut(QKeySequence(tr("F8")));
+ m_manager->m_watchAction->setShortcut(QKeySequence(tr("ALT+D,ALT+W")));
+
+ //
+ // Files
+ //
+ QDockWidget *filesDock = new QDockWidget(this);
+ filesDock->setObjectName("FilesDock");
+ filesDock->setGeometry(QRect(0, 0, 200, 200));
+ filesDock->setWindowTitle(tr("Files"));
+ filesDock->setAllowedAreas(Qt::AllDockWidgetAreas);
+ addDockWidget(Qt::LeftDockWidgetArea, filesDock);
+
+ m_filesModel = new QStandardItemModel(this);
+ m_filesWindow = new QTreeView(this);
+ m_filesWindow->setModel(m_filesModel);
+ m_filesWindow->header()->hide();
+ m_filesWindow->setRootIsDecorated(false);
+ filesDock->setWidget(m_filesWindow);
+ connect(m_filesWindow, SIGNAL(activated(QModelIndex)),
+ this, SLOT(changeCurrentFile(QModelIndex)));
+ connect(m_filesWindow, SIGNAL(clicked(QModelIndex)),
+ this, SLOT(changeCurrentFile(QModelIndex)));
+
+ //
+ // Menubar
+ //
+ QMenu *fileMenu = new QMenu(menuBar());
+ fileMenu->setTitle(tr("File"));
+ fileMenu->addAction(m_fileOpenAction);
+ fileMenu->addSeparator();
+ fileMenu->addAction(m_quitAction);
+ menuBar()->addMenu(fileMenu);
+
+ QMenu *debugMenu = new QMenu(menuBar());
+ debugMenu->setTitle(tr("Debug"));
+ debugMenu->addAction(m_manager->m_continueAction);
+ debugMenu->addAction(m_manager->m_stopAction);
+ debugMenu->addSeparator();
+ debugMenu->addAction(m_manager->m_nextAction);
+ debugMenu->addAction(m_manager->m_stepAction);
+ debugMenu->addAction(m_manager->m_nextIAction);
+ debugMenu->addAction(m_manager->m_stepIAction);
+ debugMenu->addAction(m_manager->m_stepOutAction);
+ debugMenu->addAction(m_manager->m_runToLineAction);
+ debugMenu->addAction(m_manager->m_runToFunctionAction);
+ debugMenu->addAction(m_manager->m_jumpToLineAction);
+ debugMenu->addSeparator();
+ debugMenu->addAction(m_manager->m_breakAction);
+ //debugMenu->addAction(m_startDebuggerAction);
+ menuBar()->addMenu(debugMenu);
+
+ //
+ // Toolbar
+ //
+ QToolBar *toolbar = m_manager->createToolBar();
+ toolbar->setObjectName("ToolBar");
+ addToolBar(Qt::TopToolBarArea, toolbar);
+
+ //
+ // Statusbar
+ //
+ QStatusBar *statusbar = new QStatusBar(this);
+ statusbar->setObjectName("StatusBar");
+ statusbar->setGeometry(QRect(0, 578, 800, 22));
+ setStatusBar(statusbar);
+
+ show();
+ restoreState(settings().value("MainWindow/State").toByteArray());
+ setGeometry(settings().value("MainWindow/Geometry").toRect());
+
+ connect(m_fileOpenAction, SIGNAL(triggered()),
+ this, SLOT(fileOpen()));
+ connect(m_quitAction, SIGNAL(triggered()),
+ this, SLOT(quit()));
+
+ connect(m_manager, SIGNAL(resetLocationRequested()),
+ this, SLOT(resetLocation()));
+ connect(m_manager, SIGNAL(gotoLocationRequested(QString,int,bool)),
+ this, SLOT(gotoLocation(QString,int,bool)));
+ connect(m_manager, SIGNAL(dataDumpersUnavailable()),
+ this, SLOT(handleDataDumpersUnavailable()));
+
+ // Application interaction
+ connect(m_manager, SIGNAL(currentTextEditorRequested(QString*,int*,QObject**)),
+ this, SLOT(queryCurrentTextEditor(QString*,int*,QObject**)));
+}
+
+MainWindow::~MainWindow()
+{
+ settings().setValue("MainWindow/State", saveState());
+ settings().setValue("MainWindow/Geometry", geometry());
+ settings().sync();
+}
+
+QSettings &MainWindow::settings()
+{
+ static QSettings s("Nokia", "Qdb");
+ return s;
+}
+
+void MainWindow::loadFile(const QString &fileName)
+{
+ QFileInfo fi(fileName);
+ if (fi.isExecutable() && !fileName.endsWith(".cpp") && !fileName.endsWith(".h")) {
+ m_executable = fileName;
+ QStandardItem *item = new QStandardItem(fileName);
+ QStandardItem *childItem = new QStandardItem("<gdb not running>");
+ item->appendRow(childItem); // force [+] on item
+ item->setToolTip(fi.absoluteFilePath());
+ //m_fileModel->appendRow(item);
+ } else {
+ (void)findOrCreateTextViewer(fileName);
+ }
+}
+
+void MainWindow::loadFiles(const QStringList &fileNames)
+{
+ if (fileNames.isEmpty())
+ return;
+ foreach (const QString &fileName, fileNames)
+ loadFile(fileName);
+ startDebuggingRequest();
+}
+
+void MainWindow::startDebuggingRequest()
+{
+ if (m_manager->m_startIsContinue) {
+ m_manager->continueInferior();
+ return;
+ }
+
+ m_manager->settings()->m_autoRun = true;
+ m_manager->settings()->m_autoQuit = true;
+ m_manager->settings()->m_gdbCmd = "gdb";
+ m_manager->settings()->m_breakOnMain = "gdb";
+ qDebug() << "START REQUEST";
+
+ if (m_executable.isEmpty()) {
+ QMessageBox::warning(0,
+ tr("Not a runnable project"),
+ tr("The current startup project can not be run."));
+ return;
+ }
+ StartData sd;
+ sd.outputFile = m_executable;
+ //Project *pro = project();
+ //sd.outputFile = pro->executable(pro->activeConfiguration());
+ // NBS TODO pid
+ // pid = pe->configLanguage(
+ // ProjectExplorer::Constants::P_RUNNINGPID, langID).toString();
+ // sd.env = pro->environment(pro->activeConfiguration()).toStringList();
+ // sd.workingDir = pro->workingDirectory(pro->activeConfiguration());
+ // sd.processArgs = pro->executableArguments(pro->activeConfiguration());
+ // const QFileInfo editorFile(textViewer->file()->fileName());
+ // sd.currentEditorDir = editorFile.dir().absolutePath();
+
+ m_manager->startDebuggerAndRunInferior(sd);
+}
+
+void MainWindow::startDebuggerRequest()
+{
+ // FIXME: Ignored
+ StartData sd;
+ sd.outputFile = m_executable;
+ //Project *pro = project();
+ //sd.outputFile = pro->executable(pro->activeConfiguration());
+ // NBS TODO pid
+ // pid = pe->configLanguage(
+ // ProjectExplorer::Constants::P_RUNNINGPID, langID).toString();
+ // sd.env = pro->environment(pro->activeConfiguration()).toStringList();
+ // sd.workingDir = pro->workingDirectory(pro->activeConfiguration());
+ // sd.processArgs = pro->executableArguments(pro->activeConfiguration());
+ // const QFileInfo editorFile(textViewer->file()->fileName());
+ // sd.currentEditorDir = editorFile.dir().absolutePath();
+
+ m_manager->m_settings->m_autoRun = false;
+ m_manager->m_settings->m_autoQuit = true;
+ m_manager->startDebuggerAndRunInferior(sd);
+}
+
+void MainWindow::jumpToExec()
+{
+#if 0
+ TextViewer *editor = currentTextViewer();
+ if (!editor)
+ return;
+
+ int lineNumber = editor->currentLine();
+ QString fileName = editor->file()->fileName();
+
+ if (fileName.isEmpty())
+ return;
+
+ m_manager->jumpToLineExec(fileName, lineNumber);
+#endif
+}
+
+void MainWindow::runToExec()
+{
+#if 0
+ TextViewer *editor = currentTextViewer();
+ if (!editor)
+ return;
+
+ int lineNumber = editor->currentLine();
+ QString fileName = editor->file()->fileName();
+
+ if (fileName.isEmpty())
+ return;
+
+ m_manager->runToLineExec(fileName, lineNumber);
+#endif
+}
+
+void MainWindow::showStatusMessage(const QString &msg, int timeout)
+{
+ statusBar()->showMessage(msg, timeout);
+}
+
+void MainWindow::resetLocation()
+{
+ TextViewer *textViewer = currentTextViewer();
+ if (!textViewer)
+ return;
+ const int blockNumber = m_textBlockFromName.value(textViewer, -1);
+ if (blockNumber == 1)
+ return;
+ const QTextBlock &block = textViewer->document()->findBlockByNumber(blockNumber);
+ if (block.isValid()) {
+ QTextCursor cursor(block);
+ //QTextBlockFormat format = block.blockFormat();
+ //format.setBackground(QColor(200, 200, 250));
+ cursor.setBlockFormat(QTextBlockFormat());
+ textViewer->setTextCursor(cursor);
+ textViewer->centerCursor();
+ }
+#ifdef USE_BASETEXTEDITOR
+ if (TextViewer *editor = theLocationMark()->editor())
+ editor->markableInterface()->removeMark(theLocationMark());
+ theLocationMark()->setEditor(0);
+#endif
+}
+
+void MainWindow::gotoLocation(const QString &fileName, int line, bool setMarker)
+{
+ //qDebug() << "GOTO " << fileName << line << setMarker;
+ Q_UNUSED(setMarker);
+ TextViewer *textViewer = findOrCreateTextViewer(fileName);
+ m_textViewers->setCurrentWidget(textViewer);
+
+ const int blockNumber = line - 1;
+ const QTextBlock &block = textViewer->document()->findBlockByNumber(blockNumber);
+ if (block.isValid()) {
+ QTextCursor cursor(block);
+ QTextBlockFormat format = block.blockFormat();
+ format.setBackground(QColor(230, 200, 200));
+ cursor.setBlockFormat(format);
+ textViewer->setTextCursor(cursor);
+ textViewer->centerCursor();
+ m_textBlockFromName[textViewer] = blockNumber;
+
+#ifdef USE_BASETEXTEDITOR
+ if (line >= 1) {
+ if (setMarker) {
+ theLocationMark()->setEditor(textViewer);
+ textViewer->markableInterface()->addMark(theLocationMark(), line);
+ }
+ textViewer->gotoLine(line + 8);
+ textViewer->gotoLine(line);
+ // FIXME: editor->centerCursor();
+ }
+#endif
+ } else {
+ qDebug() << "INVALID BLOCK FOR LINE " << line << " IN " << fileName;
+ }
+}
+
+void MainWindow::quit()
+{
+ m_manager->exitDebugger();
+ close();
+}
+
+void MainWindow::fileOpen()
+{
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Open File"),
+ settings().value("FileOpen/LastDir").toString()
+ // filterQString & filter = QString(),
+ //QString * selectedFilter = 0, Options options = 0
+ );
+ settings().setValue("FileOpen/LastDir", QFileInfo(fileName).dir().dirName());
+ if (fileName.isEmpty())
+ return;
+ loadFile(fileName);
+}
+
+void MainWindow::queryCurrentTextEditor(QString *fileName, int *line, QObject **object)
+{
+ //Core::IEditor *editor = core->editorManager()->currentEditor();
+ //*textEditor = qobject_cast<ITextEditor*>(current);
+ TextViewer *textEditor = currentTextViewer();
+ if (fileName)
+ *fileName = textEditor->fileName();
+ if (line)
+ *line = textEditor->currentLine();
+ if (object)
+ *object = textEditor;
+}
+
+
+TextViewer *MainWindow::findOrCreateTextViewer(const QString &fileName)
+{
+ TextViewer *textViewer = m_textViewerFromName.value(fileName);
+ if (textViewer)
+ return textViewer;
+
+ textViewer = new TextViewer(this);
+ textViewer->open(fileName);
+ textViewer->setReadOnly(true);
+ m_textViewerFromName[fileName] = textViewer;
+ m_textViewers->addTab(textViewer, fileName);
+ m_textViewers->setCurrentWidget(textViewer);
+
+ if (m_filesModel->findItems(fileName).isEmpty())
+ m_filesModel->appendRow(new QStandardItem(fileName));
+ //m_manager->textEditorOpened(textViewer->editableInterface());
+
+ return textViewer;
+}
+
+TextViewer *MainWindow::currentTextViewer()
+{
+ return qobject_cast<TextViewer *>(m_textViewers->currentWidget());
+}
+
+void MainWindow::changeCurrentFile(const QModelIndex &idx)
+{
+ QString fileName = m_filesModel->data(idx).toString();
+ m_textViewers->setCurrentWidget(findOrCreateTextViewer(fileName));
+}
+
+void MainWindow::handleDataDumpersUnavailable()
+{
+ QMessageBox::warning(this, tr("Cannot find special data dumpers"),
+ tr("The debugged binary does not contain information needed for "
+ "nice display of Qt data types.\n\n"
+ "Make sure you use something like\n\n"
+ "SOURCES *= .../ide/main/bin/gdbmacros/gdbmacros.cpp\n\n"
+ "in your .pro file.")
+ );
+}
diff --git a/src/tools/qdebugger/mainwindow.h b/src/tools/qdebugger/mainwindow.h
new file mode 100644
index 0000000000..6a313b6ed1
--- /dev/null
+++ b/src/tools/qdebugger/mainwindow.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QDB_MAINWINDOW_H
+#define QDB_MAINWINDOW_H
+
+#include <QtCore/QHash>
+
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+
+namespace GdbDebugger {
+namespace Internal {
+class DebuggerManager;
+} // namespace Internal
+} // namespace GdbDebugger
+
+class TextViewer;
+
+QT_BEGIN_NAMESPACE
+class QModelIndex;
+class QPlainTextEdit;
+class QSettings;
+class QTabWidget;
+class QTreeView;
+class QStandardItemModel;
+QT_END_NAMESPACE
+
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow();
+ ~MainWindow();
+
+ void loadFile(const QString &fileName);
+ void loadFiles(const QStringList &fileNames);
+
+private slots:
+ void startDebuggerRequest();
+ void startDebuggingRequest();
+ void jumpToExec();
+ void runToExec();
+ void showStatusMessage(const QString &msg, int timeout);
+ void resetLocation();
+ void gotoLocation(const QString &fileName, int line, bool setMarker);
+ void fileOpen();
+ void quit();
+ void changeCurrentFile(const QModelIndex &idx);
+ void handleDataDumpersUnavailable();
+ void queryCurrentTextEditor(QString *fileName, int *lineNumber,
+ QObject **widget);
+
+private:
+ QSettings &settings();
+
+ QAction *m_fileOpenAction;
+ QAction *m_quitAction;
+ //QAction *m_resetAction; // FIXME: Should not be needed in a stable release
+
+ QTreeView *m_filesWindow;
+ QStandardItemModel *m_filesModel;
+ GdbDebugger::Internal::DebuggerManager *m_manager;
+
+ QTabWidget *m_textViewers;
+ QHash<QString, TextViewer *> m_textViewerFromName;
+ QHash<TextViewer *, int> m_textBlockFromName;
+ TextViewer *findOrCreateTextViewer(const QString &fileName);
+ TextViewer *currentTextViewer();
+
+ QString m_executable;
+};
+
+#endif // QDB_MAINWINDOW_H
diff --git a/src/tools/qdebugger/qdebugger.pro b/src/tools/qdebugger/qdebugger.pro
new file mode 100644
index 0000000000..a4ff3e3bf9
--- /dev/null
+++ b/src/tools/qdebugger/qdebugger.pro
@@ -0,0 +1,123 @@
+
+QTCREATOR = ../../plugins/
+
+TARGET = ../../../bin/qdebugger
+
+QT += gui \
+ network
+
+CONFIG -= release
+CONFIG += debug
+
+DEFINES += GDBDEBUGGERLEAN
+
+INCLUDEPATH += $${QTCREATOR}
+INCLUDEPATH += $${QTCREATOR}/gdbdebugger
+
+HEADERS += \
+ lean.h \
+ mainwindow.h \
+ $${QTCREATOR}/gdbdebugger/attachexternaldialog.h \
+ $${QTCREATOR}/gdbdebugger/breakhandler.h \
+ $${QTCREATOR}/gdbdebugger/breakwindow.h \
+ $${QTCREATOR}/gdbdebugger/disassemblerhandler.h \
+ $${QTCREATOR}/gdbdebugger/disassemblerwindow.h \
+ $${QTCREATOR}/gdbdebugger/gdbdebuggerconstants.h \
+ $${QTCREATOR}/gdbdebugger/gdbdebugger.h \
+ $${QTCREATOR}/gdbdebugger/gdbmi.h \
+ $${QTCREATOR}/gdbdebugger/imports.h \
+ $${QTCREATOR}/gdbdebugger/moduleshandler.h \
+ $${QTCREATOR}/gdbdebugger/moduleswindow.h \
+ $${QTCREATOR}/gdbdebugger/registerhandler.h \
+ $${QTCREATOR}/gdbdebugger/registerwindow.h \
+ $${QTCREATOR}/gdbdebugger/gdboutputwindow.h \
+ $${QTCREATOR}/gdbdebugger/procinterrupt.h \
+ $${QTCREATOR}/gdbdebugger/stackhandler.h \
+ $${QTCREATOR}/gdbdebugger/stackwindow.h \
+ $${QTCREATOR}/gdbdebugger/startexternaldialog.h \
+ $${QTCREATOR}/gdbdebugger/threadswindow.h \
+ $${QTCREATOR}/gdbdebugger/watchhandler.h \
+ $${QTCREATOR}/gdbdebugger/watchwindow.h \
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ $${QTCREATOR}/gdbdebugger/attachexternaldialog.cpp \
+ $${QTCREATOR}/gdbdebugger/breakhandler.cpp \
+ $${QTCREATOR}/gdbdebugger/breakwindow.cpp \
+ $${QTCREATOR}/gdbdebugger/disassemblerhandler.cpp \
+ $${QTCREATOR}/gdbdebugger/disassemblerwindow.cpp \
+ $${QTCREATOR}/gdbdebugger/gdbdebugger.cpp \
+ $${QTCREATOR}/gdbdebugger/gdbmi.cpp \
+ $${QTCREATOR}/gdbdebugger/moduleshandler.cpp \
+ $${QTCREATOR}/gdbdebugger/moduleswindow.cpp \
+ $${QTCREATOR}/gdbdebugger/registerhandler.cpp \
+ $${QTCREATOR}/gdbdebugger/registerwindow.cpp \
+ $${QTCREATOR}/gdbdebugger/gdboutputwindow.cpp \
+ $${QTCREATOR}/gdbdebugger/procinterrupt.cpp \
+ $${QTCREATOR}/gdbdebugger/stackhandler.cpp \
+ $${QTCREATOR}/gdbdebugger/stackwindow.cpp \
+ $${QTCREATOR}/gdbdebugger/startexternaldialog.cpp \
+ $${QTCREATOR}/gdbdebugger/threadswindow.cpp \
+ $${QTCREATOR}/gdbdebugger/watchhandler.cpp \
+ $${QTCREATOR}/gdbdebugger/watchwindow.cpp
+
+SOURCES *= $${QTCREATOR}/../../bin/gdbmacros/gdbmacros.cpp
+
+FORMS += \
+ $${QTCREATOR}/gdbdebugger/attachexternaldialog.ui \
+ $${QTCREATOR}/gdbdebugger/gdboptionpage.ui \
+ $${QTCREATOR}/gdbdebugger/generaloptionpage.ui \
+ $${QTCREATOR}/gdbdebugger/debugmode.ui \
+ $${QTCREATOR}/gdbdebugger/startexternaldialog.ui
+
+RESOURCES += \
+ $${QTCREATOR}/gdbdebugger/gdbdebugger.qrc
+
+FORMS += \
+ $${QTCREATOR}/gdbdebugger/breakbyfunction.ui
+
+# The following chooses between a "really lean" build and a version
+# using the BaseTextEditor
+
+true {
+
+DEFINES += USE_BASETEXTEDITOR
+DEFINES += TEXTEDITOR_STANDALONE
+
+INCLUDEPATH += $${QTCREATOR}
+INCLUDEPATH += $${QTCREATOR}/texteditor
+INCLUDEPATH += $${QTCREATOR}/../libs
+
+HEADERS += \
+ $${QTCREATOR}/texteditor/basetextdocument.h \
+ $${QTCREATOR}/texteditor/basetexteditor.h \
+ $${QTCREATOR}/texteditor/storagesettings.h \
+ $${QTCREATOR}/texteditor/itexteditable.h \
+ $${QTCREATOR}/texteditor/itexteditor.h \
+ $${QTCREATOR}/texteditor/tabsettings.h \
+ $${QTCREATOR}/texteditor/displaysettings.h \
+ $${QTCREATOR}/coreplugin/icontext.h \
+ $${QTCREATOR}/coreplugin/ifile.h \
+ $${QTCREATOR}/coreplugin/editormanager/ieditor.h \
+ $${QTCREATOR}/../libs/utils/linecolumnlabel.h \
+
+SOURCES += \
+ #$${QTCREATOR}/texteditor/basetextmark.cpp \
+ $${QTCREATOR}/texteditor/basetextdocument.cpp \
+ $${QTCREATOR}/texteditor/basetexteditor.cpp \
+ $${QTCREATOR}/texteditor/storagesettings.cpp \
+ $${QTCREATOR}/texteditor/tabsettings.cpp \
+ $${QTCREATOR}/texteditor/displaysettings.cpp \
+ $${QTCREATOR}/../libs/utils/linecolumnlabel.cpp \
+}
+
+
+
+unix {
+ OBJECTS_DIR = .tmp/
+ MOC_DIR = .tmp/
+ RCC_DIR = .tmp/
+ UI_DIR = .tmp/
+}
+
diff --git a/src/tools/qtcreatorwidgets/README.txt b/src/tools/qtcreatorwidgets/README.txt
new file mode 100644
index 0000000000..6ccf8f5699
--- /dev/null
+++ b/src/tools/qtcreatorwidgets/README.txt
@@ -0,0 +1,8 @@
+A Designer custom widget collection containing the Qt Creator
+widgets from the utils library.
+
+Installs to Designer and has rpath pointing to the QtCreator library
+directory, so, it should work on Linux.
+
+On Windows, it might require copying the utils library around or setup
+some path pointing to it.
diff --git a/src/tools/qtcreatorwidgets/customwidget.h b/src/tools/qtcreatorwidgets/customwidget.h
new file mode 100644
index 0000000000..23f22cf5a2
--- /dev/null
+++ b/src/tools/qtcreatorwidgets/customwidget.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CUSTOMWIDGET
+#define CUSTOMWIDGET
+
+#include <QDesignerCustomWidgetInterface>
+
+#include <QtCore/QString>
+#include <QtCore/QSize>
+#include <QtCore/QTextStream>
+#include <QtGui/QIcon>
+
+// Parametrizable Template for custom widgets.
+
+template <class Widget>
+class CustomWidget : public QDesignerCustomWidgetInterface
+{
+
+public:
+ explicit CustomWidget(const QString &includeFile,
+ bool isContainer,
+ const QString &group,
+ const QIcon &icon,
+ const QString &toolTip,
+ const QSize &size = QSize());
+
+ bool isContainer() const { return m_isContainer; }
+ bool isInitialized() const { return m_initialized; }
+ QIcon icon() const { return m_icon; }
+ QString domXml() const;
+ QString group() const { return m_group; }
+ QString includeFile() const { return m_includeFile; }
+ QString name() const;
+ QString toolTip() const { return m_toolTip; }
+ QString whatsThis() const { return m_toolTip; }
+ QWidget *createWidget(QWidget *parent);
+ void initialize(QDesignerFormEditorInterface *core);
+
+private:
+ QString displayName() const;
+ QString geometryProperty() const;
+
+ const QString m_includeFile;
+ const bool m_isContainer;
+ const QString m_group;
+ const QIcon m_icon;
+ const QString m_toolTip;
+ const QSize m_size;
+
+ bool m_initialized;
+};
+
+
+template <class Widget>
+ CustomWidget<Widget>::CustomWidget(const QString &includeFile,
+ bool isContainer,
+ const QString &group,
+ const QIcon &icon,
+ const QString &toolTip,
+ const QSize &size) :
+ m_includeFile(includeFile),
+ m_isContainer(isContainer),
+ m_group(group),
+ m_icon(icon),
+ m_toolTip(toolTip),
+ m_size(size),
+ m_initialized(false)
+{
+}
+
+// Determine the name to be displayed in the widget box: Strip
+// namespaces.
+template <class Widget>
+ QString CustomWidget<Widget>::displayName() const
+{
+ QString rc = name();
+ const int index = rc.lastIndexOf(QLatin1Char(':'));
+ if (index != -1)
+ rc.remove(0, index + 1);
+ return rc;
+}
+
+template <class Widget>
+ QString CustomWidget<Widget>::geometryProperty() const
+{
+ QString rc;
+ if (m_size.isEmpty())
+ return rc;
+ QTextStream(&rc) << "<property name=\"geometry\"><rect><x>0</x><y>0</y><width>"
+ << m_size.width() << "</width><height>" << m_size.height()
+ << "</height></rect></property>";
+ return rc;
+}
+
+template <class Widget>
+ QString CustomWidget<Widget>::domXml() const
+{
+ const QString className = name();
+ QString rc;
+ // Name: 'QClass' -> 'class'
+ QString name = className;
+ if (name.startsWith(QLatin1Char('Q')))
+ name.remove(0, 1);
+ name[0] = name.at(0).toLower();
+ // Format
+ QTextStream str(&rc);
+ str << "<ui displayname=\"" << displayName()
+ << "\" language=\"c++\"><widget class=\"" << className << "\" name=\""
+ << name << "\">" << geometryProperty() << "</widget></ui>";
+ return rc;
+}
+
+template <class Widget>
+ QString CustomWidget<Widget>::name() const
+{
+ return QLatin1String(Widget::staticMetaObject.className());
+}
+
+template <class Widget>
+ QWidget *CustomWidget<Widget>::createWidget(QWidget *parent)
+{
+ return new Widget(parent);
+}
+
+template <class Widget>
+ void CustomWidget<Widget>::initialize(QDesignerFormEditorInterface *)
+{
+ if (!m_initialized) {
+ m_initialized = true;
+ }
+}
+
+#endif // CUSTOMWIDGET
diff --git a/src/tools/qtcreatorwidgets/customwidgets.cpp b/src/tools/qtcreatorwidgets/customwidgets.cpp
new file mode 100644
index 0000000000..80a6d31e5d
--- /dev/null
+++ b/src/tools/qtcreatorwidgets/customwidgets.cpp
@@ -0,0 +1,171 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "customwidgets.h"
+
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+static const char *groupC = "QtCreator";
+
+NewClassCustomWidget::NewClassCustomWidget(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::NewClassWidget>
+ (QLatin1String("<utils/newclasswidget.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Widget to enter classes and source files"))
+{
+}
+
+ClassNameValidatingLineEdit_CW::ClassNameValidatingLineEdit_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::ClassNameValidatingLineEdit>
+ (QLatin1String("<utils/classnamevalidatinglineedit.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Line Edit that validates a class name"))
+{
+}
+
+FileNameValidatingLineEdit_CW::FileNameValidatingLineEdit_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::FileNameValidatingLineEdit>
+ (QLatin1String("<utils/filenamevalidatinglineedit.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Line Edit that validates a file name"))
+{
+}
+
+ProjectNameValidatingLineEdit_CW::ProjectNameValidatingLineEdit_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::ProjectNameValidatingLineEdit>
+ (QLatin1String("<utils/projectnamevalidatinglineedit.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Line Edit that validates a project name"))
+{
+}
+
+LineColumnLabel_CW::LineColumnLabel_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::LineColumnLabel>
+ (QLatin1String("<utils/linecolumnlabel.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Label suited for displaying line numbers with a fixed with depending on the font size"),
+ QSize(100, 20))
+{
+}
+
+PathChooser_CW::PathChooser_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::PathChooser>
+ (QLatin1String("<utils/pathchooser.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Input widget for paths with a browse button"))
+{
+}
+
+FancyLineEdit_CW::FancyLineEdit_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::FancyLineEdit>
+ (QLatin1String("<utils/fancylineedit.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("A Line edit with a clickable menu pixmap"))
+{
+}
+
+QtColorButton_CW::QtColorButton_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::QtColorButton>
+ (QLatin1String("<utils/qtcolorbutton.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("A color button that spawns a QColorDialog on click"))
+{
+}
+
+QWidget *FancyLineEdit_CW::createWidget(QWidget *parent)
+{
+ Core::Utils::FancyLineEdit *fle = new Core::Utils::FancyLineEdit(parent);
+ QMenu *menu = new QMenu(fle);
+ menu->addAction("Test");
+ fle->setMenu(menu);
+ return fle;
+}
+
+SubmitEditorWidget_CW::SubmitEditorWidget_CW(QObject *parent) :
+ QObject(parent),
+ CustomWidget<Core::Utils::SubmitEditorWidget>
+ (QLatin1String("<utils/submiteditorwidget.h>"),
+ false,
+ QLatin1String(groupC),
+ QIcon(),
+ tr("Submit editor showing message and file list"))
+{
+}
+
+// -------------- WidgetCollection
+WidgetCollection::WidgetCollection(QObject *parent) :
+ QObject(parent)
+{
+
+ m_plugins.push_back(new NewClassCustomWidget(this));
+ m_plugins.push_back(new ClassNameValidatingLineEdit_CW(this));
+ m_plugins.push_back(new FileNameValidatingLineEdit_CW(this));
+ m_plugins.push_back(new ProjectNameValidatingLineEdit_CW(this));
+ m_plugins.push_back(new LineColumnLabel_CW(this));
+ m_plugins.push_back(new PathChooser_CW(this));
+ m_plugins.push_back(new FancyLineEdit_CW(this));
+ m_plugins.push_back(new QtColorButton_CW(this));
+ m_plugins.push_back(new SubmitEditorWidget_CW(this));
+}
+
+QList<QDesignerCustomWidgetInterface*> WidgetCollection::customWidgets() const
+{
+ return m_plugins;
+}
+
+Q_EXPORT_PLUGIN(WidgetCollection)
diff --git a/src/tools/qtcreatorwidgets/customwidgets.h b/src/tools/qtcreatorwidgets/customwidgets.h
new file mode 100644
index 0000000000..fbf638bded
--- /dev/null
+++ b/src/tools/qtcreatorwidgets/customwidgets.h
@@ -0,0 +1,162 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef _CUSTOMWIDGETS_
+#define _CUSTOMWIDGETS_
+
+#include "customwidget.h"
+
+#include <utils/newclasswidget.h>
+#include <utils/classnamevalidatinglineedit.h>
+#include <utils/filenamevalidatinglineedit.h>
+#include <utils/linecolumnlabel.h>
+#include <utils/pathchooser.h>
+#include <utils/projectnamevalidatinglineedit.h>
+#include <utils/fancylineedit.h>
+#include <utils/qtcolorbutton.h>
+#include <utils/submiteditorwidget.h>
+
+#include <QtDesigner/QDesignerCustomWidgetCollectionInterface>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QList>
+
+// Custom Widgets
+
+class NewClassCustomWidget:
+ public QObject,
+ public CustomWidget<Core::Utils::NewClassWidget>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit NewClassCustomWidget(QObject *parent = 0);
+};
+
+class ClassNameValidatingLineEdit_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::ClassNameValidatingLineEdit>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit ClassNameValidatingLineEdit_CW(QObject *parent = 0);
+};
+
+class FileNameValidatingLineEdit_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::FileNameValidatingLineEdit>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit FileNameValidatingLineEdit_CW(QObject *parent = 0);
+};
+
+class ProjectNameValidatingLineEdit_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::ProjectNameValidatingLineEdit>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit ProjectNameValidatingLineEdit_CW(QObject *parent = 0);
+};
+
+class LineColumnLabel_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::LineColumnLabel>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit LineColumnLabel_CW(QObject *parent = 0);
+};
+
+class PathChooser_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::PathChooser>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit PathChooser_CW(QObject *parent = 0);
+};
+
+class FancyLineEdit_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::FancyLineEdit>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit FancyLineEdit_CW(QObject *parent = 0);
+
+ virtual QWidget *createWidget(QWidget *parent);
+};
+
+class QtColorButton_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::QtColorButton>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit QtColorButton_CW(QObject *parent = 0);
+};
+
+class SubmitEditorWidget_CW:
+ public QObject,
+ public CustomWidget<Core::Utils::SubmitEditorWidget>
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+public:
+ explicit SubmitEditorWidget_CW(QObject *parent = 0);
+};
+
+// Collection
+
+class WidgetCollection: public QObject, public QDesignerCustomWidgetCollectionInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
+public:
+ explicit WidgetCollection(QObject *parent = 0);
+
+ virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
+
+private:
+ QList<QDesignerCustomWidgetInterface*> m_plugins;
+};
+
+#endif // _CUSTOMWIDGETS_
diff --git a/src/tools/qtcreatorwidgets/qtcreatorwidgets.pro b/src/tools/qtcreatorwidgets/qtcreatorwidgets.pro
new file mode 100644
index 0000000000..6923e09837
--- /dev/null
+++ b/src/tools/qtcreatorwidgets/qtcreatorwidgets.pro
@@ -0,0 +1,25 @@
+CONFIG += designer plugin debug_and_release
+TARGET = $$qtLibraryTarget(qtcreatorwidgets)
+TEMPLATE = lib
+
+HEADERS = customwidgets.h \
+ customwidget.h
+
+SOURCES = customwidgets.cpp
+
+# Link against the qtcreator utils lib
+
+unix {
+ # form abs path to qtcreator lib dir
+ GH_LIB=$$dirname(PWD)
+ GH_LIB=$$dirname(GH_LIB)
+ GH_LIB=$$dirname(GH_LIB)
+ GH_LIB=$$GH_LIB/lib
+ QMAKE_RPATHDIR *= $$GH_LIB
+}
+
+INCLUDEPATH += ../../../src/libs
+LIBS += -L../../../lib -lUtils
+
+DESTDIR= $$[QT_INSTALL_PLUGINS]/designer
+
diff --git a/src/tools/texteditor/main.cpp b/src/tools/texteditor/main.cpp
new file mode 100644
index 0000000000..101a046cf2
--- /dev/null
+++ b/src/tools/texteditor/main.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow mw;
+ mw.show();
+ QStringList args = app.arguments();
+ args.removeFirst(); // program name..
+ mw.loadFiles(args);
+ return app.exec();
+}
+
diff --git a/src/tools/texteditor/mainwindow.cpp b/src/tools/texteditor/mainwindow.cpp
new file mode 100644
index 0000000000..087bdc92ce
--- /dev/null
+++ b/src/tools/texteditor/mainwindow.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "mainwindow.h"
+
+#include "texteditor/basetexteditor.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+
+#include <QtGui/QAction>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMenu>
+#include <QtGui/QMenuBar>
+#include <QtGui/QMessageBox>
+#include <QtGui/QStatusBar>
+#include <QtGui/QTabWidget>
+#include <QtGui/QTextBlock>
+#include <QtGui/QToolBar>
+
+
+class MyEditor;
+
+class MyEditable : public TextEditor::BaseTextEditorEditable
+{
+public:
+ MyEditable(MyEditor *editor);
+ ~MyEditable() {}
+
+ // Core::IContext
+ const QList<int>& context() const { return m_context; }
+ // Core::IEditor
+ const char* kind() const { return "MYEDITOR"; }
+ bool duplicateSupported() const { return false; }
+ Core::IEditor* duplicate(QWidget*) { return 0; }
+
+ MyEditor *m_editor;
+ QList<int> m_context;
+};
+
+
+class MyEditor : public TextEditor::BaseTextEditor
+{
+public:
+ MyEditor(QWidget *parent)
+ : TextEditor::BaseTextEditor(parent, 0)
+ {}
+
+ TextEditor::BaseTextEditorEditable* createEditableInterface()
+ {
+ return new MyEditable(this);
+ }
+
+ void setPlainText(const QString &contents)
+ {
+ qDebug() << "Setting contents to:\n" << contents;
+ QPlainTextEdit::setPlainText(contents);
+ }
+};
+
+
+MyEditable::MyEditable(MyEditor *editor)
+ : TextEditor::BaseTextEditorEditable(editor), m_editor(editor)
+{}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// MainWindow
+//
+///////////////////////////////////////////////////////////////////////////
+
+MainWindow::MainWindow()
+{
+ //
+ // Source code view
+ //
+ m_textViewers = new QTabWidget(this);
+ m_textViewers->setObjectName("Editors");
+ m_textViewers->setElideMode(Qt::ElideLeft);
+ setCentralWidget(m_textViewers);
+ setGeometry(QRect(0, 0, 800, 600));
+
+
+ m_fileOpenAction = new QAction("Open", this);
+ m_quitAction = new QAction("Quit", this);
+
+ //
+ // Menubar
+ //
+ QMenu *fileMenu = new QMenu(menuBar());
+ fileMenu->setTitle(tr("File"));
+ fileMenu->addAction(m_fileOpenAction);
+ fileMenu->addSeparator();
+ fileMenu->addAction(m_quitAction);
+ menuBar()->addMenu(fileMenu);
+
+ //
+ // Toolbar
+ //
+ QToolBar *toolbar = new QToolBar(this);
+ toolbar->setObjectName("ToolBar");
+ toolbar->addAction(m_fileOpenAction);
+ toolbar->addAction(m_quitAction);
+ addToolBar(Qt::TopToolBarArea, toolbar);
+
+ //
+ // Statusbar
+ //
+ QStatusBar *statusbar = new QStatusBar(this);
+ statusbar->setObjectName("StatusBar");
+ setStatusBar(statusbar);
+
+ show();
+ restoreState(settings().value("MainWindow/State").toByteArray());
+ setGeometry(settings().value("MainWindow/Geometry").toRect());
+
+ //
+ // Connections
+ //
+ connect(m_fileOpenAction, SIGNAL(triggered()),
+ this, SLOT(fileOpen()));
+ connect(m_quitAction, SIGNAL(triggered()),
+ this, SLOT(close()));
+}
+
+MainWindow::~MainWindow()
+{
+ settings().setValue("MainWindow/State", saveState());
+ settings().setValue("MainWindow/Geometry", geometry());
+ settings().sync();
+}
+
+QSettings &MainWindow::settings()
+{
+ static QSettings s("Nokia", "TextEditor");
+ return s;
+}
+
+void MainWindow::loadFile(const QString &fileName)
+{
+ findOrCreateTextViewer(fileName);
+}
+
+void MainWindow::loadFiles(const QStringList &fileNames)
+{
+ foreach (const QString &fileName, fileNames)
+ loadFile(fileName);
+}
+
+void MainWindow::fileOpen()
+{
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Open Executable File"),
+ settings().value("FileOpen/LastDir").toString()
+ // filterQString & filter = QString(),
+ //QString * selectedFilter = 0, Options options = 0
+ );
+ settings().setValue("FileOpen/LastDir", QFileInfo(fileName).dir().dirName());
+ if (fileName.isEmpty())
+ return;
+ loadFile(fileName);
+}
+
+
+Editor *MainWindow::findOrCreateTextViewer(const QString &fileName)
+{
+ Editor *textViewer = m_textViewerFromName.value(fileName);
+ if (textViewer)
+ return textViewer;
+
+ QFile file(fileName);
+ file.open(QIODevice::ReadOnly);
+ QString contents = file.readAll();
+
+ textViewer = new MyEditor(this);
+ textViewer->setPlainText(contents);
+ m_textViewerFromName[fileName] = textViewer;
+ m_textViewers->addTab(textViewer, fileName);
+ return textViewer;
+}
+
diff --git a/src/tools/texteditor/mainwindow.h b/src/tools/texteditor/mainwindow.h
new file mode 100644
index 0000000000..cf9983d5b4
--- /dev/null
+++ b/src/tools/texteditor/mainwindow.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITOR_MAINWINDOW_H
+#define TEXTEDITOR_MAINWINDOW_H
+
+#include "itexteditor.h"
+
+#include <QtCore/QHash>
+
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+
+QT_BEGIN_NAMESPACE
+class QTabWidget;
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor { class BaseTextEditor; }
+typedef TextEditor::BaseTextEditor Editor;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow();
+ ~MainWindow();
+
+ void loadFile(const QString &fileName);
+ void loadFiles(const QStringList &fileNames);
+
+private slots:
+ void fileOpen();
+
+private:
+ QTabWidget *m_textViewers;
+ QHash<QString, Editor *> m_textViewerFromName;
+ Editor *findOrCreateTextViewer(const QString &fileName);
+ Editor *currentTextViewer();
+
+ QSettings &settings();
+ QAction * m_fileOpenAction;
+ QAction * m_quitAction;
+};
+
+#endif // TEXTEDITOR_MAINWINDOW_H
diff --git a/src/tools/texteditor/texteditor.pro b/src/tools/texteditor/texteditor.pro
new file mode 100644
index 0000000000..fd4db87826
--- /dev/null
+++ b/src/tools/texteditor/texteditor.pro
@@ -0,0 +1,46 @@
+
+QTCREATOR = ../../plugins/
+
+TARGET = ../../../bin/texteditor
+
+QT += gui
+
+CONFIG -= release
+CONFIG += debug
+
+DEFINES += TEXTEDITOR_STANDALONE
+
+INCLUDEPATH += $${QTCREATOR}
+INCLUDEPATH += $${QTCREATOR}/texteditor
+
+HEADERS += \
+ mainwindow.h \
+ $${QTCREATOR}/texteditor/basetextdocument.h \
+ $${QTCREATOR}/texteditor/basetexteditor.h \
+ $${QTCREATOR}/texteditor/storagesettings.h \
+ $${QTCREATOR}/texteditor/itexteditable.h \
+ $${QTCREATOR}/texteditor/itexteditor.h \
+ $${QTCREATOR}/texteditor/tabsettings.h \
+ $${QTCREATOR}/texteditor/displaysettings.h \
+ $${QTCREATOR}/coreplugin/icontext.h \
+ $${QTCREATOR}/coreplugin/ifile.h \
+ $${QTCREATOR}/coreplugin/editormanager/ieditor.h \
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ $${QTCREATOR}/texteditor/basetextdocument.cpp \
+ $${QTCREATOR}/texteditor/basetexteditor.cpp \
+ $${QTCREATOR}/texteditor/storagesettings.cpp \
+ $${QTCREATOR}/texteditor/tabsettings.cpp \
+ $${QTCREATOR}/texteditor/displaysettings.cpp \
+
+#RESOURCES += \
+# $${QTCREATOR}/gdbdebugger/gdbdebugger.qrc
+
+unix {
+ OBJECTS_DIR = .tmp/
+ MOC_DIR = .tmp/
+ RCC_DIR = .tmp/
+ UI_DIR = .tmp/
+}
diff --git a/tests/auto/extensionsystem/extensionsystem.pro b/tests/auto/extensionsystem/extensionsystem.pro
new file mode 100644
index 0000000000..bbd0355ff1
--- /dev/null
+++ b/tests/auto/extensionsystem/extensionsystem.pro
@@ -0,0 +1,11 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Mon Jul 9 17:37:18 2007
+######################################################################
+load(qttest_p4)
+
+# Input
+SOURCES += tst_composite.cpp \
+ ../../../src/libs/extensionsystem/composite.cpp
+
+HEADERS += ../../../src/libs/extensionsystem/composite.h \
+ ../../../src/libs/extensionsystem/interface.h
diff --git a/tests/auto/extensionsystem/tst_composite.cpp b/tests/auto/extensionsystem/tst_composite.cpp
new file mode 100644
index 0000000000..0673c789bf
--- /dev/null
+++ b/tests/auto/extensionsystem/tst_composite.cpp
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtTest/QtTest>
+#include "../../../src/libs/extensionsystem/composite.h"
+
+using namespace ExtensionSystem;
+
+class tst_Composite : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void init();
+ void cleanup();
+ void addInterface();
+ void removeInterface();
+ void constructor();
+
+private:
+ Composite *composite;
+ QObject *component1;
+ QObject *component2;
+};
+
+class Interface1 : public Interface
+{
+ Q_OBJECT
+};
+
+class Interface2 : public QObject
+{
+ Q_OBJECT
+};
+
+void tst_Composite::init()
+{
+ composite = new Composite;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ composite->addInterface(component1);
+}
+
+void tst_Composite::cleanup()
+{
+ delete component1;
+ delete component2;
+ delete composite;
+}
+
+void tst_Composite::addInterface()
+{
+ QCOMPARE(interface_cast<Interface2>(composite), (void*)0);
+ composite->addInterface(component2);
+ QCOMPARE(interface_cast<Interface2>(composite), component2);
+}
+
+void tst_Composite::removeInterface()
+{
+ QCOMPARE(interface_cast<Interface1>(composite), component1);
+ composite->removeInterface(component1);
+ QCOMPARE(interface_cast<Interface1>(composite), (void*)0);
+}
+
+void tst_Composite::constructor()
+{
+ Composite multiple(QSet<QObject*>() << component1 << component2);
+ QCOMPARE(interface_cast<Interface1>(&multiple), component1);
+ QCOMPARE(interface_cast<Interface2>(&multiple), component2);
+}
+
+QTEST_MAIN(tst_Composite)
+#include "tst_composite.moc"
+
diff --git a/tests/auto/profilereader/data/includefiles/pri.cpp b/tests/auto/profilereader/data/includefiles/pri.cpp
new file mode 100644
index 0000000000..5ef9c92fae
--- /dev/null
+++ b/tests/auto/profilereader/data/includefiles/pri.cpp
@@ -0,0 +1,32 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
diff --git a/tests/auto/profilereader/data/includefiles/pro.cpp b/tests/auto/profilereader/data/includefiles/pro.cpp
new file mode 100644
index 0000000000..5ef9c92fae
--- /dev/null
+++ b/tests/auto/profilereader/data/includefiles/pro.cpp
@@ -0,0 +1,32 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
diff --git a/tests/auto/profilereader/data/includefiles/test.pri b/tests/auto/profilereader/data/includefiles/test.pri
new file mode 100644
index 0000000000..6a25f2a87a
--- /dev/null
+++ b/tests/auto/profilereader/data/includefiles/test.pri
@@ -0,0 +1 @@
+SOURCES += pri.cpp
diff --git a/tests/auto/profilereader/data/includefiles/test.pro b/tests/auto/profilereader/data/includefiles/test.pro
new file mode 100644
index 0000000000..0c2209a7c3
--- /dev/null
+++ b/tests/auto/profilereader/data/includefiles/test.pro
@@ -0,0 +1,3 @@
+include(test.pri)
+
+SOURCES += pro.cpp
diff --git a/tests/auto/profilereader/main.cpp b/tests/auto/profilereader/main.cpp
new file mode 100644
index 0000000000..6ae9354cb6
--- /dev/null
+++ b/tests/auto/profilereader/main.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "profilereader.h"
+#include "profilecache.h"
+#include "proitems.h"
+
+#include <QtTest/QtTest>
+#include <QtCore/QSet>
+
+using Qt4ProjectManager::Internal::ProFileReader;
+using Qt4ProjectManager::Internal::ProFileCache;
+
+
+class tst_ProFileReader : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void readProFile();
+ void includeFiles();
+};
+
+void tst_ProFileReader::readProFile()
+{
+ ProFileCache cache;
+ ProFileReader reader(&cache);
+ QCOMPARE(reader.readProFile("nonexistant"), false);
+ QCOMPARE(reader.readProFile("data/includefiles/test.pro"), true);
+}
+
+void tst_ProFileReader::includeFiles()
+{
+ ProFileCache cache;
+ ProFileReader reader(&cache);
+ QCOMPARE(reader.readProFile("data/includefiles/test.pro"), true);
+ QCOMPARE(reader.includeFiles().size(), 2);
+}
+
+QTEST_MAIN(tst_ProFileReader)
+#include "main.moc"
diff --git a/tests/auto/profilereader/profilecache.h b/tests/auto/profilereader/profilecache.h
new file mode 100644
index 0000000000..adea20d894
--- /dev/null
+++ b/tests/auto/profilereader/profilecache.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PROFILECACHE_H
+#define PROFILECACHE_H
+
+#include "proitems.h"
+#include <QString>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProFileCache {
+public:
+ ProFile *proFile(const QString &arg)
+ { return new ProFile(arg); }
+};
+
+}
+}
+
+#endif // PROFILECACHE_H
diff --git a/tests/auto/profilereader/profilereader.pro b/tests/auto/profilereader/profilereader.pro
new file mode 100644
index 0000000000..b80ce8e495
--- /dev/null
+++ b/tests/auto/profilereader/profilereader.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+
+SOURCES += \
+ proitems.cpp \
+ profileevaluator.cpp \
+ profilereader.cpp \
+ main.cpp
+
+HEADERS += \
+ profileevaluator.h \
+ proparserutils.h \
+ proitems.h \
+ abstractproitemvisitor.h \
+ profilereader.h \
+ profilecache.h \
+ qtversionmanager.h
diff --git a/tests/auto/profilereader/qtversionmanager.h b/tests/auto/profilereader/qtversionmanager.h
new file mode 100644
index 0000000000..0f495c6c8d
--- /dev/null
+++ b/tests/auto/profilereader/qtversionmanager.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QTVERSIONMANAGER_H
+#define QTVERSIONMANAGER_H
+
+#include <QtCore/QString>
+
+class QtVersion {
+public:
+ QString path() { return QString(); }
+ QString sourcePath() { return QString(); }
+ QHash<QString,QString> versionInfo() { return QHash<QString,QString>();}
+};
+
+#endif // QTVERSIONMANAGER_H
diff --git a/tests/auto/profilereader/sync b/tests/auto/profilereader/sync
new file mode 100755
index 0000000000..f0950addcc
--- /dev/null
+++ b/tests/auto/profilereader/sync
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Cwd;
+use File::Copy;
+use File::Basename;
+use IO::File;
+use File::Spec;
+use File::Path;
+
+# --------------------------------
+sub copyFiles
+{
+ my ($srcDir, $destDir, @files) = @_;
+ unless (-d $destDir) {
+ mkpath $destDir;
+ }
+ die ('No directory ' . $srcDir) unless -d $srcDir;
+ die ('No directory ' . $destDir) unless -d $destDir;
+ foreach (@files) {
+ my $src = File::Spec->catfile($srcDir, $_);
+ print 'syncing ', $src, "...\n";
+ my $dest = File::Spec->catfile($destDir, $_);
+ if (-f $dest) {
+ unlink($dest) or die ('Unable to delete existing ' . $dest . ' :' . $!);
+ }
+ copy($src, $dest) || die ($0 . ': Unable to copy ' . $src . ': ' . $! . "\n");
+ chmod 0644, $destDir . $_;
+ }
+}
+
+# -----------------------------------------
+sub showUsage
+{
+ print "$0 usage:\n";
+ print " -qtdir <dir> Set directory for Qt (default: use qmake to figure out)\n";
+ print " -help This help\n";
+ exit 0;
+}
+
+my $currentDir = getcwd;
+my @files;
+
+my $qtSrcTree = '';
+
+# Parse arguments
+while ( @ARGV ) {
+ my $var = 0;
+ my $val = 0;
+
+ #parse
+ my $arg = shift @ARGV;
+ if ("$arg" eq "-h" || "$arg" eq "-help" || "$arg" eq "--help" || "$arg" eq "?" || "$arg" eq "/?" || "$arg" eq "-?") {
+ showUsage();
+ exit(0);
+ } elsif("$arg" eq "-qtdir") {
+ $qtSrcTree = shift @ARGV;
+ } else {
+ print "Unknown option: $arg\n";
+ showUsage();
+ exit(1);
+ }
+}
+
+# If QTDIR is not set, use qmake to figure it out
+if (!$qtSrcTree) {
+ my $qmakeInfo = `qmake -v` or die "Couldn't run qmake!";
+ chomp($qmakeInfo);
+ $qmakeInfo =~ m/Using Qt version .* in (.*)lib$/;
+ $qtSrcTree = $1;
+ # read Qt source directory from .qmake.cache
+ my $fh = IO::File->new();
+ $fh->open($qtSrcTree . '.qmake.cache');
+ while (defined (my $line = $fh->getline())) {
+ # parse line
+ # QT_SOURCE_TREE = $$quote(/home/kkoehne/dev/qt)
+ if ($line =~ /^\s*QT_SOURCE_TREE\s*=/) {
+ $qtSrcTree = $line;
+ $qtSrcTree =~ s/^QT_SOURCE_TREE\s*=\s*(\$\$quote\()?//g;
+ $qtSrcTree =~ s/\)?\n//g;
+ }
+ }
+ print "Detected qt source directory: " . $qtSrcTree . "\n";
+ $fh->close();
+}
+$qtSrcTree =~ s/\\/\//g;
+
+
+# if the sources can't be found, check for shadow builds.
+my $preprocessor_h = File::Spec->catfile($qtSrcTree, 'src', 'tools', 'moc', 'preprocessor.h');
+
+my $qtsrcdirEnv = $ENV{'QTSRCDIR'};
+if (defined $qtsrcdirEnv) {
+ if ((! -e $preprocessor_h) && ($qtsrcdirEnv ne '')) {
+ $qtSrcTree = $qtsrcdirEnv;
+ }
+}
+
+# copy files for Qt4ProjectManager
+
+
+@files = ( 'proitems.h',
+ 'abstractproitemvisitor.h',
+ 'proparserutils.h',
+ 'profileevaluator.h',
+
+ 'proitems.cpp',
+ 'profileevaluator.cpp' );
+
+copyFiles(File::Spec->catfile($qtSrcTree, 'tools', 'linguist', 'shared'), $currentDir,@files);
+
+@files = ( 'profilereader.h',
+ 'profilereader.cpp');
+copyFiles(File::Spec->catfile('..', '..', '..', 'src', 'plugins', 'qt4projectmanager'), $currentDir, @files)
diff --git a/tests/manual/cppmodelmanager/codemodel/binder.cpp b/tests/manual/cppmodelmanager/codemodel/binder.cpp
new file mode 100644
index 0000000000..6f71a7b3c4
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/binder.cpp
@@ -0,0 +1,866 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+Copyright (C) 2005 Trolltech AS
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#include "binder.h"
+#include "lexer.h"
+#include "control.h"
+#include "symbol.h"
+#include "codemodel_finder.h"
+#include "class_compiler.h"
+#include "compiler_utils.h"
+#include "tokens.h"
+#include "dumptree.h"
+
+#include <iostream>
+
+#include <qdebug.h>
+
+Binder::Binder(CppCodeModel *__model, LocationManager &__location, Control *__control)
+: _M_model(__model),
+_M_location(__location),
+_M_token_stream(&_M_location.token_stream),
+_M_control(__control),
+_M_current_function_type(CodeModel::Normal),
+type_cc(this),
+name_cc(this),
+decl_cc(this)
+{
+ _M_current_file = 0;
+ _M_current_namespace = 0;
+ _M_current_class = 0;
+ _M_current_function = 0;
+ _M_current_enum = 0;
+}
+
+Binder::~Binder()
+{
+}
+
+void Binder::run(AST *node, const QString &filename)
+{
+ _M_current_access = CodeModel::Public;
+ if (_M_current_file = model()->fileItem(filename))
+ visit(node);
+}
+
+ScopeModelItem *Binder::findScope(const QString &name) const
+{
+ return _M_known_scopes.value(name, 0);
+}
+
+ScopeModelItem *Binder::resolveScope(NameAST *id, ScopeModelItem *scope)
+{
+ Q_ASSERT(scope != 0);
+
+ bool foundScope;
+ CodeModelFinder finder(model(), this);
+ QString symbolScopeName = finder.resolveScope(id, scope, &foundScope);
+ if (!foundScope) {
+ name_cc.run(id);
+ std::cerr << "** WARNING scope not found for symbol:"
+ << qPrintable(name_cc.qualifiedName()) << std::endl;
+ return 0;
+ }
+
+ if (symbolScopeName.isEmpty())
+ return scope;
+
+ ScopeModelItem *symbolScope = findScope(symbolScopeName);
+
+ qDebug() << "Resolving: " << symbolScopeName;
+ qDebug() << " Current File: " << scope->file()->name();
+
+ if (symbolScope)
+ qDebug() << " Found in file: " << symbolScope->file()->name();
+
+ if (!symbolScope || symbolScope->file() != scope->file()) {
+ CppFileModelItem *file = model_cast<CppFileModelItem *>(scope->file());
+ symbolScope = file->findExternalScope(symbolScopeName);
+ qDebug() << " Create as external reference";
+ if (!symbolScope) {
+ symbolScope = new ScopeModelItem(_M_model);
+ symbolScope->setName(symbolScopeName);
+ file->addExternalScope(symbolScope);
+ }
+ }
+
+ return symbolScope;
+}
+
+ScopeModelItem *Binder::currentScope()
+{
+ if (_M_current_class)
+ return _M_current_class;
+ else if (_M_current_namespace)
+ return _M_current_namespace;
+
+ return _M_current_file;
+}
+
+TemplateParameterList Binder::changeTemplateParameters(TemplateParameterList templateParameters)
+{
+ TemplateParameterList old = _M_current_template_parameters;
+ _M_current_template_parameters = templateParameters;
+ return old;
+}
+
+CodeModel::FunctionType Binder::changeCurrentFunctionType(CodeModel::FunctionType functionType)
+{
+ CodeModel::FunctionType old = _M_current_function_type;
+ _M_current_function_type = functionType;
+ return old;
+}
+
+CodeModel::AccessPolicy Binder::changeCurrentAccess(CodeModel::AccessPolicy accessPolicy)
+{
+ CodeModel::AccessPolicy old = _M_current_access;
+ _M_current_access = accessPolicy;
+ return old;
+}
+
+NamespaceModelItem *Binder::changeCurrentNamespace(NamespaceModelItem *item)
+{
+ NamespaceModelItem *old = _M_current_namespace;
+ _M_current_namespace = item;
+ return old;
+}
+
+CppClassModelItem *Binder::changeCurrentClass(CppClassModelItem *item)
+{
+ CppClassModelItem *old = _M_current_class;
+ _M_current_class = item;
+ return old;
+}
+
+CppFunctionDefinitionModelItem *Binder::changeCurrentFunction(CppFunctionDefinitionModelItem *item)
+{
+ CppFunctionDefinitionModelItem *old = _M_current_function;
+ _M_current_function = item;
+ return old;
+}
+
+int Binder::decode_token(std::size_t index) const
+{
+ return _M_token_stream->kind(index);
+}
+
+CodeModel::AccessPolicy Binder::decode_access_policy(std::size_t index) const
+{
+ switch (decode_token(index))
+ {
+ case Token_class:
+ return CodeModel::Private;
+
+ case Token_struct:
+ case Token_union:
+ return CodeModel::Public;
+
+ default:
+ return CodeModel::Public;
+ }
+}
+
+CodeModel::ClassType Binder::decode_class_type(std::size_t index) const
+{
+ switch (decode_token(index))
+ {
+ case Token_class:
+ return CodeModel::Class;
+ case Token_struct:
+ return CodeModel::Struct;
+ case Token_union:
+ return CodeModel::Union;
+ default:
+ std::cerr << "** WARNING unrecognized class type" << std::endl;
+ }
+ return CodeModel::Class;
+}
+
+const NameSymbol *Binder::decode_symbol(std::size_t index) const
+{
+ return _M_token_stream->symbol(index);
+}
+
+void Binder::visitAccessSpecifier(AccessSpecifierAST *node)
+{
+ const ListNode<std::size_t> *it = node->specs;
+ if (it == 0)
+ return;
+
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+
+ do
+ {
+ switch (decode_token(it->element))
+ {
+ default:
+ break;
+
+ case Token_public:
+ changeCurrentAccess(CodeModel::Public);
+ changeCurrentFunctionType(CodeModel::Normal);
+ break;
+ case Token_protected:
+ changeCurrentAccess(CodeModel::Protected);
+ changeCurrentFunctionType(CodeModel::Normal);
+ break;
+ case Token_private:
+ changeCurrentAccess(CodeModel::Private);
+ changeCurrentFunctionType(CodeModel::Normal);
+ break;
+ case Token_signals:
+ changeCurrentAccess(CodeModel::Protected);
+ changeCurrentFunctionType(CodeModel::Signal);
+ break;
+ case Token_slots:
+ changeCurrentFunctionType(CodeModel::Slot);
+ break;
+ }
+ it = it->next;
+ }
+ while (it != end);
+}
+
+void Binder::visitSimpleDeclaration(SimpleDeclarationAST *node)
+{
+ visit(node->type_specifier);
+
+ if (const ListNode<InitDeclaratorAST*> *it = node->init_declarators)
+ {
+ it = it->toFront();
+ const ListNode<InitDeclaratorAST*> *end = it;
+ do
+ {
+ InitDeclaratorAST *init_declarator = it->element;
+ declare_symbol(node, init_declarator);
+ it = it->next;
+ }
+ while (it != end);
+ }
+}
+
+void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator)
+{
+ DeclaratorAST *declarator = init_declarator->declarator;
+
+ while (declarator && declarator->sub_declarator)
+ declarator = declarator->sub_declarator;
+
+ NameAST *id = declarator->id;
+ if (! declarator->id)
+ {
+ std::cerr << "** WARNING expected a declarator id" << std::endl;
+ return;
+ }
+
+ decl_cc.run(declarator);
+
+ if (decl_cc.isFunction())
+ {
+ name_cc.run(id->unqualified_name);
+
+ FunctionModelItem *fun = new FunctionModelItem(model());
+ updateFileAndItemPosition (fun, node);
+
+ ScopeModelItem *symbolScope = resolveScope(id, currentScope());
+ if (!symbolScope) {
+ delete fun;
+ return;
+ }
+
+ fun->setAccessPolicy(_M_current_access);
+ fun->setFunctionType(_M_current_function_type);
+ fun->setName(name_cc.qualifiedName());
+ fun->setAbstract(init_declarator->initializer != 0);
+ fun->setConstant(declarator->fun_cv != 0);
+ fun->setTemplateParameters(copyTemplateParameters(_M_current_template_parameters));
+ applyStorageSpecifiers(node->storage_specifiers, fun);
+ applyFunctionSpecifiers(node->function_specifiers, fun);
+
+ // build the type
+ TypeInfo *typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+ declarator,
+ this);
+
+ fun->setType(typeInfo);
+
+
+ fun->setVariadics (decl_cc.isVariadics ());
+
+ // ... and the signature
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+ {
+ CppArgumentModelItem *arg = new CppArgumentModelItem(model());
+ arg->setType(p.type);
+ arg->setName(p.name);
+ arg->setDefaultValue(p.defaultValue);
+ if (p.defaultValue)
+ arg->setDefaultValueExpression(p.defaultValueExpression);
+ fun->addArgument(arg);
+ }
+
+ fun->setScope(symbolScope->qualifiedName());
+ symbolScope->addFunction(fun);
+ }
+ else
+ {
+ CppVariableModelItem *var = new CppVariableModelItem(model());
+ updateFileAndItemPosition (var, node);
+
+ ScopeModelItem *symbolScope = resolveScope(id, currentScope());
+ if (!symbolScope) {
+ delete var;
+ return;
+ }
+
+ var->setTemplateParameters(copyTemplateParameters(_M_current_template_parameters));
+ var->setAccessPolicy(_M_current_access);
+ name_cc.run(id->unqualified_name);
+ var->setName(name_cc.qualifiedName());
+ TypeInfo *typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+ declarator,
+ this);
+ if (declarator != init_declarator->declarator
+ && init_declarator->declarator->parameter_declaration_clause != 0)
+ {
+ typeInfo->setFunctionPointer (true);
+ decl_cc.run (init_declarator->declarator);
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+ typeInfo->addArgument(p.type);
+ }
+
+ var->setType(typeInfo);
+ applyStorageSpecifiers(node->storage_specifiers, var);
+
+ var->setScope(symbolScope->qualifiedName());
+ symbolScope->addVariable(var);
+ }
+}
+
+void Binder::visitFunctionDefinition(FunctionDefinitionAST *node)
+{
+ Q_ASSERT(node->init_declarator != 0);
+
+ InitDeclaratorAST *init_declarator = node->init_declarator;
+ DeclaratorAST *declarator = init_declarator->declarator;
+
+ decl_cc.run(declarator);
+
+ Q_ASSERT(! decl_cc.id().isEmpty());
+
+ CppFunctionDefinitionModelItem *
+ old = changeCurrentFunction(new CppFunctionDefinitionModelItem(_M_model));
+ updateFileAndItemPosition (_M_current_function, node);
+
+ ScopeModelItem *functionScope = resolveScope(declarator->id, currentScope());
+ if (! functionScope) {
+ delete _M_current_function;
+ changeCurrentFunction(old);
+ return;
+ }
+
+ _M_current_function->setScope(functionScope->qualifiedName());
+
+ Q_ASSERT(declarator->id->unqualified_name != 0);
+ name_cc.run(declarator->id->unqualified_name);
+ QString unqualified_name = name_cc.qualifiedName();
+
+ _M_current_function->setName(unqualified_name);
+ TypeInfo *tmp_type = CompilerUtils::typeDescription(node->type_specifier,
+ declarator, this);
+
+ _M_current_function->setType(tmp_type);
+ _M_current_function->setAccessPolicy(_M_current_access);
+ _M_current_function->setFunctionType(_M_current_function_type);
+ _M_current_function->setConstant(declarator->fun_cv != 0);
+ _M_current_function->setTemplateParameters(copyTemplateParameters(_M_current_template_parameters));
+
+ applyStorageSpecifiers(node->storage_specifiers,
+ _M_current_function);
+ applyFunctionSpecifiers(node->function_specifiers,
+ _M_current_function);
+
+ _M_current_function->setVariadics (decl_cc.isVariadics ());
+
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+ {
+ CppArgumentModelItem *arg = new CppArgumentModelItem(model());
+ arg->setType(p.type);
+ arg->setName(p.name);
+ arg->setDefaultValue(p.defaultValue);
+ _M_current_function->addArgument(arg);
+ }
+
+ functionScope->addFunctionDefinition(_M_current_function);
+ changeCurrentFunction(old);
+}
+
+void Binder::visitTemplateDeclaration(TemplateDeclarationAST *node)
+{
+ const ListNode<TemplateParameterAST*> *it = node->template_parameters;
+ if (it == 0)
+ return;
+
+ TemplateParameterList savedTemplateParameters = changeTemplateParameters(TemplateParameterList());
+
+ it = it->toFront();
+ const ListNode<TemplateParameterAST*> *end = it;
+
+ do
+ {
+ TemplateParameterAST *parameter = it->element;
+ TypeParameterAST *type_parameter = parameter->type_parameter;
+ if (! type_parameter)
+ {
+ std::cerr << "** WARNING template declaration not supported ``";
+ Token const &tk = _M_token_stream->token ((int) node->start_token);
+ Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token);
+
+ std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''"
+ << std::endl << std::endl;
+
+ qDeleteAll(_M_current_template_parameters);
+ changeTemplateParameters(savedTemplateParameters);
+ return;
+ }
+ assert(type_parameter != 0);
+
+ int tk = decode_token(type_parameter->type);
+ if (tk != Token_typename && tk != Token_class)
+ {
+ std::cerr << "** WARNING template declaration not supported ``";
+ Token const &tk = _M_token_stream->token ((int) node->start_token);
+ Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token);
+
+ std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''"
+ << std::endl << std::endl;
+
+ qDeleteAll(_M_current_template_parameters);
+ changeTemplateParameters(savedTemplateParameters);
+ return;
+ }
+ assert(tk == Token_typename || tk == Token_class);
+
+ name_cc.run(type_parameter->name);
+
+ CppTemplateParameterModelItem *p = new CppTemplateParameterModelItem(model());
+ p->setName(name_cc.qualifiedName());
+ _M_current_template_parameters.append(p);
+ it = it->next;
+ }
+ while (it != end);
+
+ visit(node->declaration);
+
+ qDeleteAll(_M_current_template_parameters);
+ changeTemplateParameters(savedTemplateParameters);
+}
+
+void Binder::visitTypedef(TypedefAST *node)
+{
+ const ListNode<InitDeclaratorAST*> *it = node->init_declarators;
+ if (it == 0)
+ return;
+
+ it = it->toFront();
+ const ListNode<InitDeclaratorAST*> *end = it;
+
+ do
+ {
+ InitDeclaratorAST *init_declarator = it->element;
+ it = it->next;
+
+ Q_ASSERT(init_declarator->declarator != 0);
+
+ // the name
+ decl_cc.run (init_declarator->declarator);
+ QString alias_name = decl_cc.id ();
+
+ if (alias_name.isEmpty ())
+ {
+ std::cerr << "** WARNING anonymous typedef not supported! ``";
+ Token const &tk = _M_token_stream->token ((int) node->start_token);
+ Token const &end_tk = _M_token_stream->token ((int) node->end_token);
+
+ std::cerr << std::string (&tk.text[tk.position], end_tk.position - tk.position) << "''"
+ << std::endl << std::endl;
+ continue;
+ }
+
+ // build the type
+ TypeInfo *typeInfo = CompilerUtils::typeDescription (node->type_specifier,
+ init_declarator->declarator,
+ this);
+ DeclaratorAST *decl = init_declarator->declarator;
+ while (decl && decl->sub_declarator)
+ decl = decl->sub_declarator;
+
+ if (decl != init_declarator->declarator
+ && init_declarator->declarator->parameter_declaration_clause != 0)
+ {
+ typeInfo->setFunctionPointer (true);
+ decl_cc.run (init_declarator->declarator);
+ foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+ typeInfo->addArgument(p.type);
+ }
+
+ DeclaratorAST *declarator = init_declarator->declarator;
+
+ CppTypeAliasModelItem *typeAlias = new CppTypeAliasModelItem(model());
+ updateFileAndItemPosition (typeAlias, node);
+
+ ScopeModelItem *typedefScope = resolveScope(declarator->id, currentScope());
+ if (!typedefScope) {
+ delete typeAlias;
+ return;
+ }
+
+ typeAlias->setName (alias_name);
+ typeAlias->setType (typeInfo);
+ typeAlias->setScope (typedefScope->qualifiedName());
+ typedefScope->addTypeAlias (typeAlias);
+ }
+ while (it != end);
+}
+
+void Binder::visitNamespace(NamespaceAST *node)
+{
+ bool anonymous = (node->namespace_name == 0);
+
+ ScopeModelItem *scope = 0;
+ NamespaceModelItem *old = 0;
+ if (! anonymous)
+ {
+ // update the file if needed
+ updateFileAndItemPosition (0, node);
+ scope = currentScope();
+
+ QString name = decode_symbol(node->namespace_name)->as_string();
+
+ QString qualified_name = scope->qualifiedName();
+ if (!qualified_name.isEmpty())
+ qualified_name += QLatin1String("::");
+ qualified_name += name;
+ NamespaceModelItem *ns = model_cast<NamespaceModelItem *>(findScope(qualified_name));
+ if (ns && ns->file() != scope->file()) {
+ qDebug() << ns->file()->name() << " :: " << scope->file()->name();
+ ns = 0; // we need a separate namespaces for different files
+ }
+
+ if (!ns)
+ {
+ ns = new NamespaceModelItem(_M_model);
+ updateFileAndItemPosition (ns, node);
+
+ _M_known_scopes.insert(qualified_name, ns);
+ ns->setName(name);
+ ns->setScope(scope->qualifiedName());
+ }
+ old = changeCurrentNamespace(ns);
+ }
+
+ DefaultVisitor::visitNamespace(node);
+
+ if (! anonymous)
+ {
+ Q_ASSERT(scope->kind() == CodeModelItem::Kind_Namespace
+ || scope->kind() == CodeModelItem::Kind_File);
+
+ if (NamespaceModelItem *ns = model_cast<NamespaceModelItem *>(scope))
+ ns->addNamespace(_M_current_namespace);
+
+ changeCurrentNamespace(old);
+ }
+}
+
+void Binder::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ ClassCompiler class_cc(this);
+ class_cc.run(node);
+
+ if (class_cc.name().isEmpty())
+ {
+ // anonymous not supported
+ return;
+ }
+
+ Q_ASSERT(node->name != 0 && node->name->unqualified_name != 0);
+
+
+ CppClassModelItem *class_item = new CppClassModelItem(_M_model);
+ updateFileAndItemPosition (class_item, node);
+ ScopeModelItem *scope = currentScope();
+ CppClassModelItem *old = changeCurrentClass(class_item);
+
+ _M_current_class->setName(class_cc.name());
+ _M_current_class->setBaseClasses(class_cc.baseClasses());
+ _M_current_class->setClassType(decode_class_type(node->class_key));
+ _M_current_class->setTemplateParameters(copyTemplateParameters(_M_current_template_parameters));
+
+ QString name = _M_current_class->name();
+ if (!_M_current_template_parameters.isEmpty())
+ {
+ name += "<";
+ for (int i = 0; i<_M_current_template_parameters.size(); ++i)
+ {
+ if (i != 0)
+ name += ",";
+
+ name += _M_current_template_parameters.at(i)->name();
+ }
+
+ name += ">";
+ _M_current_class->setName(name);
+ }
+
+ CodeModel::AccessPolicy oldAccessPolicy = changeCurrentAccess(decode_access_policy(node->class_key));
+ CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal);
+
+ QString qualifiedname = scope->qualifiedName();
+ _M_current_class->setScope(qualifiedname);
+ if (!qualifiedname.isEmpty())
+ qualifiedname += QLatin1String("::");
+ qualifiedname += name;
+ _M_known_scopes.insert(qualifiedname, _M_current_class);
+
+ scope->addClass(_M_current_class);
+
+ name_cc.run(node->name->unqualified_name);
+
+ visitNodes(this, node->member_specs);
+
+ changeCurrentClass(old);
+ changeCurrentAccess(oldAccessPolicy);
+ changeCurrentFunctionType(oldFunctionType);
+}
+
+void Binder::visitLinkageSpecification(LinkageSpecificationAST *node)
+{
+ DefaultVisitor::visitLinkageSpecification(node);
+}
+
+void Binder::visitUsing(UsingAST *node)
+{
+ DefaultVisitor::visitUsing(node);
+}
+
+void Binder::visitEnumSpecifier(EnumSpecifierAST *node)
+{
+ CodeModelFinder finder(model(), this);
+
+ name_cc.run(node->name);
+ QString name = name_cc.qualifiedName();
+
+ if (name.isEmpty())
+ {
+ // anonymous enum
+ static int N = 0;
+ name = QLatin1String("$$enum_");
+ name += QString::number(++N);
+ }
+
+ _M_current_enum = new CppEnumModelItem(model());
+
+ updateFileAndItemPosition (_M_current_enum, node);
+ ScopeModelItem *enumScope = resolveScope(node->name, currentScope());
+ if (!enumScope) {
+ delete _M_current_enum;
+ _M_current_enum = 0;
+ return;
+ }
+
+
+ _M_current_enum->setAccessPolicy(_M_current_access);
+ _M_current_enum->setName(name);
+ _M_current_enum->setScope(enumScope->qualifiedName());
+
+ enumScope->addEnum(_M_current_enum);
+
+ DefaultVisitor::visitEnumSpecifier(node);
+
+ _M_current_enum = 0;
+}
+
+void Binder::visitEnumerator(EnumeratorAST *node)
+{
+ Q_ASSERT(_M_current_enum != 0);
+ CppEnumeratorModelItem *e = new CppEnumeratorModelItem(model());
+ updateFileAndItemPosition (e, node);
+ e->setName(decode_symbol(node->id)->as_string());
+
+ if (ExpressionAST *expr = node->expression)
+ {
+ const Token &start_token = _M_token_stream->token((int) expr->start_token);
+ const Token &end_token = _M_token_stream->token((int) expr->end_token);
+
+ e->setValue(QString::fromUtf8(&start_token.text[start_token.position],
+ (int) (end_token.position - start_token.position)).trimmed());
+ }
+
+ _M_current_enum->addEnumerator(e);
+}
+
+void Binder::visitUsingDirective(UsingDirectiveAST *node)
+{
+ DefaultVisitor::visitUsingDirective(node);
+}
+
+void Binder::applyStorageSpecifiers(const ListNode<std::size_t> *it, MemberModelItem *item)
+{
+ if (it == 0)
+ return;
+
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+
+ do
+ {
+ switch (decode_token(it->element))
+ {
+ default:
+ break;
+
+ case Token_friend:
+ item->setFriend(true);
+ break;
+ case Token_auto:
+ item->setAuto(true);
+ break;
+ case Token_register:
+ item->setRegister(true);
+ break;
+ case Token_static:
+ item->setStatic(true);
+ break;
+ case Token_extern:
+ item->setExtern(true);
+ break;
+ case Token_mutable:
+ item->setMutable(true);
+ break;
+ }
+ it = it->next;
+ }
+ while (it != end);
+}
+
+void Binder::applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem *item)
+{
+ if (it == 0)
+ return;
+
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+
+ do
+ {
+ switch (decode_token(it->element))
+ {
+ default:
+ break;
+
+ case Token_inline:
+ item->setInline(true);
+ break;
+
+ case Token_virtual:
+ item->setVirtual(true);
+ break;
+
+ case Token_explicit:
+ item->setExplicit(true);
+ break;
+ }
+ it = it->next;
+ }
+ while (it != end);
+}
+
+void Binder::updateFileAndItemPosition(CodeModelItem *item, AST *node)
+{
+ QString filename;
+ int sline, scolumn;
+ int eline, ecolumn;
+
+ assert (node != 0);
+ _M_location.positionAt (_M_token_stream->position(node->start_token), &sline, &scolumn, &filename);
+ _M_location.positionAt (_M_token_stream->position(node->end_token), &eline, &ecolumn, &QString());
+
+ if (!filename.isEmpty() && (!_M_current_file || _M_current_file->name() != filename))
+ _M_current_file = model()->fileItem(filename);
+
+ if (item) {
+ item->setFile(_M_current_file);
+ item->setStartPosition(sline, scolumn);
+ item->setEndPosition(eline, ecolumn);
+ }
+}
+
+TemplateParameterList Binder::copyTemplateParameters(const TemplateParameterList &in) const
+{
+ TemplateParameterList result;
+ foreach(TemplateParameterModelItem *item, in) {
+ CppTemplateParameterModelItem *newitem =
+ new CppTemplateParameterModelItem(*(model_cast<CppTemplateParameterModelItem *>(item)));
+ if (item->type()) {
+ TypeInfo *type = new TypeInfo();
+ *type = *(item->type());
+ newitem->setType(type);
+ }
+ result.append(newitem);
+ }
+ return result;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/binder.h b/tests/manual/cppmodelmanager/codemodel/binder.h
new file mode 100644
index 0000000000..252c15b744
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/binder.h
@@ -0,0 +1,141 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright (C) 2005 Trolltech AS
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef BINDER_H
+#define BINDER_H
+
+#include "default_visitor.h"
+#include "cppcodemodel.h"
+#include "type_compiler.h"
+#include "name_compiler.h"
+#include "declarator_compiler.h"
+
+class TokenStream;
+class LocationManager;
+class Control;
+struct NameSymbol;
+
+class Binder: protected DefaultVisitor
+{
+public:
+ Binder(CppCodeModel *__model, LocationManager &__location, Control *__control = 0);
+ virtual ~Binder();
+
+ inline TokenStream *tokenStream() const { return _M_token_stream; }
+ inline CppCodeModel *model() const { return _M_model; }
+ ScopeModelItem *currentScope();
+
+ void run(AST *node, const QString &filename);
+
+protected:
+ virtual void visitAccessSpecifier(AccessSpecifierAST *);
+ virtual void visitClassSpecifier(ClassSpecifierAST *);
+ virtual void visitEnumSpecifier(EnumSpecifierAST *);
+ virtual void visitEnumerator(EnumeratorAST *);
+ virtual void visitFunctionDefinition(FunctionDefinitionAST *);
+ virtual void visitLinkageSpecification(LinkageSpecificationAST *);
+ virtual void visitNamespace(NamespaceAST *);
+ virtual void visitSimpleDeclaration(SimpleDeclarationAST *);
+ virtual void visitTemplateDeclaration(TemplateDeclarationAST *);
+ virtual void visitTypedef(TypedefAST *);
+ virtual void visitUsing(UsingAST *);
+ virtual void visitUsingDirective(UsingDirectiveAST *);
+
+private:
+ ScopeModelItem *findScope(const QString &name) const;
+ ScopeModelItem *resolveScope(NameAST *id, ScopeModelItem *scope);
+
+ int decode_token(std::size_t index) const;
+ const NameSymbol *decode_symbol(std::size_t index) const;
+ CodeModel::AccessPolicy decode_access_policy(std::size_t index) const;
+ CodeModel::ClassType decode_class_type(std::size_t index) const;
+
+ CodeModel::FunctionType changeCurrentFunctionType(CodeModel::FunctionType functionType);
+ CodeModel::AccessPolicy changeCurrentAccess(CodeModel::AccessPolicy accessPolicy);
+ NamespaceModelItem *changeCurrentNamespace(NamespaceModelItem *item);
+ CppClassModelItem *changeCurrentClass(CppClassModelItem *item);
+ CppFunctionDefinitionModelItem *changeCurrentFunction(CppFunctionDefinitionModelItem *item);
+ TemplateParameterList changeTemplateParameters(TemplateParameterList templateParameters);
+
+ void declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator);
+
+ void applyStorageSpecifiers(const ListNode<std::size_t> *storage_specifiers, MemberModelItem *item);
+ void applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem *item);
+
+ void updateFileAndItemPosition(CodeModelItem *item, AST *node);
+
+ TemplateParameterList copyTemplateParameters(const TemplateParameterList &in) const;
+
+private:
+ CppCodeModel *_M_model;
+ LocationManager &_M_location;
+ TokenStream *_M_token_stream;
+ Control *_M_control;
+
+ CodeModel::FunctionType _M_current_function_type;
+ CodeModel::AccessPolicy _M_current_access;
+ CppFileModelItem *_M_current_file;
+ NamespaceModelItem *_M_current_namespace;
+ CppClassModelItem *_M_current_class;
+ CppFunctionDefinitionModelItem *_M_current_function;
+ CppEnumModelItem *_M_current_enum;
+ TemplateParameterList _M_current_template_parameters;
+ QHash<QString, ScopeModelItem *> _M_known_scopes;
+
+protected:
+ TypeCompiler type_cc;
+ NameCompiler name_cc;
+ DeclaratorCompiler decl_cc;
+};
+
+#endif // BINDER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/class_compiler.cpp b/tests/manual/cppmodelmanager/codemodel/class_compiler.cpp
new file mode 100644
index 0000000000..7a484f9447
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/class_compiler.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "class_compiler.h"
+#include "lexer.h"
+#include "binder.h"
+
+ClassCompiler::ClassCompiler(Binder *binder)
+ : _M_binder (binder),
+ _M_token_stream(binder->tokenStream ()),
+ name_cc(_M_binder),
+ type_cc(_M_binder)
+{
+}
+
+ClassCompiler::~ClassCompiler()
+{
+}
+
+void ClassCompiler::run(ClassSpecifierAST *node)
+{
+ name_cc.run(node->name);
+ _M_name = name_cc.qualifiedName();
+ _M_base_classes.clear();
+
+ visit(node);
+}
+
+void ClassCompiler::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ visit(node->base_clause);
+}
+
+void ClassCompiler::visitBaseSpecifier(BaseSpecifierAST *node)
+{
+ name_cc.run(node->name);
+ QString name = name_cc.qualifiedName();
+
+ if (! name.isEmpty())
+ _M_base_classes.append(name);
+}
+
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/class_compiler.h b/tests/manual/cppmodelmanager/codemodel/class_compiler.h
new file mode 100644
index 0000000000..a6b3656c26
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/class_compiler.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CLASS_COMPILER_H
+#define CLASS_COMPILER_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QStringList>
+
+#include "default_visitor.h"
+#include "name_compiler.h"
+#include "type_compiler.h"
+
+class TokenStream;
+class Binder;
+
+class ClassCompiler: protected DefaultVisitor
+{
+public:
+ ClassCompiler(Binder *binder);
+ virtual ~ClassCompiler();
+
+ inline QString name() const { return _M_name; }
+ inline QStringList baseClasses() const { return _M_base_classes; }
+
+ void run(ClassSpecifierAST *node);
+
+protected:
+ virtual void visitClassSpecifier(ClassSpecifierAST *node);
+ virtual void visitBaseSpecifier(BaseSpecifierAST *node);
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ QString _M_name;
+ QStringList _M_base_classes;
+ NameCompiler name_cc;
+ TypeCompiler type_cc;
+};
+
+#endif // CLASS_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/codemodel_finder.cpp b/tests/manual/cppmodelmanager/codemodel/codemodel_finder.cpp
new file mode 100644
index 0000000000..2aa5a41ea3
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/codemodel_finder.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#include "codemodel_finder.h"
+#include "cppcodemodel.h"
+#include "binder.h"
+
+CodeModelFinder::CodeModelFinder(CppCodeModel *model, Binder *binder)
+: _M_model(model),
+_M_binder (binder),
+name_cc(_M_binder)
+{
+}
+
+CodeModelFinder::~CodeModelFinder()
+{
+}
+
+QString CodeModelFinder::resolveScope(NameAST *name, ScopeModelItem *scope, bool *ok)
+{
+ Q_ASSERT(scope != 0);
+
+ _M_ok = true;
+ _M_current_scope = scope->qualifiedName();
+ visit(name);
+ *ok = _M_ok;
+
+ return _M_current_scope;
+}
+
+void CodeModelFinder::visitName(NameAST *node)
+{
+ visitNodes(this, node->qualified_names);
+}
+
+void CodeModelFinder::visitUnqualifiedName(UnqualifiedNameAST *node)
+{
+ if (!_M_ok)
+ return;
+
+ if (!_M_current_scope.isEmpty())
+ _M_current_scope += QLatin1String("::");
+
+ name_cc.run(node);
+ _M_current_scope += name_cc.qualifiedName();
+
+ if (!_M_model->hasScope(_M_current_scope))
+ _M_ok = false;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/tests/manual/cppmodelmanager/codemodel/codemodel_finder.h b/tests/manual/cppmodelmanager/codemodel/codemodel_finder.h
new file mode 100644
index 0000000000..3c6c52965d
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/codemodel_finder.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CODEMODEL_FINDER_H
+#define CODEMODEL_FINDER_H
+
+#include "default_visitor.h"
+#include "name_compiler.h"
+
+class Binder;
+class CppCodeModel;
+class ScopeModelItem;
+
+class CodeModelFinder: protected DefaultVisitor
+{
+public:
+ CodeModelFinder(CppCodeModel *model, Binder *binder);
+ virtual ~CodeModelFinder();
+
+ QString resolveScope(NameAST *name, ScopeModelItem *scope, bool *ok);
+
+ inline CppCodeModel *model() const { return _M_model; }
+
+protected:
+ virtual void visitName(NameAST *node);
+ virtual void visitUnqualifiedName(UnqualifiedNameAST *node);
+
+private:
+ CppCodeModel *_M_model;
+ Binder *_M_binder;
+ NameCompiler name_cc;
+
+ bool _M_ok;
+ QString _M_current_scope;
+};
+
+#endif // CODEMODEL_FINDER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/codemodelitems.cpp b/tests/manual/cppmodelmanager/codemodel/codemodelitems.cpp
new file mode 100644
index 0000000000..8d168a1395
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/codemodelitems.cpp
@@ -0,0 +1,893 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+Copyright (C) 2005 Trolltech AS
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#include <QtCore/QHash>
+#include "codemodelitems.h"
+
+CodeModel::~CodeModel()
+{
+
+}
+
+// ---------------------------------------------------------------------------
+bool TypeInfo::operator==(const TypeInfo &other)
+{
+ if (arrayElements().count() != other.arguments().count())
+ return false;
+
+ return flags == other.flags
+ && m_qualifiedName == other.m_qualifiedName
+ && (!m_functionPointer || m_arguments == other.m_arguments);
+}
+
+// ---------------------------------------------------------------------------
+class CodeModelItemData {
+public:
+ CodeModel *_M_model;
+ int _M_kind;
+ int _M_startLine;
+ int _M_startColumn;
+ int _M_endLine;
+ int _M_endColumn;
+ std::size_t _M_creation_id;
+ QString _M_name;
+ FileModelItem *_M_file;
+ QString _M_scope;
+};
+
+CodeModelItem::CodeModelItem(CodeModel *model, int kind)
+{
+ d = new CodeModelItemData;
+ d->_M_model = model;
+ d->_M_kind = kind;
+ d->_M_startLine = 0;
+ d->_M_startColumn = 0;
+ d->_M_endLine = 0;
+ d->_M_endColumn = 0;
+ d->_M_creation_id = 0;
+}
+
+CodeModelItem::CodeModelItem(const CodeModelItem &item)
+{
+ d = new CodeModelItemData;
+ *d = *(item.d);
+}
+
+CodeModelItem::~CodeModelItem()
+{
+ delete d;
+}
+
+int CodeModelItem::kind() const
+{
+ return d->_M_kind;
+}
+
+void CodeModelItem::setKind(int kind)
+{
+ d->_M_kind = kind;
+}
+
+QString CodeModelItem::qualifiedName() const
+{
+ if (kind() == CodeModelItem::Kind_File)
+ return QString();
+
+ QString q = scope();
+
+ if (!q.isEmpty() && !name().isEmpty())
+ q += QLatin1String("::");
+
+ q += name();
+
+ return q;
+}
+
+QString CodeModelItem::name() const
+{
+ return d->_M_name;
+}
+
+void CodeModelItem::setName(const QString &name)
+{
+ d->_M_name = name;
+}
+
+QString CodeModelItem::scope() const
+{
+ return d->_M_scope;
+}
+
+void CodeModelItem::setScope(const QString &scope)
+{
+ d->_M_scope = scope;
+}
+
+void CodeModelItem::setFile(FileModelItem *file)
+{
+ d->_M_file = file;
+}
+
+FileModelItem *CodeModelItem::file() const
+{
+ return d->_M_file;
+}
+
+void CodeModelItem::startPosition(int *line, int *column)
+{
+ *line = d->_M_startLine;
+ *column = d->_M_startColumn;
+}
+
+void CodeModelItem::setStartPosition(int line, int column)
+{
+ d->_M_startLine = line;
+ d->_M_startColumn = column;
+}
+
+void CodeModelItem::endPosition(int *line, int *column)
+{
+ *line = d->_M_endLine;
+ *column = d->_M_endColumn;
+}
+
+void CodeModelItem::setEndPosition(int line, int column)
+{
+ d->_M_endLine = line;
+ d->_M_endColumn = column;
+}
+
+std::size_t CodeModelItem::creationId() const
+{
+ return d->_M_creation_id;
+}
+
+void CodeModelItem::setCreationId(std::size_t creation_id)
+{
+ d->_M_creation_id = creation_id;
+}
+
+CodeModel *CodeModelItem::model() const
+{
+ return d->_M_model;
+}
+
+// ---------------------------------------------------------------------------
+class ClassModelItemData
+{
+public:
+ ~ClassModelItemData() {
+ qDeleteAll(_M_templateParameters);
+ }
+ QStringList _M_baseClasses;
+ TemplateParameterList _M_templateParameters;
+ CodeModel::ClassType _M_classType;
+};
+
+ClassModelItem::ClassModelItem(CodeModel *model, int kind)
+: ScopeModelItem(model, kind)
+{
+ d = new ClassModelItemData();
+ d->_M_classType = CodeModel::Class;
+}
+
+ClassModelItem::~ClassModelItem()
+{
+ delete d;
+}
+
+QStringList ClassModelItem::baseClasses() const
+{
+ return d->_M_baseClasses;
+}
+
+void ClassModelItem::setBaseClasses(const QStringList &baseClasses)
+{
+ d->_M_baseClasses = baseClasses;
+}
+
+TemplateParameterList ClassModelItem::templateParameters() const
+{
+ return d->_M_templateParameters;
+}
+
+void ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters)
+{
+ d->_M_templateParameters = templateParameters;
+}
+
+void ClassModelItem::addBaseClass(const QString &baseClass)
+{
+ d->_M_baseClasses.append(baseClass);
+}
+
+bool ClassModelItem::extendsClass(const QString &name) const
+{
+ return d->_M_baseClasses.contains(name);
+}
+
+void ClassModelItem::setClassType(CodeModel::ClassType type)
+{
+ d->_M_classType = type;
+}
+
+CodeModel::ClassType ClassModelItem::classType() const
+{
+ return d->_M_classType;
+}
+
+// ---------------------------------------------------------------------------
+class ScopeModelItemData
+{
+public:
+ ~ScopeModelItemData() {
+ qDeleteAll(_M_classes.values());
+ qDeleteAll(_M_enums.values());
+ qDeleteAll(_M_typeAliases.values());
+ qDeleteAll(_M_variables.values());
+ qDeleteAll(_M_functionDefinitions.values());
+ qDeleteAll(_M_functions.values());
+ }
+
+ QHash<QString, ClassModelItem*> _M_classes;
+ QHash<QString, EnumModelItem*> _M_enums;
+ QHash<QString, TypeAliasModelItem*> _M_typeAliases;
+ QHash<QString, VariableModelItem*> _M_variables;
+ QMultiHash<QString, FunctionDefinitionModelItem*> _M_functionDefinitions;
+ QMultiHash<QString, FunctionModelItem*> _M_functions;
+};
+
+ScopeModelItem::ScopeModelItem(CodeModel *model, int kind)
+ : CodeModelItem(model, kind)
+{
+ d = new ScopeModelItemData;
+}
+
+ScopeModelItem::~ScopeModelItem()
+{
+ delete d;
+}
+
+void ScopeModelItem::addClass(ClassModelItem *item)
+{
+ d->_M_classes.insert(item->name(), item);
+}
+
+void ScopeModelItem::addFunction(FunctionModelItem *item)
+{
+ d->_M_functions.insert(item->name(), item);
+}
+
+void ScopeModelItem::addFunctionDefinition(FunctionDefinitionModelItem *item)
+{
+ d->_M_functionDefinitions.insert(item->name(), item);
+}
+
+void ScopeModelItem::addVariable(VariableModelItem *item)
+{
+ d->_M_variables.insert(item->name(), item);
+}
+
+void ScopeModelItem::addTypeAlias(TypeAliasModelItem *item)
+{
+ d->_M_typeAliases.insert(item->name(), item);
+}
+
+void ScopeModelItem::addEnum(EnumModelItem *item)
+{
+ d->_M_enums.insert(item->name(), item);
+}
+
+// ---------------------------------------------------------------------------
+class NamespaceModelItemData
+{
+public:
+ ~NamespaceModelItemData() {
+ qDeleteAll(_M_namespaces.values());
+ }
+
+ QHash<QString, NamespaceModelItem *> _M_namespaces;
+};
+
+NamespaceModelItem::NamespaceModelItem(CodeModel *model, int kind)
+: ScopeModelItem(model, kind)
+{
+ d = new NamespaceModelItemData();
+}
+
+NamespaceModelItem::~NamespaceModelItem()
+{
+ delete d;
+}
+
+NamespaceList NamespaceModelItem::namespaces() const
+{
+ return d->_M_namespaces.values();
+}
+void NamespaceModelItem::addNamespace(NamespaceModelItem *item)
+{
+ d->_M_namespaces.insert(item->name(), item);
+}
+
+// ---------------------------------------------------------------------------
+class ArgumentModelItemData
+{
+public:
+ ~ArgumentModelItemData() {
+ delete _M_type;
+ }
+ TypeInfo *_M_type;
+ QString _M_defaultValueExpression;
+ bool _M_defaultValue;
+};
+
+ArgumentModelItem::ArgumentModelItem(CodeModel *model, int kind)
+: CodeModelItem(model, kind)
+{
+ d = new ArgumentModelItemData();
+ d->_M_defaultValue = false;
+}
+
+ArgumentModelItem::~ArgumentModelItem()
+{
+ delete d;
+}
+
+TypeInfo *ArgumentModelItem::type() const
+{
+ return d->_M_type;
+}
+
+void ArgumentModelItem::setType(TypeInfo *type)
+{
+ d->_M_type = type;
+}
+
+bool ArgumentModelItem::defaultValue() const
+{
+ return d->_M_defaultValue;
+}
+
+void ArgumentModelItem::setDefaultValue(bool defaultValue)
+{
+ d->_M_defaultValue = defaultValue;
+}
+
+QString ArgumentModelItem::defaultValueExpression() const
+{
+ return d->_M_defaultValueExpression;
+}
+
+void ArgumentModelItem::setDefaultValueExpression(const QString &expr)
+{
+ d->_M_defaultValueExpression = expr;
+}
+
+// ---------------------------------------------------------------------------
+class FunctionModelItemData
+{
+public:
+ ~FunctionModelItemData() {
+ qDeleteAll(_M_arguments);
+ }
+
+ ArgumentList _M_arguments;
+ CodeModel::FunctionType _M_functionType;
+ union
+ {
+ struct
+ {
+ uint _M_isVirtual: 1;
+ uint _M_isInline: 1;
+ uint _M_isAbstract: 1;
+ uint _M_isExplicit: 1;
+ uint _M_isVariadics: 1;
+ };
+ uint _M_flags;
+ };
+};
+
+FunctionModelItem::FunctionModelItem(CodeModel *model, int kind)
+: MemberModelItem(model, kind)
+{
+ d = new FunctionModelItemData();
+ d->_M_functionType = CodeModel::Normal;
+ d->_M_flags = 0;
+}
+
+FunctionModelItem::~FunctionModelItem()
+{
+ delete d;
+}
+
+bool FunctionModelItem::isSimilar(FunctionModelItem *other) const
+{
+ if (name() != other->name())
+ return false;
+
+ if (isConstant() != other->isConstant())
+ return false;
+
+ if (isVariadics() != other->isVariadics())
+ return false;
+
+ if (arguments().count() != other->arguments().count())
+ return false;
+
+ // ### check the template parameters
+
+ for (int i=0; i<arguments().count(); ++i)
+ {
+ ArgumentModelItem *arg1 = arguments().at(i);
+ ArgumentModelItem *arg2 = other->arguments().at(i);
+
+ TypeInfo *t1 = static_cast<TypeInfo *>(arg1->type());
+ TypeInfo *t2 = static_cast<TypeInfo *>(arg2->type());
+
+ if (*t1 != *t2)
+ return false;
+ }
+
+ return true;
+}
+
+ArgumentList FunctionModelItem::arguments() const
+{
+ return d->_M_arguments;
+}
+
+void FunctionModelItem::addArgument(ArgumentModelItem *item)
+{
+ d->_M_arguments.append(item);
+}
+
+CodeModel::FunctionType FunctionModelItem::functionType() const
+{
+ return d->_M_functionType;
+}
+
+void FunctionModelItem::setFunctionType(CodeModel::FunctionType functionType)
+{
+ d->_M_functionType = functionType;
+}
+
+bool FunctionModelItem::isVariadics() const
+{
+ return d->_M_isVariadics;
+}
+
+void FunctionModelItem::setVariadics(bool isVariadics)
+{
+ d->_M_isVariadics = isVariadics;
+}
+
+bool FunctionModelItem::isVirtual() const
+{
+ return d->_M_isVirtual;
+}
+
+void FunctionModelItem::setVirtual(bool isVirtual)
+{
+ d->_M_isVirtual = isVirtual;
+}
+
+bool FunctionModelItem::isInline() const
+{
+ return d->_M_isInline;
+}
+
+void FunctionModelItem::setInline(bool isInline)
+{
+ d->_M_isInline = isInline;
+}
+
+bool FunctionModelItem::isExplicit() const
+{
+ return d->_M_isExplicit;
+}
+
+void FunctionModelItem::setExplicit(bool isExplicit)
+{
+ d->_M_isExplicit = isExplicit;
+}
+
+bool FunctionModelItem::isAbstract() const
+{
+ return d->_M_isAbstract;
+}
+
+void FunctionModelItem::setAbstract(bool isAbstract)
+{
+ d->_M_isAbstract = isAbstract;
+}
+
+// ---------------------------------------------------------------------------
+class TypeAliasModelItemData
+{
+public:
+ ~TypeAliasModelItemData() {
+ delete _M_type;
+ }
+
+ TypeInfo *_M_type;
+};
+
+TypeAliasModelItem::TypeAliasModelItem(CodeModel *model, int kind)
+: CodeModelItem(model, kind)
+{
+ d = new TypeAliasModelItemData;
+}
+
+TypeAliasModelItem::~TypeAliasModelItem()
+{
+ delete d;
+}
+
+TypeInfo *TypeAliasModelItem::type() const
+{
+ return d->_M_type;
+}
+
+void TypeAliasModelItem::setType(TypeInfo *type)
+{
+ d->_M_type = type;
+}
+
+// ---------------------------------------------------------------------------
+class EnumModelItemData
+{
+public:
+ ~EnumModelItemData() {
+ qDeleteAll(_M_enumerators);
+ }
+ CodeModel::AccessPolicy _M_accessPolicy;
+ EnumeratorList _M_enumerators;
+};
+
+EnumModelItem::EnumModelItem(CodeModel *model, int kind)
+: CodeModelItem(model, kind)
+{
+ d = new EnumModelItemData;
+ d->_M_accessPolicy = CodeModel::Public;
+}
+
+EnumModelItem::~EnumModelItem()
+{
+ delete d;
+}
+
+CodeModel::AccessPolicy EnumModelItem::accessPolicy() const
+{
+ return d->_M_accessPolicy;
+}
+
+void EnumModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
+{
+ d->_M_accessPolicy = accessPolicy;
+}
+
+EnumeratorList EnumModelItem::enumerators() const
+{
+ return d->_M_enumerators;
+}
+
+void EnumModelItem::addEnumerator(EnumeratorModelItem *item)
+{
+ d->_M_enumerators.append(item);
+}
+
+// ---------------------------------------------------------------------------
+class EnumeratorModelItemData
+{
+public:
+ QString _M_value;
+};
+
+EnumeratorModelItem::EnumeratorModelItem(CodeModel *model, int kind)
+: CodeModelItem(model, kind)
+{
+ d = new EnumeratorModelItemData;
+}
+
+EnumeratorModelItem::~EnumeratorModelItem()
+{
+ delete d;
+}
+
+QString EnumeratorModelItem::value() const
+{
+ return d->_M_value;
+}
+
+void EnumeratorModelItem::setValue(const QString &value)
+{
+ d->_M_value = value;
+}
+
+// ---------------------------------------------------------------------------
+class TemplateParameterModelItemData
+{
+public:
+ ~TemplateParameterModelItemData() {
+ delete _M_type;
+ }
+
+ TypeInfo *_M_type;
+ bool _M_defaultValue;
+};
+
+TemplateParameterModelItem::TemplateParameterModelItem(CodeModel *model, int kind)
+: CodeModelItem(model, kind)
+{
+ d = new TemplateParameterModelItemData;
+ d->_M_defaultValue = false;
+ d->_M_type = 0;
+}
+
+TemplateParameterModelItem::TemplateParameterModelItem(const TemplateParameterModelItem& item)
+ : CodeModelItem(item)
+{
+ d = new TemplateParameterModelItemData;
+ *d = *(item.d);
+}
+
+TemplateParameterModelItem::~TemplateParameterModelItem()
+{
+ delete d;
+}
+
+TypeInfo *TemplateParameterModelItem::type() const
+{
+ return d->_M_type;
+}
+
+void TemplateParameterModelItem::setType(TypeInfo *type)
+{
+ d->_M_type = type;
+}
+
+bool TemplateParameterModelItem::defaultValue() const
+{
+ return d->_M_defaultValue;
+}
+
+void TemplateParameterModelItem::setDefaultValue(bool defaultValue)
+{
+ d->_M_defaultValue = defaultValue;
+}
+
+// ---------------------------------------------------------------------------
+FileModelItem::FileModelItem(CodeModel *model, int kind)
+: NamespaceModelItem(model, kind)
+{
+}
+
+FileModelItem::~FileModelItem()
+{
+}
+
+FunctionDefinitionModelItem::FunctionDefinitionModelItem(CodeModel *model, int kind)
+: FunctionModelItem(model, kind)
+{
+
+}
+
+FunctionDefinitionModelItem::~FunctionDefinitionModelItem()
+{
+
+}
+
+VariableModelItem::VariableModelItem(CodeModel *model, int kind)
+: MemberModelItem(model, kind)
+{
+
+}
+
+VariableModelItem::~VariableModelItem()
+{
+
+}
+
+// ---------------------------------------------------------------------------
+class MemberModelItemData
+{
+public:
+ ~MemberModelItemData() {
+ delete _M_type;
+ qDeleteAll(_M_templateParameters);
+ }
+ TemplateParameterList _M_templateParameters;
+ TypeInfo *_M_type;
+ CodeModel::AccessPolicy _M_accessPolicy;
+ union
+ {
+ struct
+ {
+ uint _M_isConstant: 1;
+ uint _M_isVolatile: 1;
+ uint _M_isStatic: 1;
+ uint _M_isAuto: 1;
+ uint _M_isFriend: 1;
+ uint _M_isRegister: 1;
+ uint _M_isExtern: 1;
+ uint _M_isMutable: 1;
+ };
+ uint _M_flags;
+ };
+};
+
+MemberModelItem::MemberModelItem(CodeModel *model, int kind)
+: CodeModelItem(model, kind)
+{
+ d = new MemberModelItemData();
+ d->_M_accessPolicy = CodeModel::Public;
+ d->_M_flags = 0;
+}
+
+MemberModelItem::~MemberModelItem()
+{
+ delete d;
+}
+
+TypeInfo *MemberModelItem::type() const
+{
+ return d->_M_type;
+}
+
+void MemberModelItem::setType(TypeInfo *type)
+{
+ d->_M_type = type;
+}
+
+CodeModel::AccessPolicy MemberModelItem::accessPolicy() const
+{
+ return d->_M_accessPolicy;
+}
+
+void MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
+{
+ d->_M_accessPolicy = accessPolicy;
+}
+
+bool MemberModelItem::isStatic() const
+{
+ return d->_M_isStatic;
+}
+
+void MemberModelItem::setStatic(bool isStatic)
+{
+ d->_M_isStatic = isStatic;
+}
+
+bool MemberModelItem::isConstant() const
+{
+ return d->_M_isConstant;
+}
+
+void MemberModelItem::setConstant(bool isConstant)
+{
+ d->_M_isConstant = isConstant;
+}
+
+bool MemberModelItem::isVolatile() const
+{
+ return d->_M_isVolatile;
+}
+
+void MemberModelItem::setVolatile(bool isVolatile)
+{
+ d->_M_isVolatile = isVolatile;
+}
+
+bool MemberModelItem::isAuto() const
+{
+ return d->_M_isAuto;
+}
+
+void MemberModelItem::setAuto(bool isAuto)
+{
+ d->_M_isAuto = isAuto;
+}
+
+bool MemberModelItem::isFriend() const
+{
+ return d->_M_isFriend;
+}
+
+void MemberModelItem::setFriend(bool isFriend)
+{
+ d->_M_isFriend = isFriend;
+}
+
+bool MemberModelItem::isRegister() const
+{
+ return d->_M_isRegister;
+}
+
+void MemberModelItem::setRegister(bool isRegister)
+{
+ d->_M_isRegister = isRegister;
+}
+
+bool MemberModelItem::isExtern() const
+{
+ return d->_M_isExtern;
+}
+
+void MemberModelItem::setExtern(bool isExtern)
+{
+ d->_M_isExtern = isExtern;
+}
+
+bool MemberModelItem::isMutable() const
+{
+ return d->_M_isMutable;
+}
+
+void MemberModelItem::setMutable(bool isMutable)
+{
+ d->_M_isMutable = isMutable;
+}
+
+TemplateParameterList MemberModelItem::templateParameters() const
+{
+ return d->_M_templateParameters;
+}
+
+void MemberModelItem::setTemplateParameters(const TemplateParameterList &templateParameters)
+{
+ d->_M_templateParameters = templateParameters;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/tests/manual/cppmodelmanager/codemodel/codemodelitems.h b/tests/manual/cppmodelmanager/codemodel/codemodelitems.h
new file mode 100644
index 0000000000..a2ce4f6b2e
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/codemodelitems.h
@@ -0,0 +1,527 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+Copyright (C) 2005 Trolltech AS
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CODEMODELITEMS_H
+#define CODEMODELITEMS_H
+
+#include <QtCore/QStringList>
+
+class CodeModelItem;
+class ArgumentModelItem;
+class ClassModelItem;
+class EnumModelItem;
+class EnumeratorModelItem;
+class FileModelItem;
+class FunctionDefinitionModelItem;
+class FunctionModelItem;
+class NamespaceModelItem;
+class TemplateParameterModelItem;
+class TypeAliasModelItem;
+class VariableModelItem;
+class TypeInfo;
+
+typedef QList<ArgumentModelItem*> ArgumentList;
+typedef QList<ClassModelItem*> ClassList;
+typedef QList<EnumModelItem*> EnumList;
+typedef QList<EnumeratorModelItem*> EnumeratorList;
+typedef QList<FileModelItem*> FileList;
+typedef QList<FunctionDefinitionModelItem*> FunctionDefinitionList;
+typedef QList<FunctionModelItem*> FunctionList;
+typedef QList<NamespaceModelItem*> NamespaceList;
+typedef QList<TemplateParameterModelItem*> TemplateParameterList;
+typedef QList<TypeAliasModelItem*> TypeAliasList;
+typedef QList<VariableModelItem*> VariableList;
+typedef QList<TypeInfo*> TypeInfoList;
+
+#define DECLARE_MODEL_NODE(name) \
+ enum { __node_kind = Kind_##name };
+
+
+template <class T> inline T model_cast(CodeModelItem *item) { return 0; }
+
+#define DECLARE_MODELITEM(name) \
+ template <> inline name##ModelItem *model_cast<##name##ModelItem *>(CodeModelItem *item) { \
+ if (item && item->kind() == CodeModelItem::Kind_##name) \
+ return static_cast<##name##ModelItem *>(item); \
+ return 0; }
+
+class CodeModel
+{
+public:
+ enum AccessPolicy
+ {
+ Public,
+ Protected,
+ Private
+ };
+
+ enum FunctionType
+ {
+ Normal,
+ Signal,
+ Slot
+ };
+
+ enum ClassType
+ {
+ Class,
+ Struct,
+ Union
+ };
+
+public:
+ virtual ~CodeModel();
+
+/* virtual FileList files() const = 0;
+ virtual NamespaceModelItem *globalNamespace() const = 0; */
+};
+
+class TypeInfo
+{
+public:
+ TypeInfo(): flags (0) {}
+ virtual ~TypeInfo() { qDeleteAll(m_arguments); }
+
+ QString qualifiedName() const { return m_qualifiedName; }
+ void setQualifiedName(const QString &qualified_name) { m_qualifiedName = qualified_name; }
+
+ bool isConstant() const { return m_constant; }
+ void setConstant(bool is) { m_constant = is; }
+
+ bool isVolatile() const { return m_volatile; }
+ void setVolatile(bool is) { m_volatile = is; }
+
+ bool isReference() const { return m_reference; }
+ void setReference(bool is) { m_reference = is; }
+
+ int indirections() const { return m_indirections; }
+ void setIndirections(int indirections) { m_indirections = indirections; }
+
+ bool isFunctionPointer() const { return m_functionPointer; }
+ void setFunctionPointer(bool is) { m_functionPointer = is; }
+
+ QStringList arrayElements() const { return m_arrayElements; }
+ void setArrayElements(const QStringList &arrayElements) { m_arrayElements = arrayElements; }
+
+ TypeInfoList arguments() const { return m_arguments; }
+ void addArgument(TypeInfo *arg) { m_arguments.append(arg); }
+
+ bool operator==(const TypeInfo &other);
+ bool operator!=(const TypeInfo &other) { return !(*this==other); }
+
+private:
+ union
+ {
+ uint flags;
+
+ struct
+ {
+ uint m_constant: 1;
+ uint m_volatile: 1;
+ uint m_reference: 1;
+ uint m_functionPointer: 1;
+ uint m_indirections: 6;
+ uint m_padding: 22;
+ };
+ };
+
+ QString m_qualifiedName;
+ QStringList m_arrayElements;
+ TypeInfoList m_arguments;
+};
+
+class CodeModelItemData;
+class CodeModelItem
+{
+public:
+ enum Kind
+ {
+ /* These are bit-flags resembling inheritance */
+ Kind_Scope = 0x1,
+ Kind_Namespace = 0x2 | Kind_Scope,
+ Kind_Member = 0x4,
+ Kind_Function = 0x8 | Kind_Member,
+ KindMask = 0xf,
+
+ /* These are for classes that are not inherited from */
+ FirstKind = 0x8,
+ Kind_Argument = 1 << FirstKind,
+ Kind_Class = 2 << FirstKind | Kind_Scope,
+ Kind_Enum = 3 << FirstKind,
+ Kind_Enumerator = 4 << FirstKind,
+ Kind_File = 5 << FirstKind | Kind_Namespace,
+ Kind_FunctionDefinition = 6 << FirstKind | Kind_Function,
+ Kind_TemplateParameter = 7 << FirstKind,
+ Kind_TypeAlias = 8 << FirstKind,
+ Kind_Variable = 9 << FirstKind | Kind_Member
+ };
+
+ CodeModelItem(CodeModel *model, int kind);
+ CodeModelItem(const CodeModelItem &item);
+ virtual ~CodeModelItem();
+
+ int kind() const;
+
+ QString qualifiedName() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString scope() const;
+ void setScope(const QString &scope);
+
+ void setFile(FileModelItem *file);
+ FileModelItem *file() const;
+
+ void startPosition(int *line, int *column);
+ void setStartPosition(int line, int column);
+
+ void endPosition(int *line, int *column);
+ void setEndPosition(int line, int column);
+
+ std::size_t creationId() const;
+ void setCreationId(std::size_t creation_id);
+
+ CodeModel *model() const;
+
+protected:
+ void setKind(int kind);
+
+private:
+ CodeModelItemData *d;
+};
+
+class ScopeModelItemData;
+class ScopeModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Scope)
+ ScopeModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~ScopeModelItem();
+
+ void addClass(ClassModelItem *item);
+ void addEnum(EnumModelItem *item);
+ void addFunction(FunctionModelItem *item);
+ void addFunctionDefinition(FunctionDefinitionModelItem *item);
+ void addTypeAlias(TypeAliasModelItem *item);
+ void addVariable(VariableModelItem *item);
+
+private:
+ ScopeModelItemData *d;
+};
+DECLARE_MODELITEM(Scope)
+
+class ClassModelItemData;
+class ClassModelItem: public ScopeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Class)
+ ClassModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~ClassModelItem();
+
+ QStringList baseClasses() const;
+
+ void setBaseClasses(const QStringList &baseClasses);
+ void addBaseClass(const QString &baseClass);
+
+ TemplateParameterList templateParameters() const;
+ void setTemplateParameters(const TemplateParameterList &templateParameters);
+
+ bool extendsClass(const QString &name) const;
+
+ void setClassType(CodeModel::ClassType type);
+ CodeModel::ClassType classType() const;
+
+private:
+ ClassModelItemData *d;
+};
+DECLARE_MODELITEM(Class)
+
+class NamespaceModelItemData;
+class NamespaceModelItem: public ScopeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Namespace)
+ NamespaceModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~NamespaceModelItem();
+
+ NamespaceList namespaces() const;
+ void addNamespace(NamespaceModelItem *item);
+ NamespaceModelItem *findNamespace(const QString &name) const;
+
+private:
+ NamespaceModelItemData *d;
+};
+DECLARE_MODELITEM(Namespace)
+
+class FileModelItem: public NamespaceModelItem
+{
+public:
+ DECLARE_MODEL_NODE(File)
+ FileModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~FileModelItem();
+};
+DECLARE_MODELITEM(File)
+
+class ArgumentModelItemData;
+class ArgumentModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Argument)
+ ArgumentModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~ArgumentModelItem();
+
+public:
+ TypeInfo *type() const;
+ void setType(TypeInfo *type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+ QString defaultValueExpression() const;
+ void setDefaultValueExpression(const QString &expr);
+
+private:
+ ArgumentModelItemData *d;
+};
+DECLARE_MODELITEM(Argument)
+
+class MemberModelItemData;
+class MemberModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Member)
+ MemberModelItem(CodeModel *model, int kind);
+ virtual ~MemberModelItem();
+
+ bool isConstant() const;
+ void setConstant(bool isConstant);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isStatic() const;
+ void setStatic(bool isStatic);
+
+ bool isAuto() const;
+ void setAuto(bool isAuto);
+
+ bool isFriend() const;
+ void setFriend(bool isFriend);
+
+ bool isRegister() const;
+ void setRegister(bool isRegister);
+
+ bool isExtern() const;
+ void setExtern(bool isExtern);
+
+ bool isMutable() const;
+ void setMutable(bool isMutable);
+
+ CodeModel::AccessPolicy accessPolicy() const;
+ void setAccessPolicy(CodeModel::AccessPolicy accessPolicy);
+
+ TemplateParameterList templateParameters() const;
+ void setTemplateParameters(const TemplateParameterList &templateParameters);
+
+ TypeInfo *type() const;
+ void setType(TypeInfo *type);
+
+private:
+ MemberModelItemData *d;
+};
+DECLARE_MODELITEM(Member)
+
+class FunctionModelItemData;
+class FunctionModelItem: public MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Function)
+ FunctionModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~FunctionModelItem();
+
+ ArgumentList arguments() const;
+
+ void addArgument(ArgumentModelItem *item);
+
+ CodeModel::FunctionType functionType() const;
+ void setFunctionType(CodeModel::FunctionType functionType);
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ bool isInline() const;
+ void setInline(bool isInline);
+
+ bool isExplicit() const;
+ void setExplicit(bool isExplicit);
+
+ bool isAbstract() const;
+ void setAbstract(bool isAbstract);
+
+ bool isVariadics() const;
+ void setVariadics(bool isVariadics);
+
+ bool isSimilar(FunctionModelItem *other) const;
+
+private:
+ FunctionModelItemData *d;
+};
+DECLARE_MODELITEM(Function)
+
+class FunctionDefinitionModelItem: public FunctionModelItem
+{
+public:
+ DECLARE_MODEL_NODE(FunctionDefinition)
+ FunctionDefinitionModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~FunctionDefinitionModelItem();
+};
+DECLARE_MODELITEM(FunctionDefinition)
+
+class VariableModelItem: public MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Variable)
+ VariableModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~VariableModelItem();
+};
+DECLARE_MODELITEM(Variable)
+
+class TypeAliasModelItemData;
+class TypeAliasModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TypeAlias)
+ TypeAliasModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~TypeAliasModelItem();
+
+ TypeInfo *type() const;
+ void setType(TypeInfo *type);
+
+private:
+ TypeAliasModelItemData *d;
+};
+DECLARE_MODELITEM(TypeAlias)
+
+class EnumModelItemData;
+class EnumModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Enum)
+ EnumModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~EnumModelItem();
+
+ CodeModel::AccessPolicy accessPolicy() const;
+ void setAccessPolicy(CodeModel::AccessPolicy accessPolicy);
+
+ EnumeratorList enumerators() const;
+ void addEnumerator(EnumeratorModelItem *item);
+
+private:
+ EnumModelItemData *d;
+};
+DECLARE_MODELITEM(Enum)
+
+class EnumeratorModelItemData;
+class EnumeratorModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Enumerator)
+ EnumeratorModelItem(CodeModel *model, int kind = __node_kind);
+ virtual ~EnumeratorModelItem();
+
+ QString value() const;
+ void setValue(const QString &value);
+
+private:
+ EnumeratorModelItemData *d;
+};
+DECLARE_MODELITEM(Enumerator)
+
+class TemplateParameterModelItemData;
+class TemplateParameterModelItem: public CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TemplateParameter)
+ TemplateParameterModelItem(CodeModel *model, int kind = __node_kind);
+ TemplateParameterModelItem(const TemplateParameterModelItem& item);
+ virtual ~TemplateParameterModelItem();
+
+ TypeInfo *type() const;
+ void setType(TypeInfo *type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+private:
+ TemplateParameterModelItemData *d;
+};
+DECLARE_MODELITEM(TemplateParameter)
+
+// ### todo, check language
+#define DECLARE_LANGUAGE_MODELITEM(name, language) \
+ template <> inline language##name##ModelItem *model_cast<##language##name##ModelItem *>(CodeModelItem *item) { \
+ if (item && item->kind() == CodeModelItem::Kind_##name) \
+ return static_cast<##language##name##ModelItem *>(item); \
+ return 0; }
+
+// ### todo, check language
+template <class T> inline T model_cast(CodeModel *item) { return 0; }
+
+#define DECLARE_LANGUAGE_CODEMODEL(language) \
+ template <> inline language##CodeModel *model_cast<##language##CodeModel *>(CodeModel *item) { \
+ return item ? static_cast<##language##CodeModel *>(item) : 0; }
+
+#endif //CODEMODELITEMS_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/compiler_utils.cpp b/tests/manual/cppmodelmanager/codemodel/compiler_utils.cpp
new file mode 100644
index 0000000000..3243825449
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/compiler_utils.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "compiler_utils.h"
+#include "type_compiler.h"
+#include "name_compiler.h"
+#include "declarator_compiler.h"
+#include "ast.h"
+#include "binder.h"
+
+TypeInfo *CompilerUtils::typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder)
+{
+ TypeCompiler type_cc (binder);
+ DeclaratorCompiler decl_cc (binder);
+
+ type_cc.run (type_specifier);
+ decl_cc.run (declarator);
+
+ TypeInfo *typeInfo = new TypeInfo();
+ typeInfo->setQualifiedName (type_cc.qualifiedName ());
+ typeInfo->setConstant (type_cc.isConstant ());
+ typeInfo->setVolatile (type_cc.isVolatile ());
+ typeInfo->setReference (decl_cc.isReference ());
+ typeInfo->setIndirections (decl_cc.indirection ());
+ typeInfo->setArrayElements (decl_cc.arrayElements ());
+
+ return typeInfo;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/compiler_utils.h b/tests/manual/cppmodelmanager/codemodel/compiler_utils.h
new file mode 100644
index 0000000000..3b42164d63
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/compiler_utils.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef COMPILER_UTILS_H
+#define COMPILER_UTILS_H
+
+struct TypeSpecifierAST;
+struct DeclaratorAST;
+class Binder;
+class TypeInfo;
+
+namespace CompilerUtils
+{
+
+TypeInfo *typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder);
+
+} // namespace CompilerUtils
+
+#endif // COMPILER_UTILS_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/declarator_compiler.cpp b/tests/manual/cppmodelmanager/codemodel/declarator_compiler.cpp
new file mode 100644
index 0000000000..a30286af64
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/declarator_compiler.cpp
@@ -0,0 +1,168 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "declarator_compiler.h"
+#include "name_compiler.h"
+#include "type_compiler.h"
+#include "compiler_utils.h"
+#include "lexer.h"
+#include "binder.h"
+
+#include <qdebug.h>
+
+DeclaratorCompiler::DeclaratorCompiler(Binder *binder)
+ : _M_binder (binder), _M_token_stream (binder->tokenStream ())
+{
+}
+
+void DeclaratorCompiler::run(DeclaratorAST *node)
+{
+ _M_id.clear();
+ _M_parameters.clear();
+ _M_array.clear();
+ _M_function = false;
+ _M_reference = false;
+ _M_variadics = false;
+ _M_indirection = 0;
+
+ if (node)
+ {
+ NameCompiler name_cc(_M_binder);
+
+ DeclaratorAST *decl = node;
+ while (decl && decl->sub_declarator)
+ decl = decl->sub_declarator;
+
+ Q_ASSERT (decl != 0);
+
+ name_cc.run(decl->id);
+ _M_id = name_cc.qualifiedName();
+ _M_function = (node->parameter_declaration_clause != 0);
+ if (node->parameter_declaration_clause && node->parameter_declaration_clause->ellipsis)
+ _M_variadics = true;
+
+ visitNodes(this, node->ptr_ops);
+ visit(node->parameter_declaration_clause);
+
+ if (const ListNode<ExpressionAST*> *it = node->array_dimensions)
+ {
+ it->toFront();
+ const ListNode<ExpressionAST*> *end = it;
+
+ do
+ {
+ QString elt;
+ if (ExpressionAST *expr = it->element)
+ {
+ const Token &start_token = _M_token_stream->token((int) expr->start_token);
+ const Token &end_token = _M_token_stream->token((int) expr->end_token);
+
+ elt += QString::fromUtf8(&start_token.text[start_token.position],
+ (int) (end_token.position - start_token.position)).trimmed();
+ }
+
+ _M_array.append (elt);
+
+ it = it->next;
+ }
+ while (it != end);
+ }
+ }
+}
+
+void DeclaratorCompiler::visitPtrOperator(PtrOperatorAST *node)
+{
+ std::size_t op = _M_token_stream->kind(node->op);
+
+ switch (op)
+ {
+ case '&':
+ _M_reference = true;
+ break;
+ case '*':
+ ++_M_indirection;
+ break;
+
+ default:
+ break;
+ }
+
+ if (node->mem_ptr)
+ {
+#if defined(__GNUC__)
+#warning "ptr to mem -- not implemented"
+#endif
+ }
+}
+
+void DeclaratorCompiler::visitParameterDeclaration(ParameterDeclarationAST *node)
+{
+ Parameter p;
+
+ TypeCompiler type_cc(_M_binder);
+ DeclaratorCompiler decl_cc(_M_binder);
+
+ decl_cc.run(node->declarator);
+
+ p.name = decl_cc.id();
+ p.type = CompilerUtils::typeDescription(node->type_specifier, node->declarator, _M_binder);
+ if (node->expression != 0)
+ {
+ p.defaultValue = true;
+ const Token &start = _M_token_stream->token((int) node->expression->start_token);
+ const Token &end = _M_token_stream->token((int) node->expression->end_token);
+ int length = (int) (end.position - start.position);
+ p.defaultValueExpression = QString::fromUtf8(&start.text[start.position], length).trimmed();
+ }
+
+ _M_parameters.append(p);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/declarator_compiler.h b/tests/manual/cppmodelmanager/codemodel/declarator_compiler.h
new file mode 100644
index 0000000000..d715c1ec05
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/declarator_compiler.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DECLARATOR_COMPILER_H
+#define DECLARATOR_COMPILER_H
+
+#include "default_visitor.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+
+class TokenStream;
+class Binder;
+class TypeInfo;
+
+class DeclaratorCompiler: protected DefaultVisitor
+{
+public:
+ struct Parameter
+ {
+ TypeInfo *type;
+ QString name;
+ QString defaultValueExpression;
+ bool defaultValue;
+
+ Parameter(): defaultValue(false) {}
+ };
+
+public:
+ DeclaratorCompiler(Binder *binder);
+
+ void run(DeclaratorAST *node);
+
+ inline QString id() const { return _M_id; }
+ inline QStringList arrayElements() const { return _M_array; }
+ inline bool isFunction() const { return _M_function; }
+ inline bool isVariadics() const { return _M_variadics; }
+ inline bool isReference() const { return _M_reference; }
+ inline int indirection() const { return _M_indirection; }
+ inline QList<Parameter> parameters() const { return _M_parameters; }
+
+protected:
+ virtual void visitPtrOperator(PtrOperatorAST *node);
+ virtual void visitParameterDeclaration(ParameterDeclarationAST *node);
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+
+ bool _M_function;
+ bool _M_reference;
+ bool _M_variadics;
+ int _M_indirection;
+ QString _M_id;
+ QStringList _M_array;
+ QList<Parameter> _M_parameters;
+};
+
+#endif // DECLARATOR_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/name_compiler.cpp b/tests/manual/cppmodelmanager/codemodel/name_compiler.cpp
new file mode 100644
index 0000000000..a85d9969b5
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/name_compiler.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright (C) 2005 Trolltech
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "name_compiler.h"
+#include "type_compiler.h"
+#include "declarator_compiler.h"
+#include "lexer.h"
+#include "symbol.h"
+#include "binder.h"
+
+#include <QtCore/qdebug.h>
+
+NameCompiler::NameCompiler(Binder *binder)
+ : _M_binder (binder), _M_token_stream (binder->tokenStream ())
+{
+}
+
+QString NameCompiler::decode_operator(std::size_t index) const
+{
+ const Token &tk = _M_token_stream->token((int) index);
+ return QString::fromUtf8(&tk.text[tk.position], (int) tk.size);
+}
+
+void NameCompiler::internal_run(AST *node)
+{
+ _M_name.clear();
+ visit(node);
+}
+
+void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node)
+{
+ QString tmp_name;
+
+ if (node->tilde)
+ tmp_name += QLatin1String("~");
+
+ if (node->id)
+ tmp_name += _M_token_stream->symbol(node->id)->as_string();
+
+ if (OperatorFunctionIdAST *op_id = node->operator_id)
+ {
+#if defined(__GNUC__)
+#warning "NameCompiler::visitUnqualifiedName() -- implement me"
+#endif
+
+ if (op_id->op && op_id->op->op)
+ {
+ tmp_name += QLatin1String("operator");
+ tmp_name += decode_operator(op_id->op->op);
+ if (op_id->op->close)
+ tmp_name += decode_operator(op_id->op->close);
+ }
+ else if (op_id->type_specifier)
+ {
+#if defined(__GNUC__)
+#warning "don't use an hardcoded string as cast' name"
+#endif
+ Token const &tk = _M_token_stream->token ((int) op_id->start_token);
+ Token const &end_tk = _M_token_stream->token ((int) op_id->end_token);
+ tmp_name += QString::fromLatin1 (&tk.text[tk.position],
+ (int) (end_tk.position - tk.position)).trimmed ();
+ }
+ }
+
+ if (!_M_name.isEmpty())
+ _M_name += QLatin1String("::");
+ _M_name += tmp_name;
+
+ if (node->template_arguments)
+ {
+ _M_name += QLatin1String("<");
+ visitNodes(this, node->template_arguments);
+ _M_name.truncate(_M_name.count() - 1); // remove the last ','
+ _M_name += QLatin1String(">");
+ }
+}
+
+void NameCompiler::visitTemplateArgument(TemplateArgumentAST *node)
+{
+ if (node->type_id && node->type_id->type_specifier)
+ {
+ TypeCompiler type_cc(_M_binder);
+ type_cc.run(node->type_id->type_specifier);
+
+ DeclaratorCompiler decl_cc(_M_binder);
+ decl_cc.run(node->type_id->declarator);
+
+ if (type_cc.isConstant())
+ _M_name += "const ";
+
+ _M_name += type_cc.qualifiedName ();
+
+ if (decl_cc.isReference())
+ _M_name += "&";
+ if (decl_cc.indirection())
+ _M_name += QString(decl_cc.indirection(), '*');
+
+ _M_name += QLatin1String(",");
+ }
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/name_compiler.h b/tests/manual/cppmodelmanager/codemodel/name_compiler.h
new file mode 100644
index 0000000000..5d61e316bd
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/name_compiler.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef NAME_COMPILER_H
+#define NAME_COMPILER_H
+
+#include "default_visitor.h"
+#include <QtCore/QString>
+
+class TokenStream;
+class Binder;
+
+class NameCompiler: protected DefaultVisitor
+{
+public:
+ NameCompiler(Binder *binder);
+
+ void run(NameAST *node) { internal_run(node); }
+ void run(UnqualifiedNameAST *node) { internal_run(node); }
+
+ QString qualifiedName() const { return _M_name; }
+
+protected:
+ virtual void visitUnqualifiedName(UnqualifiedNameAST *node);
+ virtual void visitTemplateArgument(TemplateArgumentAST *node);
+
+ void internal_run(AST *node);
+ QString decode_operator(std::size_t index) const;
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ QString _M_name;
+};
+
+#endif // NAME_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/type_compiler.cpp b/tests/manual/cppmodelmanager/codemodel/type_compiler.cpp
new file mode 100644
index 0000000000..05708c9c94
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/type_compiler.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright (C) 2005 Trolltech AS
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "type_compiler.h"
+#include "name_compiler.h"
+#include "lexer.h"
+#include "symbol.h"
+#include "tokens.h"
+#include "binder.h"
+
+#include <QtCore/QString>
+
+TypeCompiler::TypeCompiler(Binder *binder)
+ : _M_binder (binder), _M_token_stream(binder->tokenStream ())
+{
+}
+
+void TypeCompiler::run(TypeSpecifierAST *node)
+{
+ _M_type.clear();
+ _M_cv.clear();
+
+ visit(node);
+
+ if (node && node->cv)
+ {
+ const ListNode<std::size_t> *it = node->cv->toFront();
+ const ListNode<std::size_t> *end = it;
+ do
+ {
+ int kind = _M_token_stream->kind(it->element);
+ if (! _M_cv.contains(kind))
+ _M_cv.append(kind);
+
+ it = it->next;
+ }
+ while (it != end);
+ }
+}
+
+void TypeCompiler::visitClassSpecifier(ClassSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void TypeCompiler::visitEnumSpecifier(EnumSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void TypeCompiler::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node)
+{
+ visit(node->name);
+}
+
+void TypeCompiler::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node)
+{
+ if (const ListNode<std::size_t> *it = node->integrals)
+ {
+ it = it->toFront();
+ const ListNode<std::size_t> *end = it;
+ QString current_item;
+ do
+ {
+ std::size_t token = it->element;
+ current_item += token_name(_M_token_stream->kind(token));
+ current_item += " ";
+ it = it->next;
+ }
+ while (it != end);
+ if (!_M_type.isEmpty())
+ _M_type += QLatin1String("::");
+ _M_type += current_item.trimmed();
+ }
+ else if (node->type_of)
+ {
+ // ### implement me
+
+ if (!_M_type.isEmpty())
+ _M_type += QLatin1String("::");
+ _M_type += QLatin1String("typeof<...>");
+ }
+
+ visit(node->name);
+}
+
+void TypeCompiler::visitName(NameAST *node)
+{
+ NameCompiler name_cc(_M_binder);
+ name_cc.run(node);
+ _M_type = name_cc.qualifiedName();
+}
+
+QStringList TypeCompiler::cvString() const
+{
+ QStringList lst;
+
+ foreach (int q, cv())
+ {
+ if (q == Token_const)
+ lst.append(QLatin1String("const"));
+ else if (q == Token_volatile)
+ lst.append(QLatin1String("volatile"));
+ }
+
+ return lst;
+}
+
+bool TypeCompiler::isConstant() const
+{
+ return _M_cv.contains(Token_const);
+}
+
+bool TypeCompiler::isVolatile() const
+{
+ return _M_cv.contains(Token_volatile);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/codemodel/type_compiler.h b/tests/manual/cppmodelmanager/codemodel/type_compiler.h
new file mode 100644
index 0000000000..43231354e0
--- /dev/null
+++ b/tests/manual/cppmodelmanager/codemodel/type_compiler.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* This file is part of KDevelop
+ Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef TYPE_COMPILER_H
+#define TYPE_COMPILER_H
+
+#include "default_visitor.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+
+class TokenStream;
+class Binder;
+
+class TypeCompiler: protected DefaultVisitor
+{
+public:
+ TypeCompiler(Binder *binder);
+
+ inline QString qualifiedName() const { return _M_type; }
+ inline QList<int> cv() const { return _M_cv; }
+
+ bool isConstant() const;
+ bool isVolatile() const;
+
+ QStringList cvString() const;
+
+ void run(TypeSpecifierAST *node);
+
+protected:
+ virtual void visitClassSpecifier(ClassSpecifierAST *node);
+ virtual void visitEnumSpecifier(EnumSpecifierAST *node);
+ virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node);
+ virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node);
+
+ virtual void visitName(NameAST *node);
+
+private:
+ Binder *_M_binder;
+ TokenStream *_M_token_stream;
+ QString _M_type;
+ QList<int> _M_cv;
+};
+
+#endif // TYPE_COMPILER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/cppcodemodel.cpp b/tests/manual/cppmodelmanager/cppcodemodel.cpp
new file mode 100644
index 0000000000..cdfbb6a996
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppcodemodel.cpp
@@ -0,0 +1,204 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+#include "cppcodemodelitems.h"
+#include "cpppartparser.h"
+#include "cppcodemodel.h"
+#include "cppcodemodelpart.h"
+
+CppCodeModel::CppCodeModel(const QByteArray &configuration, QObject *parent)
+ : QObject(parent)
+{
+ m_configuration = configuration;
+ m_parsefiles << QLatin1String("<configfile>");
+}
+
+CppCodeModel::~CppCodeModel()
+{
+
+}
+
+void CppCodeModel::addIncludePath(const QString &path)
+{
+ QString newpath = QDir::cleanPath(path);
+ if (m_includedirs.contains(newpath))
+ return;
+
+ m_includedirs.insert(newpath, new CppCodeModelPart(newpath, this));
+}
+
+void CppCodeModel::removeIncludePath(const QString &path)
+{
+ QString newpath = QDir::cleanPath(path + QLatin1Char('/'));
+ if (!m_includedirs.contains(newpath))
+ return;
+
+ delete m_includedirs.take(newpath);
+}
+
+void CppCodeModel::update(const QStringList &files)
+{
+ m_parsefiles += m_parsefiles.fromList(files);
+
+ CppPartParser *parser = CppPartParser::instance(parent());
+ parser->parse(this);
+}
+
+QStringList CppCodeModel::needsParsing()
+{
+ QStringList result = m_parsefiles.toList();
+
+ if (m_parsefiles.contains(QLatin1String("<configfile>")))
+ result.prepend(QLatin1String("<configfile>"));
+
+ m_parsefiles.clear();
+ return result;
+}
+
+void CppCodeModel::resolvePart(const QString &abspath, CppCodeModelPart **part) const
+{
+ int length = 0;
+
+ QMap<QString, CppCodeModelPart *>::const_iterator i = m_includedirs.constBegin();
+ while (i != m_includedirs.constEnd()) {
+ if (abspath.startsWith(i.key()) && i.key().count() > length) {
+ length = i.key().count();
+ (*part) = i.value();
+ }
+ ++i;
+ }
+}
+
+void CppCodeModel::resolveGlobalPath(QString &file, CppCodeModelPart **part) const
+{
+ QString abspath;
+
+ (*part) = 0;
+ QMap<QString, CppCodeModelPart *>::const_iterator i = m_includedirs.constBegin();
+ while (i != m_includedirs.constEnd()) {
+ abspath = i.key() + QLatin1Char('/') + file;
+ QFileInfo fi(abspath);
+ if (fi.exists() && fi.isFile()) {
+ (*part) = i.value();
+ break;
+ }
+ ++i;
+ }
+
+ if (*part)
+ file = QDir::cleanPath(abspath);
+}
+
+void CppCodeModel::resolveLocalPath(QString &file, const QString &local, CppCodeModelPart **part) const
+{
+ (*part) = m_partcache.value(local, 0);
+ QFileInfo fi(local);
+ file = QDir::cleanPath(fi.absolutePath() + QLatin1Char('/') + file);
+}
+
+QByteArray *CppCodeModel::contents(QString &file, const QString &local)
+{
+ CppCodeModelPart *part = 0;
+
+ if (file == QLatin1String("<configfile>"))
+ return new QByteArray(m_configuration);
+
+ if (local.isEmpty()) {
+ resolveGlobalPath(file, &part);
+ if (!m_partcache.contains(file)) {
+ resolvePart(file, &part);
+ m_partcache.insert(file, part);
+ } else {
+ part = m_partcache.value(file, 0);
+ }
+ } else {
+ resolveLocalPath(file, local, &part);
+ m_partcache.insert(file, part);
+ }
+
+ if (!part) {
+ qDebug() << "Didn't find: " << file;
+ return 0;
+ }
+
+ return part->contents(file);
+}
+
+QHash<QString, pp_macro*> *CppCodeModel::macros()
+{
+ return &m_macros;
+}
+
+void CppCodeModel::store()
+{
+ QMap<QString, CppFileModelItem *>::const_iterator i = m_fileitems.constBegin();
+ while (i != m_fileitems.constEnd()) {
+ if (CppCodeModelPart *part = m_partcache.value(i.key()))
+ part->store(i.value());
+ ++i;
+ }
+
+ m_partcache.clear();
+ m_fileitems.clear();
+}
+
+CppFileModelItem *CppCodeModel::fileItem(const QString &name)
+{
+ if (!m_partcache.contains(name))
+ return 0;
+
+ if (m_fileitems.contains(name))
+ return m_fileitems.value(name);
+
+ CppFileModelItem *item = new CppFileModelItem(this);
+ item->setPart(m_partcache.value(name));
+ item->setName(name);
+ item->setFile(item);
+ m_fileitems.insert(name, item);
+ return item;
+}
+
+bool CppCodeModel::hasScope(const QString &name) const
+{
+ QMap<QString, CppCodeModelPart *>::const_iterator i = m_includedirs.constBegin();
+ while (i != m_includedirs.constEnd()) {
+ if (i.value()->hasScope(name))
+ return true;
+ ++i;
+ }
+ return false;
+}
+
diff --git a/tests/manual/cppmodelmanager/cppcodemodel.h b/tests/manual/cppmodelmanager/cppcodemodel.h
new file mode 100644
index 0000000000..7f591b17e4
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppcodemodel.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPCODEMODEL_H
+#define CPPCODEMODEL_H
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+
+#include "cppcodemodelitems.h"
+
+class pp_macro;
+class CppCodeModelPart;
+class CppPartParser;
+class CppPartPP;
+
+class CppCodeModel : public QObject,
+ public CodeModel
+{
+ Q_OBJECT
+
+public:
+ CppCodeModel(const QByteArray &configuration, QObject *parent = 0);
+ ~CppCodeModel();
+
+ void addIncludePath(const QString &path);
+ void removeIncludePath(const QString &path);
+
+ void update(const QStringList &files);
+
+protected:
+ // returns the macros for this part
+ QStringList needsParsing();
+ QHash<QString, pp_macro*> *macros();
+ QByteArray *contents(QString &file, const QString &local = QString());
+ void store();
+
+ void resolvePart(const QString &abspath, CppCodeModelPart **part) const;
+ void resolveGlobalPath(QString &file, CppCodeModelPart **part) const;
+ void resolveLocalPath(QString &file, const QString &local, CppCodeModelPart **part) const;
+
+ // used by the parser
+ CppFileModelItem *fileItem(const QString &name);
+ bool hasScope(const QString &name) const;
+
+private:
+ QMap<QString, CppCodeModelPart *> m_partcache;
+ QMap<QString, CppFileModelItem *> m_fileitems;
+ QMap<QString, CppCodeModelPart *> m_includedirs;
+
+ QByteArray m_configuration;
+ QSet<QString> m_parsefiles;
+ QHash<QString, pp_macro*> m_macros;
+
+ friend class Binder;
+ friend class CodeModelFinder;
+ friend class CppPartParser;
+ friend class CppPartPP;
+};
+DECLARE_LANGUAGE_CODEMODEL(Cpp)
+
+#endif // CPPCODEMODELPART_H
diff --git a/tests/manual/cppmodelmanager/cppcodemodelitems.cpp b/tests/manual/cppmodelmanager/cppcodemodelitems.cpp
new file mode 100644
index 0000000000..cb8aac652b
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppcodemodelitems.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+Copyright (C) 2005 Trolltech AS
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#include <QtCore/QHash>
+#include "cppcodemodelitems.h"
+#include "cppcodemodel.h"
+
+CppClassModelItem::CppClassModelItem(CppCodeModel *model)
+ : ClassModelItem(model) { }
+
+CppFileModelItem::CppFileModelItem(CppCodeModel *model)
+ : FileModelItem(model)
+{
+
+}
+
+CppFileModelItem::~CppFileModelItem()
+{
+ qDeleteAll(_M_externalscopes.values());
+}
+
+void CppFileModelItem::setPart(CppCodeModelPart *part)
+{
+ _M_part = part;
+}
+
+CppCodeModelPart *CppFileModelItem::part() const
+{
+ return _M_part;
+}
+
+ScopeModelItem *CppFileModelItem::findExternalScope(const QString &name) const
+{
+ return _M_externalscopes.value(name, 0);
+}
+
+void CppFileModelItem::addExternalScope(ScopeModelItem *item)
+{
+ _M_externalscopes.insert(item->qualifiedName(), item);
+}
+
+QList<ScopeModelItem* > CppFileModelItem::externalScopes() const
+{
+ return _M_externalscopes.values();
+}
+
+CppArgumentModelItem::CppArgumentModelItem(CppCodeModel *model)
+: ArgumentModelItem(model) { }
+
+CppFunctionDefinitionModelItem::CppFunctionDefinitionModelItem(CppCodeModel *model)
+: FunctionDefinitionModelItem(model) { }
+
+CppVariableModelItem::CppVariableModelItem(CppCodeModel *model)
+: VariableModelItem(model) { }
+
+CppTypeAliasModelItem::CppTypeAliasModelItem(CppCodeModel *model)
+: TypeAliasModelItem(model) { }
+
+CppEnumModelItem::CppEnumModelItem(CppCodeModel *model)
+: EnumModelItem(model) { }
+
+CppEnumeratorModelItem::CppEnumeratorModelItem(CppCodeModel *model)
+: EnumeratorModelItem(model) { }
+
+CppTemplateParameterModelItem::CppTemplateParameterModelItem(CppCodeModel *model)
+: TemplateParameterModelItem(model) { }
+
+CppTemplateParameterModelItem::CppTemplateParameterModelItem(const CppTemplateParameterModelItem &item)
+: TemplateParameterModelItem(item) { }
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/tests/manual/cppmodelmanager/cppcodemodelitems.h b/tests/manual/cppmodelmanager/cppcodemodelitems.h
new file mode 100644
index 0000000000..7d80363abb
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppcodemodelitems.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file is part of KDevelop
+Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+Copyright (C) 2005 Trolltech AS
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License version 2 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CPPCODEMODELITEMS_H
+#define CPPCODEMODELITEMS_H
+
+class CppCodeModel;
+class CppCodeModelPart;
+#include "codemodel/codemodelitems.h"
+
+class CppClassModelItem: public ClassModelItem
+{
+public:
+ CppClassModelItem(CppCodeModel *model);
+};
+
+class CppFileModelItem: public FileModelItem
+{
+public:
+ CppFileModelItem(CppCodeModel *model);
+ ~CppFileModelItem();
+
+ void setPart(CppCodeModelPart *part);
+ CppCodeModelPart *part() const;
+
+ ScopeModelItem *findExternalScope(const QString &name) const;
+ void addExternalScope(ScopeModelItem *item);
+ QList<ScopeModelItem *> externalScopes() const;
+
+private:
+ QHash<QString, ScopeModelItem *> _M_externalscopes;
+ CppCodeModelPart *_M_part;
+};
+DECLARE_LANGUAGE_MODELITEM(File, Cpp)
+
+class CppArgumentModelItem: public ArgumentModelItem
+{
+public:
+ CppArgumentModelItem(CppCodeModel *model);
+};
+DECLARE_LANGUAGE_MODELITEM(Argument, Cpp)
+
+class CppFunctionDefinitionModelItem : public FunctionDefinitionModelItem
+{
+public:
+ CppFunctionDefinitionModelItem(CppCodeModel *model);
+};
+DECLARE_LANGUAGE_MODELITEM(FunctionDefinition, Cpp)
+
+class CppVariableModelItem : public VariableModelItem
+{
+public:
+ CppVariableModelItem(CppCodeModel *model);
+};
+DECLARE_LANGUAGE_MODELITEM(Variable, Cpp)
+
+class CppTypeAliasModelItem : public TypeAliasModelItem
+{
+public:
+ CppTypeAliasModelItem(CppCodeModel *model);
+};
+DECLARE_LANGUAGE_MODELITEM(TypeAlias, Cpp)
+
+class CppEnumModelItem : public EnumModelItem
+{
+public:
+ CppEnumModelItem(CppCodeModel *model);
+};
+DECLARE_LANGUAGE_MODELITEM(Enum, Cpp)
+
+class CppEnumeratorModelItem : public EnumeratorModelItem
+{
+public:
+ CppEnumeratorModelItem(CppCodeModel *model);
+};
+DECLARE_LANGUAGE_MODELITEM(Enumerator, Cpp)
+
+class CppTemplateParameterModelItem : public TemplateParameterModelItem
+{
+public:
+ CppTemplateParameterModelItem(CppCodeModel *model);
+ CppTemplateParameterModelItem(const CppTemplateParameterModelItem &item);
+};
+DECLARE_LANGUAGE_MODELITEM(TemplateParameter, Cpp)
+
+#endif //CPPCODEMODELITEMS_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tests/manual/cppmodelmanager/cppcodemodelpart.cpp b/tests/manual/cppmodelmanager/cppcodemodelpart.cpp
new file mode 100644
index 0000000000..ae95cd444d
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppcodemodelpart.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfoList>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+#include "cppcodemodelpart.h"
+#include "cpppartparser.h"
+#include "cppcodemodelitems.h"
+
+CppCodeModelPart::CppCodeModelPart(const QString &path, QObject *parent)
+ : QObject(parent)
+{
+ m_path = path;
+}
+
+CppCodeModelPart::~CppCodeModelPart()
+{
+
+}
+
+QString CppCodeModelPart::path() const
+{
+ return m_path;
+}
+
+void CppCodeModelPart::update()
+{
+
+}
+
+QByteArray *CppCodeModelPart::contents(const QString &file)
+{
+ QByteArray *result = new QByteArray();
+ if (!m_files.contains(file)) {
+ m_files.insert(file);
+ QFile f(file);
+ if (!f.open(QIODevice::ReadOnly))
+ return 0;
+ (*result) = f.readAll();
+ f.close();
+ }
+
+ return result;
+}
+
+void CppCodeModelPart::store(CppFileModelItem *item)
+{
+ qDebug() << "Deleting: " << item->name();
+ delete item;
+}
+
+bool CppCodeModelPart::hasScope(const QString &name) const
+{
+ // ### implement me
+ return true;
+}
diff --git a/tests/manual/cppmodelmanager/cppcodemodelpart.h b/tests/manual/cppmodelmanager/cppcodemodelpart.h
new file mode 100644
index 0000000000..89a973b751
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppcodemodelpart.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPCODEMODELPART_H
+#define CPPCODEMODELPART_H
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+
+class CppCodeModel;
+class CppFileModelItem;
+
+class CppCodeModelPart : public QObject
+{
+ Q_OBJECT
+
+public:
+ CppCodeModelPart(const QString &path, QObject *parent = 0);
+ ~CppCodeModelPart();
+
+ QString path() const;
+ void update();
+
+protected:
+ // returns true if the given qualified name is known
+ bool hasScope(const QString &name) const;
+
+ // returns the contents of the file, this may be
+ // the current content of an open editor
+ // the byte array is deleted when no longer needed
+ QByteArray *contents(const QString &file);
+
+ // stores/replaces the parsed code model in the
+ // database or memory
+ void store(CppFileModelItem *item);
+
+private:
+ QString m_path;
+ QSet<QString> m_files;
+
+ friend class CppCodeModel;
+};
+
+#endif // CPPCODEMODELPART_H
diff --git a/tests/manual/cppmodelmanager/cppmodelmanager.pro b/tests/manual/cppmodelmanager/cppmodelmanager.pro
new file mode 100644
index 0000000000..714cc6c6a0
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cppmodelmanager.pro
@@ -0,0 +1,62 @@
+# #####################################################################
+# Automatically generated by qmake (2.01a) ma 24. apr 11:14:33 2006
+# #####################################################################
+TEMPLATE = app
+TARGET =
+QT += sql
+DEPENDPATH += .
+INCLUDEPATH += . \
+ codemodel
+include(../../../../cppparser/rxx.pri)|error("Can't find RXX")
+include(rpp/rpp.pri)
+SOURCES -= $$RXXPATH/codemodel.cpp \
+ $$RXXPATH/binder.cpp \
+ $$RXXPATH/codemodel_finder.cpp \
+ $$RXXPATH/compiler_utils.cpp \
+ $$RXXPATH/declarator_compiler.cpp \
+ $$RXXPATH/name_compiler.cpp \
+ $$RXXPATH/class_compiler.cpp \
+ $$RXXPATH/type_compiler.cpp
+
+HEADERS -= $$RXXPATH/codemodel.h \
+ $$RXXPATH/binder.h \
+ $$RXXPATH/codemodel_finder.h \
+ $$RXXPATH/compiler_utils.h \
+ $$RXXPATH/declarator_compiler.h \
+ $$RXXPATH/name_compiler.h \
+ $$RXXPATH/class_compiler.h \
+ $$RXXPATH/type_compiler.h \
+ $$RXXPATH/codemodel_fwd.h
+
+SOURCES += codemodel/codemodelitems.cpp \
+ codemodel/binder.cpp \
+ codemodel/codemodel_finder.cpp \
+ codemodel/compiler_utils.cpp \
+ codemodel/declarator_compiler.cpp \
+ codemodel/name_compiler.cpp \
+ codemodel/class_compiler.cpp \
+ codemodel/type_compiler.cpp
+
+HEADERS += codemodel/codemodelitems.h \
+ codemodel/binder.h \
+ codemodel/codemodel_finder.h \
+ codemodel/compiler_utils.h \
+ codemodel/declarator_compiler.h \
+ codemodel/name_compiler.h \
+ codemodel/class_compiler.h \
+ codemodel/type_compiler.h
+
+# Input
+SOURCES += main.cpp \
+ dbcodemodel.cpp \
+ cppcodemodel.cpp \
+ cppcodemodelitems.cpp \
+ cppcodemodelpart.cpp \
+ cpppartparser.cpp
+HEADERS += dbcodemodel.h \
+ cppcodemodelpart.h \
+ cppcodemodel.h \
+ cppcodemodelitems.h \
+ cpppartparser.h
+
+CONFIG += console
diff --git a/tests/manual/cppmodelmanager/cpppartparser.cpp b/tests/manual/cppmodelmanager/cpppartparser.cpp
new file mode 100644
index 0000000000..5fa3ae3847
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cpppartparser.cpp
@@ -0,0 +1,204 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+
+#include "cpppartparser.h"
+#include "cppcodemodel.h"
+
+#include "preprocessor.h"
+#include "pp-stream.h"
+#include "pp-engine.h"
+
+#include "parser.h"
+#include "control.h"
+
+#include "binder.h"
+
+CppPartParser *CppPartParser::m_instance = 0;
+
+// ****************************
+// CppStream
+// ****************************
+
+class CppStream : public Stream
+{
+public:
+ CppStream(QByteArray *array);
+ virtual ~CppStream();
+
+private:
+ QByteArray *m_array;
+};
+
+CppStream::CppStream(QByteArray *array)
+ : Stream(array)
+{
+ m_array = array;
+}
+
+CppStream::~CppStream()
+{
+ delete m_array;
+}
+
+// ****************************
+// CppPartPP
+// ****************************
+
+class CppPartPP : private Preprocessor
+{
+public:
+ QByteArray process(QString &fileName, CppCodeModel *model);
+
+protected:
+ Stream* sourceNeeded(QString& fileName, IncludeType type);
+
+private:
+ CppCodeModel *m_model;
+ pp *m_proc;
+};
+
+QByteArray CppPartPP::process(QString &fileName, CppCodeModel *model)
+{
+ QByteArray result;
+
+ m_model = model;
+ pp proc(this, (*model->macros()));
+ m_proc = &proc;
+ if (QByteArray *contents = m_model->contents(fileName)) {
+ result = proc.processFile(*(contents), fileName);
+ delete contents;
+ }
+
+ return result;
+}
+
+Stream* CppPartPP::sourceNeeded(QString& fileName, IncludeType type)
+{
+ QString localfile;
+ if (type == IncludeLocal)
+ localfile = m_proc->currentfile();
+
+ QByteArray *contents = m_model->contents(fileName, localfile);
+ if (!contents)
+ return 0;
+
+ return new CppStream(contents);
+}
+
+// ****************************
+// CppPartParser
+// ****************************
+
+CppPartParser::CppPartParser(QObject *parent)
+ : QThread(parent)
+{
+ m_cppPartPP = new CppPartPP();
+
+ m_cancelParsing = false;
+ m_currentModel = 0;
+}
+
+CppPartParser::~CppPartParser()
+{
+ delete m_cppPartPP;
+}
+
+CppPartParser *CppPartParser::instance(QObject *parent)
+{
+ if (!m_instance)
+ m_instance = new CppPartParser(parent);
+
+ return m_instance;
+}
+
+void CppPartParser::parse(CppCodeModel *model)
+{
+ mutex.lock();
+ if (!m_modelQueue.contains(model))
+ m_modelQueue.enqueue(model);
+ mutex.unlock();
+
+ if (!isRunning()) {
+ m_cancelParsing = false;
+ start();
+ setPriority(QThread::LowPriority);
+ }
+}
+
+void CppPartParser::remove(CppCodeModel *model)
+{
+ mutex.lock();
+ if (m_modelQueue.contains(model))
+ m_modelQueue.removeAll(model);
+
+ if (m_currentModel == model) {
+ m_cancelParsing = true;
+ mutex.unlock();
+ wait();
+ m_cancelParsing = false;
+ start();
+ setPriority(QThread::LowPriority);
+ } else {
+ mutex.unlock();
+ }
+}
+
+void CppPartParser::run()
+{
+ while (!m_cancelParsing && !m_modelQueue.isEmpty()) {
+ mutex.lock();
+ m_currentModel = m_modelQueue.dequeue();
+ mutex.unlock();
+
+ QStringList files = m_currentModel->needsParsing();
+ for (int i=0; i<files.count() && !m_cancelParsing; ++i) {
+ QString resolvedName = files.at(i);
+ QByteArray ppcontent = m_cppPartPP->process(
+ resolvedName, m_currentModel);
+
+ Control control;
+ Parser p(&control);
+ pool __pool;
+
+ TranslationUnitAST *ast = p.parse(ppcontent, ppcontent.size(), &__pool);
+ qDebug() << p.problemCount();
+
+ Binder binder(m_currentModel, p.location());
+ binder.run(ast, resolvedName);
+
+ m_currentModel->store();
+ }
+ }
+}
+
diff --git a/tests/manual/cppmodelmanager/cpppartparser.h b/tests/manual/cppmodelmanager/cpppartparser.h
new file mode 100644
index 0000000000..0d5790a210
--- /dev/null
+++ b/tests/manual/cppmodelmanager/cpppartparser.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPPARTPARSER_H
+#define CPPPARTPARSER_H
+
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+#include <QtCore/QQueue>
+
+class CppPartPP;
+class CppCodeModel;
+
+class CppPartParser : public QThread
+{
+ Q_OBJECT
+
+public:
+ ~CppPartParser();
+
+ static CppPartParser *instance(QObject *parent = 0);
+ void parse(CppCodeModel *model);
+ void remove(CppCodeModel *model);
+
+protected:
+ void run();
+ CppPartParser(QObject *parent = 0);
+
+private:
+ QMutex mutex;
+
+ bool m_cancelParsing;
+ CppCodeModel *m_currentModel;
+
+ QQueue<CppCodeModel *> m_modelQueue;
+
+ static CppPartParser *m_instance;
+
+ CppPartPP *m_cppPartPP;
+ friend class CppPartPP;
+};
+
+#endif //CPPPARTPARSER_H
diff --git a/tests/manual/cppmodelmanager/dbcodemodel.cpp b/tests/manual/cppmodelmanager/dbcodemodel.cpp
new file mode 100644
index 0000000000..a9abfd83b7
--- /dev/null
+++ b/tests/manual/cppmodelmanager/dbcodemodel.cpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QFile>
+
+#include "dbcodemodel.h"
+
+DBCodeModel::DBCodeModel(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+DBCodeModel::~DBCodeModel()
+{
+
+}
+
+bool DBCodeModel::open(const QString &fileName)
+{
+ m_db = QSqlDatabase::addDatabase("QSQLITE", fileName);
+
+ if (!QFile::exists(fileName)) {
+ m_db.setDatabaseName(fileName);
+ if (!m_db.open() || !create())
+ return false;
+ } else {
+ m_db.setDatabaseName(fileName);
+ if (!m_db.open()) // || !update(fileName))
+ return false;
+ }
+
+ return true;
+}
+
+bool DBCodeModel::create()
+{
+ QSqlQuery query(m_db);
+
+ // table to store type information
+ query.exec("CREATE TABLE TYPEINFO ("
+ "id INTEGER PRIMARY KEY, "
+ "typename TEXT, "
+ "typeflags INTEGER, "
+ ")");
+
+ // table to store position information
+ query.exec("CREATE TABLE POSITION ("
+ "id INTEGER PRIMARY KEY, "
+ "sline INTEGER, "
+ "scolumn INTEGER, "
+ "eline INTEGER, "
+ "ecolumn INTEGER"
+ ")");
+
+ // table to store files (global namespace), namespaces, unions, structs and classes
+ query.exec("CREATE TABLE SCOPE ("
+ "id INTEGER PRIMARY KEY, "
+ "scopetype INTEGER, "
+ "name TEXT, "
+ "parent INTEGER, "
+ "posid INTEGER, "
+ "fileid INTEGER"
+ ")");
+
+ // table to store scope member information
+ // a scope member is a enum, function, variable or typealias
+ query.exec("CREATE TABLE SCOPEMEMBER ("
+ "id INTEGER PRIMARY KEY, "
+ "membertype INTEGER, "
+ "name TEXT, "
+ "scopeid INTEGER, "
+ "flags INTEGER, "
+ "typeid INTEGER, "
+ "posid INTEGER, "
+ "fileid INTEGER"
+ ")");
+
+ // table to store arguments
+ // used if the membertype is a function
+ query.exec("CREATE TABLE ARGUMENT ("
+ "name TEXT, "
+ "default TEXT, "
+ "argnr INTEGER, "
+ "typeid INTEGER, "
+ "memberid INTEGER"
+ ")");
+
+ // table to store enumerators
+ // used if the membertype is an enum
+ query.exec("CREATE TABLE ENUMERATOR ("
+ "name TEXT, "
+ "value INTEGER, "
+ "memberid INTEGER"
+ ")");
+
+ // table to store arguments to types
+ // used if typeflags indicates that it has arguments (i.e. function pointers)
+ query.exec("CREATE TABLE TYPEARGUMENT ("
+ "parentid INTEGER, "
+ "argnr INTEGER, "
+ "typeid INTEGER"
+ ")");
+
+ // table to store the class hierarchy
+ query.exec("CREATE TABLE CLASSHIERARCHY ("
+ "scopeid INTEGER, "
+ "basename TEXT"
+ ")");
+
+ // table to store all the modified timestamps used
+ // for updating the database
+ query.exec("CREATE TABLE MODIFIED ("
+ "fileid INTEGER, "
+ "modified INTEGER)");
+
+ return true;
+}
diff --git a/tests/manual/cppmodelmanager/dbcodemodel.h b/tests/manual/cppmodelmanager/dbcodemodel.h
new file mode 100644
index 0000000000..479fde8656
--- /dev/null
+++ b/tests/manual/cppmodelmanager/dbcodemodel.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DBCODEMODEL_H
+#define DBCODEMODEL_H
+
+#include <QtSql>
+
+class DBCodeModel : public QObject
+{
+ Q_OBJECT
+
+public:
+ DBCodeModel(QObject *parent = 0);
+ ~DBCodeModel();
+
+ bool open(const QString &fileName);
+
+protected:
+ bool create();
+
+private:
+ QSqlDatabase m_db;
+};
+
+#endif // DBCODEMODEL_H
diff --git a/tests/manual/cppmodelmanager/main.cpp b/tests/manual/cppmodelmanager/main.cpp
new file mode 100644
index 0000000000..da82664136
--- /dev/null
+++ b/tests/manual/cppmodelmanager/main.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore>
+
+#include "cppcodemodel.h"
+#include "preprocessor.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ QFile f("C:\\depot\\research\\main\\cppparser\\rpp\\pp-qt-configuration");
+ f.open(QIODevice::ReadOnly);
+ CppCodeModel model(f.readAll());
+ f.close();
+
+ model.addIncludePath("C:\\depot\\qt\\4.1\\include\\");
+ model.addIncludePath("C:\\depot\\qt\\4.1\\include\\QtCore");
+ model.addIncludePath("C:\\depot\\qt\\4.1\\include\\QtGui");
+
+/* model.addIncludePath("C:\\depot\\research\\main\\qworkbench\\tests\\manual\\cppmodelmanager\\tests"); */
+ model.update(QStringList() << "qwidget.h");
+
+// return app.exec();
+ return 0;
+
+/* Preprocessor pp;
+ pp.addIncludePaths(QStringList() << "C:/depot/qt/4.1/include/QtCore/");
+ pp.processFile("C:/depot/research/main/cppparser/rpp/pp-qt-configuration");
+ QString ppstuff = pp.processFile("test.h");
+
+
+ Control control;
+ Parser p(&control);
+ pool __pool;
+
+ QByteArray byteArray = ppstuff.toUtf8();
+ TranslationUnitAST *ast = p.parse(byteArray, byteArray.size(), &__pool);
+ qDebug() << p.problemCount();
+
+ CodeModel model;
+ Binder binder(&model, p.location());
+ FileModelItem fileModel = binder.run(ast);
+
+ qDebug() << "Count: " << model.files().count(); */
+
+/* DBCodeModel db;
+ db.open("c:/bin/test.cdb"); */
+
+
+}
diff --git a/tests/manual/cppmodelmanager/rpp/pp-engine.cpp b/tests/manual/cppmodelmanager/rpp/pp-engine.cpp
new file mode 100644
index 0000000000..cef2b08292
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-engine.cpp
@@ -0,0 +1,1117 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-engine.h"
+
+#include <QFile>
+
+#include <QtCore/QDebug>
+
+#include "pp-internal.h"
+#include "preprocessor.h"
+
+pp::pp(Preprocessor* preprocessor, QHash<QString, pp_macro*>& environment)
+ : m_environment(environment)
+ , expand(this)
+ , m_preprocessor(preprocessor)
+ , nextToken(0)
+ , haveNextToken(false)
+ , hideNext(false)
+{
+ iflevel = 0;
+ _M_skipping[iflevel] = 0;
+ _M_true_test[iflevel] = 0;
+}
+
+QList<pp::ErrorMessage> pp::errorMessages () const
+{
+ return _M_error_messages;
+}
+
+void pp::clearErrorMessages ()
+{
+ _M_error_messages.clear ();
+}
+
+void pp::reportError (const QString &fileName, int line, int column, const QString &message)
+{
+ ErrorMessage msg;
+ msg.setFileName (fileName);
+ msg.setLine (line);
+ msg.setColumn (column);
+ msg.setMessage (message);
+
+ _M_error_messages.append (msg);
+}
+
+QString pp::processFile(const QString& filename)
+{
+ QFile file(filename);
+ if (file.open(QIODevice::ReadOnly))
+ {
+ m_files.push(filename);
+
+ Stream is(&file);
+ QString result;
+
+ {
+ Stream rs(&result);
+ operator () (is, rs);
+ }
+
+ return result;
+ }
+
+ qWarning() << "file '" << filename << "' not found!" << endl;
+ return QString();
+}
+
+QString pp::processFile(QIODevice* device)
+{
+ Q_ASSERT(device);
+
+ QString result;
+ m_files.push("<internal>");
+
+ {
+ Stream is(device);
+ Stream rs(&result);
+ operator () (is, rs);
+ }
+
+ return result;
+}
+
+QString pp::processFile(const QByteArray& input)
+{
+ QString result;
+ m_files.push("<internal>");
+
+ {
+ Stream is(input);
+ Stream rs(&result);
+ operator () (is, rs);
+ }
+
+ return result;
+}
+
+QByteArray pp::processFile(const QByteArray& input, const QString &fileName)
+{
+ QByteArray result;
+ m_files.push(fileName);
+
+ {
+ Stream is(input);
+ Stream rs(&result);
+ operator () (is, rs);
+ }
+
+ return result;
+}
+
+QString pp::find_header_protection(Stream& input)
+{
+ while (!input.atEnd())
+ {
+ if (input.current().isSpace())
+ {
+ ++input;
+ }
+ else if (PPInternal::isComment(input))
+ {
+ skip_comment_or_divop (input, PPInternal::devnull());
+ }
+ else if (input == '#')
+ {
+ skip_blanks (++input, PPInternal::devnull());
+
+ if (!input.atEnd() && input == 'i')
+ {
+ QString directive = skip_identifier(input);
+
+ if (directive == "ifndef")
+ {
+ skip_blanks (input, PPInternal::devnull());
+
+ QString define = skip_identifier(input);
+
+ if (!define.isEmpty() && !input.atEnd())
+ {
+ input.reset();
+ return define;
+ }
+ }
+ }
+ break;
+
+ } else {
+ break;
+ }
+ }
+
+ input.reset();
+ return QString();
+}
+
+pp::PP_DIRECTIVE_TYPE pp::find_directive (const QString& directive) const
+{
+ static QHash<QString, PP_DIRECTIVE_TYPE> directiveHash;
+ if (directiveHash.isEmpty()) {
+ directiveHash.insert("if", PP_IF);
+ directiveHash.insert("elif", PP_ELIF);
+ directiveHash.insert("else", PP_ELSE);
+ directiveHash.insert("ifdef", PP_IFDEF);
+ directiveHash.insert("undef", PP_UNDEF);
+ directiveHash.insert("endif", PP_ENDIF);
+ directiveHash.insert("ifndef", PP_IFNDEF);
+ directiveHash.insert("define", PP_DEFINE);
+ directiveHash.insert("include", PP_INCLUDE);
+ }
+
+ if (directiveHash.contains(directive))
+ return directiveHash[directive];
+
+ return PP_UNKNOWN_DIRECTIVE;
+}
+
+void pp::handle_directive(const QString& directive, Stream& input, Stream& output)
+{
+ skip_blanks (input, output);
+
+ switch (find_directive(directive))
+ {
+ case PP_DEFINE:
+ if (! skipping ())
+ return handle_define(input);
+ break;
+
+ case PP_INCLUDE:
+ if (! skipping ())
+ return handle_include (input, output);
+ break;
+
+ case PP_UNDEF:
+ if (! skipping ())
+ return handle_undef(input);
+ break;
+
+ case PP_ELIF:
+ return handle_elif(input);
+
+ case PP_ELSE:
+ return handle_else();
+
+ case PP_ENDIF:
+ return handle_endif();
+
+ case PP_IF:
+ return handle_if(input);
+
+ case PP_IFDEF:
+ return handle_ifdef(false, input);
+
+ case PP_IFNDEF:
+ return handle_ifdef(true, input);
+
+ default:
+ break;
+ }
+}
+
+void pp::handle_include(Stream& input, Stream& output)
+{
+ Q_ASSERT(input == '<' || input == '"');
+ QChar quote((input == '"') ? '"' : '>');
+ ++input;
+
+ QString includeName;
+
+ while (!input.atEnd() && input != quote) {
+ Q_ASSERT(input != '\n');
+
+ includeName.append(input);
+ ++input;
+ }
+
+ Stream* include = m_preprocessor->sourceNeeded(includeName,
+ quote == '"' ? Preprocessor::IncludeLocal : Preprocessor::IncludeGlobal);
+ if (include && !include->atEnd()) {
+ m_files.push(includeName);
+
+ output.mark(includeName, 0);
+
+ operator()(*include, output);
+
+ // restore the file name and sync the buffer
+ m_files.pop();
+ output.mark(m_files.top(), input.inputLineNumber());
+ }
+
+ delete include;
+}
+
+void pp::operator () (Stream& input, Stream& output)
+{
+#ifndef PP_NO_SMART_HEADER_PROTECTION
+ QString headerDefine = find_header_protection(input);
+ if (m_environment.contains(headerDefine))
+ {
+ //kDebug() << k_funcinfo << "found header protection: " << headerDefine << endl;
+ return;
+ }
+#endif
+
+ forever
+ {
+ if (skipping()) {
+ skip_blanks(input, PPInternal::devnull());
+
+ } else {
+ skip_blanks(input, output);
+ }
+
+ if (input.atEnd()) {
+ break;
+
+ } else if (input == '#') {
+ skip_blanks(++input, PPInternal::devnull());
+
+ QString directive = skip_identifier(input);
+
+ Q_ASSERT(directive.length() < 512);
+
+ skip_blanks(input, PPInternal::devnull());
+
+ QString skipped;
+ {
+ Stream ss(&skipped);
+ skip (input, ss);
+ }
+
+ Stream ss(&skipped);
+ handle_directive(directive, ss, output);
+
+ } else if (input == '\n') {
+ checkMarkNeeded(input, output);
+ output << input;
+ ++input;
+
+ } else if (skipping ()) {
+ skip (input, PPInternal::devnull());
+
+ } else {
+ checkMarkNeeded(input, output);
+ expand (input, output);
+ }
+ }
+}
+
+void pp::checkMarkNeeded(Stream& input, Stream& output)
+{
+ if (input.inputLineNumber() != output.outputLineNumber() && !output.isNull())
+ output.mark(m_files.top(), input.inputLineNumber());
+}
+
+void pp::handle_define (Stream& input)
+{
+ pp_macro* macro = new pp_macro();
+#if defined (PP_WITH_MACRO_POSITION)
+ macro->file = m_files.top();
+#endif
+ QString definition;
+
+ skip_blanks (input, PPInternal::devnull());
+ QString macro_name = skip_identifier(input);
+
+ if (!input.atEnd() && input == '(')
+ {
+ macro->function_like = true;
+
+ skip_blanks (++input, PPInternal::devnull()); // skip '('
+ QString formal = skip_identifier(input);
+ if (!formal.isEmpty())
+ macro->formals << formal;
+
+ skip_blanks(input, PPInternal::devnull());
+
+ if (input == '.') {
+ macro->variadics = true;
+
+ do {
+ ++input;
+
+ } while (input == '.');
+ }
+
+ while (!input.atEnd() && input == ',')
+ {
+ skip_blanks(++input, PPInternal::devnull());
+
+ QString formal = skip_identifier(input);
+ if (!formal.isEmpty())
+ macro->formals << formal;
+
+ skip_blanks (input, PPInternal::devnull());
+
+ if (input == '.') {
+ macro->variadics = true;
+
+ do {
+ ++input;
+
+ } while (input == '.');
+ }
+ }
+
+ Q_ASSERT(input == ')');
+ ++input;
+ }
+
+ skip_blanks (input, PPInternal::devnull());
+
+ while (!input.atEnd() && input != '\n')
+ {
+ if (input == '\\')
+ {
+ qint64 pos = input.pos();
+ skip_blanks (++input, PPInternal::devnull());
+
+ if (!input.atEnd() && input == '\n')
+ {
+ ++macro->lines;
+ skip_blanks(++input, PPInternal::devnull());
+ definition += ' ';
+ continue;
+
+ } else {
+ // Whoops, rewind :)
+ input.seek(pos);
+ }
+ }
+
+ definition += input;
+ ++input;
+ }
+
+ macro->definition = definition;
+
+ if (pp_macro* replacemacro = m_environment.value(macro_name, 0))
+ delete replacemacro;
+
+ m_environment.insert(macro_name, macro);
+}
+
+
+void pp::skip (Stream& input, Stream& output, bool outputText)
+{
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+
+ while (!input.atEnd() && input != '\n')
+ {
+ if (input == '/')
+ {
+ skip_comment_or_divop (input, output, outputText);
+ }
+ else if (input == '"')
+ {
+ skip_string_literal (input, output);
+ }
+ else if (input == '\'')
+ {
+ skip_char_literal (input, output);
+ }
+ else if (input == '\\')
+ {
+ output << input;
+ skip_blanks (++input, output);
+
+ if (!input.atEnd() && input == '\n')
+ {
+ output << input;
+ ++input;
+ }
+ }
+ else
+ {
+ output << input;
+ ++input;
+ }
+ }
+}
+
+inline bool pp::test_if_level()
+{
+ bool result = !_M_skipping[iflevel++];
+ _M_skipping[iflevel] = _M_skipping[iflevel - 1];
+ _M_true_test[iflevel] = false;
+ return result;
+}
+
+inline int pp::skipping() const
+{ return _M_skipping[iflevel]; }
+
+
+long pp::eval_primary(Stream& input)
+{
+ bool expect_paren = false;
+ int token = next_token_accept(input);
+ long result = 0;
+
+ switch (token) {
+ case TOKEN_NUMBER:
+ return token_value;
+
+ case TOKEN_DEFINED:
+ token = next_token_accept(input);
+
+ if (token == '(')
+ {
+ expect_paren = true;
+ token = next_token_accept(input);
+ }
+
+ if (token != TOKEN_IDENTIFIER)
+ {
+ qWarning() << "expected ``identifier'' found:" << token << endl;
+ break;
+ }
+
+ result = m_environment.contains(token_text);
+
+ token = next_token(input); // skip '('
+
+ if (expect_paren) {
+ token = next_token(input);
+
+ if (token != ')')
+ qWarning() << "expected ``)''" << endl;
+ else
+ accept_token();
+ }
+ break;
+
+ case TOKEN_IDENTIFIER:
+ break;
+
+ case '!':
+ return !eval_primary(input);
+
+ case '(':
+ result = eval_constant_expression(input);
+ token = next_token(input);
+
+ if (token != ')')
+ qWarning() << "expected ``)'' = " << token << endl;
+ else
+ accept_token();
+
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+long pp::eval_multiplicative(Stream& input)
+{
+ long result = eval_primary(input);
+
+ int token = next_token(input);
+
+ while (token == '*' || token == '/' || token == '%') {
+ accept_token();
+
+ long value = eval_primary(input);
+
+ if (token == '*') {
+ result *= value;
+
+ } else if (token == '/') {
+ if (value == 0) {
+ qWarning() << "division by zero" << endl;
+ result = 0;
+
+ } else {
+ result = result / value;
+ }
+
+ } else {
+ if (value == 0) {
+ qWarning() << "division by zero" << endl;
+ result = 0;
+
+ } else {
+ result %= value;
+ }
+ }
+
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+long pp::eval_additive(Stream& input)
+{
+ long result = eval_multiplicative(input);
+
+ int token = next_token(input);
+
+ while (token == '+' || token == '-') {
+ accept_token();
+
+ long value = eval_multiplicative(input);
+
+ if (token == '+')
+ result += value;
+ else
+ result -= value;
+
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_shift(Stream& input)
+{
+ long result = eval_additive(input);
+
+ int token;
+ token = next_token(input);
+
+ while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) {
+ accept_token();
+
+ long value = eval_additive(input);
+
+ if (token == TOKEN_LT_LT)
+ result <<= value;
+ else
+ result >>= value;
+
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_relational(Stream& input)
+{
+ long result = eval_shift(input);
+
+ int token = next_token(input);
+
+ while (token == '<'
+ || token == '>'
+ || token == TOKEN_LT_EQ
+ || token == TOKEN_GT_EQ)
+ {
+ accept_token();
+ long value = eval_shift(input);
+
+ switch (token)
+ {
+ default:
+ Q_ASSERT(0);
+ break;
+
+ case '<':
+ result = result < value;
+ break;
+
+ case '>':
+ result = result < value;
+ break;
+
+ case TOKEN_LT_EQ:
+ result = result <= value;
+ break;
+
+ case TOKEN_GT_EQ:
+ result = result >= value;
+ break;
+ }
+
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_equality(Stream& input)
+{
+ long result = eval_relational(input);
+
+ int token = next_token(input);
+
+ while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) {
+ accept_token();
+ long value = eval_relational(input);
+
+ if (token == TOKEN_EQ_EQ)
+ result = result == value;
+ else
+ result = result != value;
+
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_and(Stream& input)
+{
+ long result = eval_equality(input);
+
+ int token = next_token(input);
+
+ while (token == '&') {
+ accept_token();
+ long value = eval_equality(input);
+ result = result & value;
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_xor(Stream& input)
+{
+ long result = eval_and(input);
+
+ int token;
+ token = next_token(input);
+
+ while (token == '^') {
+ accept_token();
+ long value = eval_and(input);
+ result = result ^ value;
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_or(Stream& input)
+{
+ long result = eval_xor(input);
+
+ int token = next_token(input);
+
+ while (token == '|') {
+ accept_token();
+ long value = eval_xor(input);
+ result = result | value;
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_logical_and(Stream& input)
+{
+ long result = eval_or(input);
+
+ int token = next_token(input);
+
+ while (token == TOKEN_AND_AND) {
+ accept_token();
+ long value = eval_or(input);
+ result = result && value;
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_logical_or(Stream& input)
+{
+ long result = eval_logical_and(input);
+
+ int token = next_token(input);
+
+ while (token == TOKEN_OR_OR) {
+ accept_token();
+ long value = eval_logical_and(input);
+ result = result || value;
+ token = next_token(input);
+ }
+
+ return result;
+}
+
+
+long pp::eval_constant_expression(Stream& input)
+{
+ long result = eval_logical_or(input);
+
+ int token = next_token(input);
+
+ if (token == '?')
+ {
+ accept_token();
+ long left_value = eval_constant_expression(input);
+ skip_blanks(input, PPInternal::devnull());
+
+ token = next_token_accept(input);
+ if (token == ':')
+ {
+ long right_value = eval_constant_expression(input);
+
+ result = result ? left_value : right_value;
+ }
+ else
+ {
+ qWarning() << "expected ``:'' = " << int (token) << endl;
+ result = left_value;
+ }
+ }
+
+ return result;
+}
+
+
+long pp::eval_expression(Stream& input)
+{
+ skip_blanks(input, PPInternal::devnull());
+ return eval_constant_expression(input);
+}
+
+
+void pp::handle_if (Stream& input)
+{
+ if (test_if_level())
+ {
+ pp_macro_expander expand_condition(this);
+ skip_blanks(input, PPInternal::devnull());
+ QString condition;
+ {
+ Stream cs(&condition);
+ expand_condition(input, cs);
+ }
+
+ Stream cs(&condition);
+ long result = eval_expression(cs);
+
+ _M_true_test[iflevel] = result;
+ _M_skipping[iflevel] = !result;
+ }
+}
+
+
+void pp::handle_else()
+{
+ if (iflevel == 0 && !skipping ())
+ {
+ qWarning() << "#else without #if" << endl;
+ }
+ else if (iflevel > 0 && _M_skipping[iflevel - 1])
+ {
+ _M_skipping[iflevel] = true;
+ }
+ else
+ {
+ _M_skipping[iflevel] = _M_true_test[iflevel];
+ }
+}
+
+
+void pp::handle_elif(Stream& input)
+{
+ Q_ASSERT(iflevel > 0);
+
+ if (iflevel == 0 && !skipping())
+ {
+ qWarning() << "#else without #if" << endl;
+ }
+ else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1])
+ {
+ long result = eval_expression(input);
+ _M_true_test[iflevel] = result;
+ _M_skipping[iflevel] = !result;
+ }
+ else
+ {
+ _M_skipping[iflevel] = true;
+ }
+}
+
+
+void pp::handle_endif()
+{
+ if (iflevel == 0 && !skipping())
+ {
+ qWarning() << "#endif without #if" << endl;
+ }
+ else
+ {
+ _M_skipping[iflevel] = 0;
+ _M_true_test[iflevel] = 0;
+
+ --iflevel;
+ }
+}
+
+
+void pp::handle_ifdef (bool check_undefined, Stream& input)
+{
+ if (test_if_level())
+ {
+ QString macro_name = skip_identifier(input);
+ bool value = m_environment.contains(macro_name);
+
+ if (check_undefined)
+ value = !value;
+
+ _M_true_test[iflevel] = value;
+ _M_skipping[iflevel] = !value;
+ }
+}
+
+
+void pp::handle_undef(Stream& input)
+{
+ skip_blanks (input, PPInternal::devnull());
+
+ QString macro_name = skip_identifier(input);
+ Q_ASSERT(!macro_name.isEmpty());
+
+ delete m_environment.take(macro_name);
+}
+
+int pp::next_token (Stream& input)
+{
+ if (haveNextToken)
+ return nextToken;
+
+ skip_blanks(input, PPInternal::devnull());
+
+ if (input.atEnd())
+ {
+ return 0;
+ }
+
+ char ch = input.current().toLatin1();
+ char ch2 = input.peek().toLatin1();
+
+ nextToken = 0;
+
+ switch (ch) {
+ case '/':
+ if (ch2 == '/' || ch2 == '*')
+ {
+ skip_comment_or_divop(input, PPInternal::devnull(), false);
+ return next_token(input);
+ }
+ ++input;
+ nextToken = '/';
+ break;
+
+ case '<':
+ ++input;
+ if (ch2 == '<')
+ {
+ ++input;
+ nextToken = TOKEN_LT_LT;
+ }
+ else if (ch2 == '=')
+ {
+ ++input;
+ nextToken = TOKEN_LT_EQ;
+ }
+ else
+ nextToken = '<';
+
+ break;
+
+ case '>':
+ ++input;
+ if (ch2 == '>')
+ {
+ ++input;
+ nextToken = TOKEN_GT_GT;
+ }
+ else if (ch2 == '=')
+ {
+ ++input;
+ nextToken = TOKEN_GT_EQ;
+ }
+ else
+ nextToken = '>';
+
+ break;
+
+ case '!':
+ ++input;
+ if (ch2 == '=')
+ {
+ ++input;
+ nextToken = TOKEN_NOT_EQ;
+ }
+ else
+ nextToken = '!';
+
+ break;
+
+ case '=':
+ ++input;
+ if (ch2 == '=')
+ {
+ ++input;
+ nextToken = TOKEN_EQ_EQ;
+ }
+ else
+ nextToken = '=';
+
+ break;
+
+ case '|':
+ ++input;
+ if (ch2 == '|')
+ {
+ ++input;
+ nextToken = TOKEN_OR_OR;
+ }
+ else
+ nextToken = '|';
+
+ break;
+
+ case '&':
+ ++input;
+ if (ch2 == '&')
+ {
+ ++input;
+ nextToken = TOKEN_AND_AND;
+ }
+ else
+ nextToken = '&';
+
+ break;
+
+ default:
+ if (QChar(ch).isLetter() || ch == '_')
+ {
+ token_text = skip_identifier (input);
+
+ if (token_text == "defined")
+ nextToken = TOKEN_DEFINED;
+ else
+ nextToken = TOKEN_IDENTIFIER;
+ }
+ else if (QChar(ch).isNumber())
+ {
+ QString number;
+ {
+ Stream ns(&number);
+ skip_number(input, ns);
+ }
+ token_value = number.toLong();
+
+ nextToken = TOKEN_NUMBER;
+ }
+ else
+ {
+ nextToken = input.current().toLatin1();
+ ++input;
+ }
+ }
+
+ //kDebug() << "Next token '" << ch << ch2 << "' " << nextToken << " txt " << token_text << " val " << token_value << endl;
+
+ haveNextToken = true;
+ return nextToken;
+}
+
+int pp::next_token_accept (Stream& input)
+{
+ int result = next_token(input);
+ accept_token();
+ return result;
+}
+
+void pp::accept_token()
+{
+ haveNextToken = false;
+ nextToken = 0;
+}
+
+bool pp::hideNextMacro( ) const
+{
+ return hideNext;
+}
+
+void pp::setHideNextMacro( bool h )
+{
+ hideNext = h;
+}
+
+QHash< QString, pp_macro * > & pp::environment( )
+{
+ return m_environment;
+}
+
+// kate: indent-width 2;
diff --git a/tests/manual/cppmodelmanager/rpp/pp-engine.h b/tests/manual/cppmodelmanager/rpp/pp-engine.h
new file mode 100644
index 0000000000..446b08a870
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-engine.h
@@ -0,0 +1,232 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_ENGINE_H
+#define PP_ENGINE_H
+
+#include <QHash>
+#include <QString>
+#include <QStack>
+
+#include "pp-macro.h"
+#include "pp-macro-expander.h"
+#include "pp-scanner.h"
+
+class Preprocessor;
+
+class pp
+{
+ QHash<QString, pp_macro*>& m_environment;
+ pp_macro_expander expand;
+ pp_skip_identifier skip_identifier;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+ pp_skip_number skip_number;
+ QStack<QString> m_files;
+ Preprocessor* m_preprocessor;
+
+ class ErrorMessage
+ {
+ int _M_line;
+ int _M_column;
+ QString _M_fileName;
+ QString _M_message;
+
+ public:
+ ErrorMessage ():
+ _M_line (0),
+ _M_column (0) {}
+
+ inline int line () const { return _M_line; }
+ inline void setLine (int line) { _M_line = line; }
+
+ inline int column () const { return _M_column; }
+ inline void setColumn (int column) { _M_column = column; }
+
+ inline QString fileName () const { return _M_fileName; }
+ inline void setFileName (const QString &fileName) { _M_fileName = fileName; }
+
+ inline QString message () const { return _M_message; }
+ inline void setMessage (const QString &message) { _M_message = message; }
+ };
+
+ QList<ErrorMessage> _M_error_messages;
+
+ enum { MAX_LEVEL = 512 };
+ int _M_skipping[MAX_LEVEL];
+ int _M_true_test[MAX_LEVEL];
+ int iflevel;
+ int nextToken;
+ bool haveNextToken;
+ bool hideNext;
+
+ long token_value;
+ QString token_text;
+
+ enum TOKEN_TYPE
+ {
+ TOKEN_NUMBER = 1000,
+ TOKEN_IDENTIFIER,
+ TOKEN_DEFINED,
+ TOKEN_LT_LT,
+ TOKEN_LT_EQ,
+ TOKEN_GT_GT,
+ TOKEN_GT_EQ,
+ TOKEN_EQ_EQ,
+ TOKEN_NOT_EQ,
+ TOKEN_OR_OR,
+ TOKEN_AND_AND,
+ };
+
+ enum PP_DIRECTIVE_TYPE
+ {
+ PP_UNKNOWN_DIRECTIVE,
+ PP_DEFINE,
+ PP_INCLUDE,
+ PP_ELIF,
+ PP_ELSE,
+ PP_ENDIF,
+ PP_IF,
+ PP_IFDEF,
+ PP_IFNDEF,
+ PP_UNDEF
+ };
+
+public:
+ pp(Preprocessor* preprocessor, QHash<QString, pp_macro*>& environment);
+
+ QList<ErrorMessage> errorMessages () const;
+ void clearErrorMessages ();
+
+ void reportError (const QString &fileName, int line, int column, const QString &message);
+
+ long eval_expression (Stream& input);
+
+ QString processFile(const QString& filename);
+ QString processFile(QIODevice* input);
+ QString processFile(const QByteArray& input);
+ QByteArray processFile(const QByteArray& input, const QString &fileName);
+
+ inline QString currentfile() const {
+ return m_files.top();
+ }
+
+ void operator () (Stream& input, Stream& output);
+
+ void checkMarkNeeded(Stream& input, Stream& output);
+
+ bool hideNextMacro() const;
+ void setHideNextMacro(bool hideNext);
+
+ QHash<QString, pp_macro*>& environment();
+
+private:
+ int skipping() const;
+ bool test_if_level();
+
+ PP_DIRECTIVE_TYPE find_directive (const QString& directive) const;
+
+ QString find_header_protection(Stream& input);
+
+ void skip(Stream& input, Stream& output, bool outputText = true);
+
+ long eval_primary(Stream& input);
+
+ long eval_multiplicative(Stream& input);
+
+ long eval_additive(Stream& input);
+
+ long eval_shift(Stream& input);
+
+ long eval_relational(Stream& input);
+
+ long eval_equality(Stream& input);
+
+ long eval_and(Stream& input);
+
+ long eval_xor(Stream& input);
+
+ long eval_or(Stream& input);
+
+ long eval_logical_and(Stream& input);
+
+ long eval_logical_or(Stream& input);
+
+ long eval_constant_expression(Stream& input);
+
+ void handle_directive(const QString& directive, Stream& input, Stream& output);
+
+ void handle_include(Stream& input, Stream& output);
+
+ void handle_define(Stream& input);
+
+ void handle_if(Stream& input);
+
+ void handle_else();
+
+ void handle_elif(Stream& input);
+
+ void handle_endif();
+
+ void handle_ifdef(bool check_undefined, Stream& input);
+
+ void handle_undef(Stream& input);
+
+ int next_token (Stream& input);
+ int next_token_accept (Stream& input);
+ void accept_token();
+};
+
+#endif // PP_ENGINE_H
+
+// kate: indent-width 2;
+
diff --git a/tests/manual/cppmodelmanager/rpp/pp-internal.cpp b/tests/manual/cppmodelmanager/rpp/pp-internal.cpp
new file mode 100644
index 0000000000..c427d006b1
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-internal.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-internal.h"
+
+bool PPInternal::isComment(Stream& input)
+{
+ QChar c1 = input;
+ QChar c2 = input.peek();
+
+ return c1 == '/' && (c2 == '/' || c2 == '*');
+}
+
+Stream& PPInternal::devnull()
+{
+ static Stream null;
+ return null;
+}
diff --git a/tests/manual/cppmodelmanager/rpp/pp-internal.h b/tests/manual/cppmodelmanager/rpp/pp-internal.h
new file mode 100644
index 0000000000..4be1f6ce5d
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-internal.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_INTERNAL_H
+#define PP_INTERNAL_H
+
+#include "pp-stream.h"
+
+namespace PPInternal
+{
+
+bool isComment(Stream& input);
+
+Stream& devnull();
+
+}
+// _PP_internal
+
+#endif // PP_INTERNAL_H
diff --git a/tests/manual/cppmodelmanager/rpp/pp-macro-expander.cpp b/tests/manual/cppmodelmanager/rpp/pp-macro-expander.cpp
new file mode 100644
index 0000000000..032bf36593
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-macro-expander.cpp
@@ -0,0 +1,287 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-macro-expander.h"
+
+#include <QtCore/QDebug>
+
+#include "pp-internal.h"
+#include "pp-engine.h"
+
+pp_frame::pp_frame(pp_macro* __expandingMacro, const QList<QString>& __actuals)
+ : expandingMacro(__expandingMacro)
+ , actuals(__actuals)
+{
+}
+
+QString pp_macro_expander::resolve_formal(const QString& name)
+{
+ Q_ASSERT(!name.isEmpty());
+
+ if (!m_frame)
+ return QString();
+
+ Q_ASSERT(m_frame->expandingMacro != 0);
+
+ const QStringList& formals = m_frame->expandingMacro->formals;
+
+ for (int index = 0; index < formals.size(); ++index) {
+ if (name == formals[index]) {
+ if (index < m_frame->actuals.size())
+ return m_frame->actuals[index];
+ else
+ Q_ASSERT(0); // internal error?
+ }
+ }
+
+ return QString();
+}
+
+pp_macro_expander::pp_macro_expander(pp* engine, pp_frame* frame)
+ : m_engine(engine)
+ , m_frame(frame)
+{
+}
+
+void pp_macro_expander::operator()(Stream& input, Stream& output)
+{
+ skip_blanks(input, output);
+
+ while (!input.atEnd())
+ {
+ if (input == '\n')
+ {
+ output << input;
+
+ skip_blanks(++input, output);
+
+ if (!input.atEnd() && input == '#')
+ break;
+ }
+ else if (input == '#')
+ {
+ skip_blanks(++input, output);
+
+ QString identifier = skip_identifier(input);
+ output << '\"';
+
+ Stream is(&identifier);
+ operator()(is, output);
+
+ output << '\"';
+ }
+ else if (input == '\"')
+ {
+ skip_string_literal(input, output);
+ }
+ else if (input == '\'')
+ {
+ skip_char_literal(input, output);
+ }
+ else if (PPInternal::isComment(input))
+ {
+ skip_comment_or_divop(input, output);
+ }
+ else if (input.current().isSpace())
+ {
+ do {
+ if (input == '\n' || !input.current().isSpace())
+ break;
+
+ } while (!(++input).atEnd());
+
+ output << ' ';
+ }
+ else if (input.current().isNumber())
+ {
+ skip_number (input, output);
+ }
+ else if (input.current().isLetter() || input == '_')
+ {
+ QString name = skip_identifier (input);
+
+ // search for the paste token
+ qint64 blankStart = input.pos();
+ skip_blanks (input, PPInternal::devnull());
+ if (!input.atEnd() && input == '#') {
+ ++input;
+
+ if (!input.atEnd() && input == '#')
+ skip_blanks(++input, PPInternal::devnull());
+ else
+ input.seek(blankStart);
+
+ } else {
+ input.seek(blankStart);
+ }
+
+ Q_ASSERT(name.length() >= 0 && name.length() < 512);
+
+ QString actual = resolve_formal(name);
+ if (!actual.isEmpty()) {
+ output << actual;
+ continue;
+ }
+
+ pp_macro* macro = m_engine->environment().value(name, 0);
+ if (! macro || macro->hidden || m_engine->hideNextMacro())
+ {
+ m_engine->setHideNextMacro(name == "defined");
+ output << name;
+ continue;
+ }
+
+ if (!macro->function_like)
+ {
+ pp_macro_expander expand_macro(m_engine);
+ macro->hidden = true;
+ Stream ms(&macro->definition, QIODevice::ReadOnly);
+ expand_macro(ms, output);
+ macro->hidden = false;
+ continue;
+ }
+
+ // function like macro
+ if (input.atEnd() || input != '(')
+ {
+ output << name;
+ continue;
+ }
+
+ QList<QString> actuals;
+ ++input; // skip '('
+
+ pp_macro_expander expand_actual(m_engine, m_frame);
+
+ qint64 before = input.pos();
+ {
+ actual.clear();
+
+ {
+ Stream as(&actual);
+ skip_argument_variadics(actuals, macro, input, as);
+ }
+
+ if (input.pos() != before)
+ {
+ QString newActual;
+ {
+ Stream as(&actual);
+ Stream nas(&newActual);
+ expand_actual(as, nas);
+ }
+ actuals.append(newActual);
+ }
+ }
+
+ // TODO: why separate from the above?
+ while (!input.atEnd() && input == ',')
+ {
+ actual.clear();
+ ++input; // skip ','
+
+ {
+ {
+ Stream as(&actual);
+ skip_argument_variadics(actuals, macro, input, as);
+ }
+
+ QString newActual;
+ {
+ Stream as(&actual);
+ Stream nas(&newActual);
+ expand_actual(as, nas);
+ }
+ actuals.append(newActual);
+ }
+ }
+
+ //Q_ASSERT(!input.atEnd() && input == ')');
+
+ ++input; // skip ')'
+
+#if 0 // ### enable me
+ assert ((macro->variadics && macro->formals.size () >= actuals.size ())
+ || macro->formals.size() == actuals.size());
+#endif
+
+ pp_frame frame(macro, actuals);
+ pp_macro_expander expand_macro(m_engine, &frame);
+ macro->hidden = true;
+ Stream ms(&macro->definition, QIODevice::ReadOnly);
+ expand_macro(ms, output);
+ macro->hidden = false;
+
+ } else {
+ output << input;
+ ++input;
+ }
+ }
+}
+
+void pp_macro_expander::skip_argument_variadics (const QList<QString>& __actuals, pp_macro *__macro, Stream& input, Stream& output)
+{
+ qint64 first;
+
+ do {
+ first = input.pos();
+ skip_argument(input, output);
+
+ } while ( __macro->variadics
+ && first != input.pos()
+ && !input.atEnd()
+ && input == '.'
+ && (__actuals.size() + 1) == __macro->formals.size());
+}
+
+// kate: indent-width 2;
diff --git a/tests/manual/cppmodelmanager/rpp/pp-macro-expander.h b/tests/manual/cppmodelmanager/rpp/pp-macro-expander.h
new file mode 100644
index 0000000000..933fc90b39
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-macro-expander.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_MACRO_EXPANDER_H
+#define PP_MACRO_EXPANDER_H
+
+#include <QList>
+#include <QHash>
+#include <QString>
+
+#include "pp-macro.h"
+#include "pp-stream.h"
+#include "pp-scanner.h"
+
+class pp;
+
+class pp_frame
+{
+public:
+ pp_frame (pp_macro* __expandingMacro, const QList<QString>& __actuals);
+
+ pp_macro* expandingMacro;
+ QList<QString> actuals;
+};
+
+class pp_macro_expander
+{
+public:
+ pp_macro_expander(pp* engine, pp_frame* frame = 0);
+
+ QString resolve_formal(const QString& name);
+
+ /// Expands text with the known macros. Continues until it finds a new text line
+ /// beginning with #, at which point control is returned.
+ void operator()(Stream& input, Stream& output);
+
+ void skip_argument_variadics (const QList<QString>& __actuals, pp_macro *__macro,
+ Stream& input, Stream& output);
+
+private:
+ pp* m_engine;
+ pp_frame* m_frame;
+
+ pp_skip_number skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_argument skip_argument;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+};
+
+#endif // PP_MACRO_EXPANDER_H
+
+// kate: indent-width 2;
diff --git a/tests/manual/cppmodelmanager/rpp/pp-macro.cpp b/tests/manual/cppmodelmanager/rpp/pp-macro.cpp
new file mode 100644
index 0000000000..397f3df19b
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-macro.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-macro.h"
+
+pp_macro::pp_macro( )
+ : lines(0)
+ , hidden(false)
+ , function_like(false)
+ , variadics(false)
+{
+}
diff --git a/tests/manual/cppmodelmanager/rpp/pp-macro.h b/tests/manual/cppmodelmanager/rpp/pp-macro.h
new file mode 100644
index 0000000000..9d3d4cdd26
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-macro.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_MACRO_H
+#define PP_MACRO_H
+
+#include <QStringList>
+
+class pp_macro
+{
+public:
+ pp_macro();
+
+ QString definition;
+#if defined (PP_WITH_MACRO_POSITION)
+ QString file;
+#endif
+ QStringList formals;
+
+ int lines;
+
+ bool hidden: 1;
+ bool function_like: 1;
+ bool variadics: 1;
+};
+
+#endif // PP_MACRO_H
+
+// kate: indent-width 2;
diff --git a/tests/manual/cppmodelmanager/rpp/pp-scanner.cpp b/tests/manual/cppmodelmanager/rpp/pp-scanner.cpp
new file mode 100644
index 0000000000..d851ede307
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-scanner.cpp
@@ -0,0 +1,289 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <QtCore/QDebug>
+#include "pp-scanner.h"
+
+void pp_skip_blanks::operator()(Stream& input, Stream& output)
+{
+ while (!input.atEnd()) {
+ if (input == '\\') {
+ ++input;
+ if (input != '\n') {
+ --input;
+ return;
+
+ } else {
+ ++input;
+ continue;
+ }
+ }
+
+ if (input == '\n' || !input.current().isSpace())
+ return;
+
+ output << input;
+ ++input;
+ }
+}
+
+void pp_skip_comment_or_divop::operator()(Stream& input, Stream& output, bool outputText)
+{
+ enum {
+ MAYBE_BEGIN,
+ BEGIN,
+ MAYBE_END,
+ END,
+ IN_COMMENT,
+ IN_CXX_COMMENT
+ } state (MAYBE_BEGIN);
+
+ while (!input.atEnd()) {
+ switch (state) {
+ case MAYBE_BEGIN:
+ if (input != '/')
+ return;
+
+ state = BEGIN;
+ break;
+
+ case BEGIN:
+ if (input == '*')
+ state = IN_COMMENT;
+ else if (input == '/')
+ state = IN_CXX_COMMENT;
+ else
+ return;
+ break;
+
+ case IN_COMMENT:
+ if (input == '*')
+ state = MAYBE_END;
+ break;
+
+ case IN_CXX_COMMENT:
+ if (input == '\n')
+ return;
+ break;
+
+ case MAYBE_END:
+ if (input == '/')
+ state = END;
+ else if (input != '*')
+ state = IN_COMMENT;
+ break;
+
+ case END:
+ return;
+ }
+
+ if (outputText)
+ output << input;
+ else if (input == '\n')
+ output << '\n';
+ else
+ output << ' ';
+ ++input;
+ }
+}
+
+QString pp_skip_identifier::operator()(Stream& input)
+{
+ QString identifier;
+
+ while (!input.atEnd()) {
+ if (!input.current().isLetterOrNumber() && input != '_')
+ break;
+
+ identifier.append(input);
+ ++input;
+ }
+
+ return identifier;
+}
+
+void pp_skip_number::operator()(Stream& input, Stream& output)
+{
+ while (!input.atEnd()) {
+ if (!input.current().isLetterOrNumber() && input != '_')
+ return;
+
+ output << input;
+ ++input;
+ }
+}
+
+void pp_skip_string_literal::operator()(Stream& input, Stream& output)
+{
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ while (!input.atEnd()) {
+ switch (state) {
+ case BEGIN:
+ if (input != '\"')
+ return;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ Q_ASSERT(input != '\n');
+
+ if (input == '\"')
+ state = END;
+ else if (input == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+
+ case END:
+ return;
+ }
+
+ output << input;
+ ++input;
+ }
+}
+
+void pp_skip_char_literal::operator()(Stream& input, Stream& output)
+{
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ while (!input.atEnd()) {
+ if (state == END)
+ break;
+
+ switch (state) {
+ case BEGIN:
+ if (input != '\'')
+ return;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ Q_ASSERT(input != '\n');
+
+ if (input == '\'')
+ state = END;
+ else if (input == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+
+ default:
+ Q_ASSERT(0);
+ break;
+ }
+
+ output << input;
+ ++input;
+ }
+}
+
+void pp_skip_argument::operator()(Stream& input, Stream& output)
+{
+ int depth = 0;
+
+ while (!input.atEnd()) {
+ if (!depth && (input == ')' || input == ',')) {
+ return;
+
+ } else if (input == '(') {
+ ++depth;
+
+ } else if (input == ')') {
+ --depth;
+
+ } else if (input == '\"') {
+ skip_string_literal(input, output);
+ continue;
+
+ } else if (input == '\'') {
+ skip_char_literal (input, output);
+ continue;
+
+ } else if (input == '/') {
+ skip_comment_or_divop (input, output);
+ continue;
+
+ } else if (input.current().isLetter() || input == '_') {
+ output << skip_identifier(input);
+ continue;
+
+ } else if (input.current().isNumber()) {
+ output << skip_number(input);
+ continue;
+
+ }
+
+ output << input;
+ ++input;
+ }
+
+ return;
+}
diff --git a/tests/manual/cppmodelmanager/rpp/pp-scanner.h b/tests/manual/cppmodelmanager/rpp/pp-scanner.h
new file mode 100644
index 0000000000..2941a19b74
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-scanner.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_SCANNER_H
+#define PP_SCANNER_H
+
+#include <QString>
+
+#include "pp-stream.h"
+
+class pp_skip_blanks
+{
+public:
+ void operator()(Stream& input, Stream& output);
+};
+
+class pp_skip_comment_or_divop
+{
+public:
+ /**
+ * This scanner can either output equivalent blank space,
+ * or the actual text (the default).
+ */
+ void operator()(Stream& input, Stream& output, bool outputText = false);
+
+private:
+ bool m_outputText;
+};
+
+class pp_skip_identifier
+{
+public:
+ QString operator()(Stream& input);
+};
+
+class pp_skip_number
+{
+public:
+ void operator()(Stream& input, Stream& output);
+};
+
+class pp_skip_string_literal
+{
+public:
+ void operator()(Stream& input, Stream& output);
+};
+
+class pp_skip_char_literal
+{
+public:
+ void operator()(Stream& input, Stream& output);
+};
+
+class pp_skip_argument
+{
+public:
+ void operator()(Stream& input, Stream& output);
+
+private:
+ pp_skip_identifier skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+};
+
+#endif // PP_SCANNER_H
+
+// kate: indent-width 2;
diff --git a/tests/manual/cppmodelmanager/rpp/pp-stream.cpp b/tests/manual/cppmodelmanager/rpp/pp-stream.cpp
new file mode 100644
index 0000000000..91d483db39
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-stream.cpp
@@ -0,0 +1,266 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-stream.h"
+
+#include <QtCore/QDebug>
+
+class DevNullDevice : public QIODevice
+{
+protected:
+ virtual qint64 readData ( char *, qint64 ) { return 0; }
+ virtual qint64 writeData ( const char *, qint64 maxSize ) { return maxSize; }
+};
+
+Stream::Stream()
+ : QTextStream(new DevNullDevice)
+ , m_atEnd(false)
+ , m_isNull(true)
+ , m_pos(0)
+ , m_inputLine(0)
+ , m_outputLine(0)
+{
+}
+
+Stream::Stream( const QByteArray & array, QIODevice::OpenMode openMode )
+ : QTextStream(array, openMode)
+ , m_atEnd(!array.count())
+ , m_isNull(false)
+ , m_pos(0)
+ , m_inputLine(0)
+ , m_outputLine(0)
+{
+ operator>>(c);
+ //kDebug() << "'" << c << "' " << c.cell() << endl;
+}
+
+Stream::Stream( QByteArray * array, QIODevice::OpenMode openMode )
+ : QTextStream(array, openMode)
+ , m_atEnd(!array->count())
+ , m_isNull(false)
+ , m_pos(0)
+ , m_inputLine(0)
+ , m_outputLine(0)
+{
+ operator>>(c);
+ //kDebug() << "'" << c << "' " << c.cell() << endl;
+}
+
+Stream::Stream( QString * string, QIODevice::OpenMode openMode )
+ : QTextStream(string, openMode)
+ , m_atEnd(!string->count())
+ , m_isNull(false)
+ , m_pos(0)
+ , m_inputLine(0)
+ , m_outputLine(0)
+{
+ operator>>(c);
+ //if (!string->isEmpty())
+ //kDebug() << "'" << c << "' " << c.cell() << endl;
+}
+
+Stream::Stream( FILE * fileHandle, QIODevice::OpenMode openMode )
+ : QTextStream(fileHandle, openMode)
+ , m_atEnd(false)
+ , m_isNull(false)
+ , m_pos(0)
+ , m_inputLine(0)
+ , m_outputLine(0)
+{
+ operator>>(c);
+ //kDebug() << "'" << c << "' " << c.cell() << endl;
+}
+
+Stream::Stream( QIODevice * device )
+ : QTextStream(device)
+ , m_atEnd(false)
+ , m_isNull(false)
+ , m_pos(0)
+ , m_inputLine(0)
+ , m_outputLine(0)
+{
+ operator>>(c);
+ //kDebug() << "'" << c << "' " << c.cell() << endl;
+}
+
+Stream::~Stream()
+{
+ if (isNull())
+ delete device();
+}
+
+Stream & Stream::operator ++( )
+{
+ if (m_atEnd)
+ return *this;
+
+ if (c == '\n')
+ ++m_inputLine;
+
+ if (QTextStream::atEnd()) {
+ m_atEnd = true;
+ ++m_pos;
+ c = QChar();
+
+ } else {
+ operator>>(c);
+ //kDebug() << "'" << c << "' " << c.cell() << endl;
+ ++m_pos;
+ }
+ return *this;
+}
+
+Stream& Stream::operator--()
+{
+ seek(pos() - 2);
+ operator>>(c);
+ --m_pos;
+ return *this;
+}
+
+void Stream::rewind(qint64 offset)
+{
+ seek(pos() - offset);
+}
+
+bool Stream::atEnd() const
+{
+ return m_atEnd;
+}
+
+QChar Stream::peek() const
+{
+ Stream* s = const_cast<Stream*>(this);
+ int inputLine = m_inputLine;
+ ++(*s);
+ QChar ret = s->current();
+ s->rewind();
+ inputLine = m_inputLine;
+ return ret;
+}
+
+qint64 Stream::pos( ) const
+{
+ return m_pos;
+}
+
+void Stream::seek(qint64 offset)
+{
+ if (QTextStream::seek(offset)) {
+ m_pos = offset;
+ if (QTextStream::atEnd()) {
+ m_atEnd = true;
+ } else {
+ operator>>(c);
+ m_atEnd = false;
+ }
+ }
+}
+
+Stream& Stream::operator<< ( QChar c )
+{
+ if (!isNull()) {
+ if (c == '\n') {
+ ++m_outputLine;
+ //output.clear();
+ } else {
+ //output += c;
+ }
+ QTextStream::operator<<(c);
+ }
+ return *this;
+}
+
+Stream& Stream::operator<< ( const QString & string )
+{
+ if (!isNull()) {
+ m_outputLine += string.count('\n');
+ //output += c;
+ QTextStream::operator<<(string);
+ }
+ return *this;
+}
+
+int Stream::outputLineNumber() const
+{
+ return m_outputLine;
+}
+
+bool Stream::isNull() const
+{
+ return m_isNull;
+}
+
+int Stream::inputLineNumber() const
+{
+ return m_inputLine;
+}
+
+void Stream::setOutputLineNumber(int line)
+{
+ m_outputLine = line;
+}
+
+void Stream::mark(const QString& filename, int inputLineNumber)
+{
+ QTextStream::operator<<(QString("# %1 \"%2\"\n").arg(inputLineNumber).arg(filename.isEmpty() ? QString("<internal>") : filename));
+ setOutputLineNumber(inputLineNumber);
+}
+
+void Stream::reset( )
+{
+ QTextStream::seek(0);
+ m_inputLine = m_outputLine = m_pos = 0;
+ //output.clear();
+ m_atEnd = false;
+ operator>>(c);
+}
diff --git a/tests/manual/cppmodelmanager/rpp/pp-stream.h b/tests/manual/cppmodelmanager/rpp/pp-stream.h
new file mode 100644
index 0000000000..03ba7dbf52
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/pp-stream.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef STREAM_H
+#define STREAM_H
+
+#include <QTextStream>
+
+/**
+ * Stream designed for character-at-a-time processing
+ *
+ * @author Hamish Rodda <rodda@kde.org>
+ */
+class Stream : private QTextStream
+{
+ public:
+ Stream();
+ Stream( QIODevice * device );
+ Stream( FILE * fileHandle, QIODevice::OpenMode openMode = QIODevice::ReadWrite );
+ Stream( QString * string, QIODevice::OpenMode openMode = QIODevice::ReadWrite );
+ Stream( QByteArray * array, QIODevice::OpenMode openMode = QIODevice::ReadWrite );
+ Stream( const QByteArray & array, QIODevice::OpenMode openMode = QIODevice::ReadOnly );
+ ~Stream();
+
+ bool isNull() const;
+
+ bool atEnd() const;
+
+ qint64 pos() const;
+
+ QChar peek() const;
+
+ /// Move back \a offset chars in the stream
+ void rewind(qint64 offset = 1);
+
+ /// \warning the input and output lines are not updated when calling this function.
+ /// if you're seek()ing over a line boundary, you'll need to fix the line
+ /// numbers.
+ void seek(qint64 offset);
+
+ /// Start from the beginning again
+ void reset();
+
+ inline const QChar& current() const { return c; }
+ inline operator const QChar&() const { return c; }
+ Stream& operator++();
+ Stream& operator--();
+
+ int inputLineNumber() const;
+
+ int outputLineNumber() const;
+ void setOutputLineNumber(int line);
+ void mark(const QString& filename, int inputLineNumber);
+
+ Stream & operator<< ( QChar c );
+ Stream & operator<< ( const QString & string );
+
+ private:
+ Q_DISABLE_COPY(Stream)
+
+ QChar c;
+ bool m_atEnd;
+ bool m_isNull;
+ qint64 m_pos;
+ int m_inputLine, m_outputLine;
+ //QString output;
+};
+
+#endif
diff --git a/tests/manual/cppmodelmanager/rpp/preprocessor.cpp b/tests/manual/cppmodelmanager/rpp/preprocessor.cpp
new file mode 100644
index 0000000000..8d3301396a
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/preprocessor.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Harald Fernengel <harry@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "preprocessor.h"
+
+#include <QFile>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+
+#include "pp-stream.h"
+#include "pp-engine.h"
+
+class PreprocessorPrivate
+{
+public:
+ QString result;
+ QHash<QString, pp_macro*> env;
+ QStringList includePaths;
+};
+
+QHash<QString, QStringList> includedFiles;
+
+Preprocessor::Preprocessor()
+{
+ d = new PreprocessorPrivate;
+ includedFiles.clear();
+}
+
+Preprocessor::~Preprocessor()
+{
+ qDeleteAll(d->env);
+ delete d;
+}
+
+QString Preprocessor::processFile(const QString& fileName)
+{
+ pp proc(this, d->env);
+
+ return proc.processFile(fileName);
+}
+
+QString Preprocessor::processString(const QByteArray &bytearray)
+{
+ pp proc(this, d->env);
+
+ return proc.processFile(bytearray);
+}
+
+void Preprocessor::addIncludePaths(const QStringList &includePaths)
+{
+ d->includePaths += includePaths;
+}
+
+QStringList Preprocessor::macroNames() const
+{
+ return d->env.keys();
+}
+
+QList<Preprocessor::MacroItem> Preprocessor::macros() const
+{
+ QList<MacroItem> items;
+
+ QHashIterator<QString, pp_macro*> it = d->env;
+ while (it.hasNext()) {
+ it.next();
+
+ MacroItem item;
+ item.name = it.key();
+ item.definition = it.value()->definition;
+ item.parameters = it.value()->formals;
+ item.isFunctionLike = it.value()->function_like;
+
+#ifdef PP_WITH_MACRO_POSITION
+ item.fileName = it.value()->file;
+#endif
+ items << item;
+ }
+
+ return items;
+}
+
+Stream * Preprocessor::sourceNeeded(QString &fileName, IncludeType type)
+{
+ Q_UNUSED(type)
+
+ if (!QFile::exists(fileName)) {
+ foreach (const QString& includePath, d->includePaths) {
+ QFileInfo fi(includePath + QLatin1Char('/') + fileName);
+ fileName = QDir::cleanPath(fi.absoluteFilePath());
+ if (QFile::exists(fileName))
+ goto found;
+ }
+
+ return 0L;
+ }
+
+ found:
+ QFile* f = new QFile(fileName);
+ if (!f->open(QIODevice::ReadOnly)) {
+ qWarning() << "Could not open successfully stat-ed file " << fileName << endl;
+ delete f;
+ return 0L;
+ }
+
+ // Hrm, hazardous?
+ f->deleteLater();
+
+ return new Stream(f);
+}
diff --git a/tests/manual/cppmodelmanager/rpp/preprocessor.h b/tests/manual/cppmodelmanager/rpp/preprocessor.h
new file mode 100644
index 0000000000..7a919aa79d
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/preprocessor.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Harald Fernengel <harry@kdevelop.org>
+ Copyright 2006 Hamish Rodda <rodda@kde.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PREPROCESSOR_H
+#define PREPROCESSOR_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+class QByteArray;
+class PreprocessorPrivate;
+class Stream;
+
+class Preprocessor
+{
+public:
+ enum IncludeType {
+ /// An include specified as being local (eg. "file.h")
+ IncludeLocal,
+ /// An include specified as being global (eg. &lt;file.h&gt;)
+ IncludeGlobal
+ };
+
+ Preprocessor();
+ virtual ~Preprocessor();
+
+ QString processFile(const QString &fileName);
+ QString processString(const QByteArray &str);
+
+ void addIncludePaths(const QStringList &includePaths);
+
+ /**
+ * This function is called by the preprocessor whenever
+ * it encounters an include directive.
+ *
+ * This class is permitted to modify \a fileName%; this
+ * value will be used when marking the file in the preprocessed
+ * output.
+ *
+ * \param fileName name of the source file to include
+ * \param type the way that the file was requested
+ *
+ * \return a Stream with the appropriate contents to allow
+ * the file to be #included. Ownership of the Stream is yielded to
+ * class pp at this point.
+ */
+ virtual Stream* sourceNeeded(QString& fileName, IncludeType type);
+
+ QStringList macroNames() const;
+
+ struct MacroItem
+ {
+ QString name;
+ QStringList parameters;
+ QString definition;
+ bool isFunctionLike;
+#ifdef PP_WITH_MACRO_POSITION
+ QString fileName;
+#endif
+ };
+ QList<MacroItem> macros() const;
+
+private:
+ Q_DISABLE_COPY(Preprocessor)
+ PreprocessorPrivate *d;
+};
+
+#endif
diff --git a/tests/manual/cppmodelmanager/rpp/rpp.pri b/tests/manual/cppmodelmanager/rpp/rpp.pri
new file mode 100644
index 0000000000..542015edd6
--- /dev/null
+++ b/tests/manual/cppmodelmanager/rpp/rpp.pri
@@ -0,0 +1,20 @@
+VPATH += $$PWD
+
+SOURCES += pp-engine.cpp \
+ pp-internal.cpp \
+ pp-macro-expander.cpp \
+ pp-macro.cpp \
+ pp-scanner.cpp \
+ pp-stream.cpp \
+ preprocessor.cpp
+
+HEADERS += pp-engine.h \
+ pp-internal.h \
+ pp-macro-expander.h \
+ pp-macro.h \
+ pp-scanner.h \
+ pp-stream.h \
+ preprocessor.h
+
+
+INCLUDEPATH += $$PWD \ No newline at end of file
diff --git a/tests/manual/dockwidgets/dockwidgets.pro b/tests/manual/dockwidgets/dockwidgets.pro
new file mode 100644
index 0000000000..7a836c967d
--- /dev/null
+++ b/tests/manual/dockwidgets/dockwidgets.pro
@@ -0,0 +1,11 @@
+INCLUDEPATH += ../../../src/lib/
+
+HEADERS = mainwindow.h \
+ ../../../src/lib/qdockarrows.h \
+ ../../../src/lib/qdockarrows_p.h \
+ ../../../src/lib/tabpositionindicator.h
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ ../../../src/lib/qdockarrows.cpp \
+ ../../../src/lib/tabpositionindicator.cpp
+
diff --git a/tests/manual/dockwidgets/main.cpp b/tests/manual/dockwidgets/main.cpp
new file mode 100644
index 0000000000..3df4beaa80
--- /dev/null
+++ b/tests/manual/dockwidgets/main.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2005-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow mainWin;
+ mainWin.show();
+ return app.exec();
+}
diff --git a/tests/manual/dockwidgets/mainwindow.cpp b/tests/manual/dockwidgets/mainwindow.cpp
new file mode 100644
index 0000000000..d2f5f42242
--- /dev/null
+++ b/tests/manual/dockwidgets/mainwindow.cpp
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2005-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+
+#include "qdockarrows.h"
+#include "mainwindow.h"
+
+class TestTool : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TestTool(QWidget *parent = 0) : QWidget(parent) {
+ m_widget = new QLabel("Test", this);
+ qDebug() << m_tmp.width() << m_tmp.height();
+ }
+
+ QSize sizeHint() const
+ {
+ return QSize(20, 100);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event)
+ {
+ m_widget->setVisible(false);
+
+ QStyleOptionTabV2 opt;
+ opt.initFrom(this);
+ opt.shape = QTabBar::RoundedWest;
+ opt.text = tr("Hello");
+
+ QStylePainter p(this);
+ p.drawControl(QStyle::CE_TabBarTab, opt);
+
+ m_tmp = QPixmap::grabWidget(m_widget, 10, 0, 10, 10);
+
+ QPainter pn(this);
+ pn.drawPixmap(0,0,m_tmp);
+
+ QWidget::paintEvent(event);
+ }
+
+private:
+ QPixmap m_tmp;
+ QLabel *m_widget;
+};
+#include "mainwindow.moc"
+
+MainWindow::MainWindow()
+{
+ centralWidget = new QLabel(tr("Central Widget"));
+ setCentralWidget(centralWidget);
+
+ QToolBar *tb = this->addToolBar("Normal Toolbar");
+ tb->addAction("Test");
+
+ tb = this->addToolBar("Test Toolbar");
+ tb->setMovable(false);
+ tb->addWidget(new TestTool(this));
+ this->addToolBar(Qt::RightToolBarArea, tb);
+
+ createDockWindows();
+
+ setWindowTitle(tr("Dock Widgets"));
+}
+
+void MainWindow::createDockWindows()
+{
+ QDockArrowManager *manager = new QDockArrowManager(this);
+
+ for (int i=0; i<5; ++i) {
+ QArrowManagedDockWidget *dock = new QArrowManagedDockWidget(manager);
+ QLabel *label = new QLabel(tr("Widget %1").arg(i), dock);
+ label->setWindowTitle(tr("Widget %1").arg(i));
+ label->setObjectName(tr("widget_%1").arg(i));
+ dock->setObjectName(tr("dock_%1").arg(i));
+ dock->setWidget(label);
+ addDockWidget(Qt::RightDockWidgetArea, dock);
+ }
+}
diff --git a/tests/manual/dockwidgets/mainwindow.h b/tests/manual/dockwidgets/mainwindow.h
new file mode 100644
index 0000000000..159d66c9f7
--- /dev/null
+++ b/tests/manual/dockwidgets/mainwindow.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 2005-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+class QLabel;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+private:
+ void createDockWindows();
+
+ QLabel *centralWidget;
+};
+
+#endif
diff --git a/tests/manual/gdbdebugger/script/math.js b/tests/manual/gdbdebugger/script/math.js
new file mode 100644
index 0000000000..0fd14f2b9d
--- /dev/null
+++ b/tests/manual/gdbdebugger/script/math.js
@@ -0,0 +1,6 @@
+
+ function cube(a) {
+ return a * a * a;
+ }
+
+ var a = cube(3);
diff --git a/tests/manual/gdbdebugger/script/script.pro b/tests/manual/gdbdebugger/script/script.pro
new file mode 100644
index 0000000000..b1f98ef331
--- /dev/null
+++ b/tests/manual/gdbdebugger/script/script.pro
@@ -0,0 +1,4 @@
+
+TEMPLATE = script
+TARGET = math.js
+SOURCES += math.js
diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp
new file mode 100644
index 0000000000..9cfbdfefff
--- /dev/null
+++ b/tests/manual/gdbdebugger/simple/app.cpp
@@ -0,0 +1,827 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+/****************************************************************************
+**
+** Copyright (C) 2004-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QLibrary>
+#include <QtCore/QMap>
+#include <QtCore/QPointer>
+#include <QtCore/QString>
+#include <QtCore/QThread>
+#include <QtCore/QVariant>
+#include <QtCore/QVector>
+
+#include <QtGui/QApplication>
+#include <QtGui/QAction>
+#include <QtGui/QColor>
+#include <QtGui/QFont>
+#include <QtGui/QLabel>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+
+#include <QtNetwork/QHostAddress>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#endif
+
+
+uint qHash(const QMap<int, int> &)
+{
+ return 0;
+}
+
+uint qHash(const double & f)
+{
+ return int(f);
+}
+
+class Foo
+{
+public:
+ Foo(int i=0)
+ : a(i), b(2)
+ {
+ int s = 1;
+ int t = 2;
+ b = 2 + s + t;
+ a += 1;
+ }
+ void doit()
+ {
+ static QObject ob;
+ m["1"] = "2";
+ h[&ob] = m.begin();
+
+ a += 1;
+ --b;
+ //s += 'x';
+ }
+
+
+ struct Bar {
+ Bar() : ob(0) {}
+ QObject *ob;
+ };
+
+public:
+ int a, b;
+ char x[6];
+
+private:
+ //QString s;
+ typedef QMap<QString, QString> Map;
+ Map m;
+ QHash<QObject *, Map::iterator> h;
+};
+
+void testArray()
+{
+ QString x[4];
+ x[0] = "a";
+ x[1] = "b";
+ x[2] = "c";
+ x[3] = "d";
+
+ Foo foo[10];
+ //for (int i = 0; i != sizeof(foo)/sizeof(foo[0]); ++i) {
+ for (int i = 0; i < 5; ++i) {
+ foo[i].a = i;
+ foo[i].doit();
+ }
+}
+
+
+void testByteArray()
+{
+ QByteArray ba = "Hello";
+ ba += '"';
+ ba += "World";
+ ba += char(0);
+ ba += 1;
+ ba += 2;
+}
+
+
+void testHash()
+{
+ QHash<int, float> hgg0;
+ hgg0[11] = 11.0;
+ hgg0[22] = 22.0;
+
+
+ QHash<QString, float> hgg1;
+ hgg1["22.0"] = 22.0;
+
+ QHash<int, QString> hgg2;
+ hgg2[22] = "22.0";
+
+ QHash<QString, Foo> hgg3;
+ hgg3["22.0"] = Foo(22);
+ hgg3["33.0"] = Foo(33);
+
+ QObject ob;
+ QHash<QString, QPointer<QObject> > hash;
+ hash.insert("Hallo", QPointer<QObject>(&ob));
+ hash.insert("Welt", QPointer<QObject>(&ob));
+ hash.insert(".", QPointer<QObject>(&ob));
+}
+
+void testImage()
+{
+ QImage im(QSize(200, 200), QImage::Format_RGB32);
+ im.fill(QColor(200, 100, 130).rgba());
+ QPainter pain;
+ pain.begin(&im);
+ pain.drawLine(2, 2, 130, 130);
+ pain.drawLine(4, 2, 130, 140);
+ pain.drawRect(30, 30, 80, 80);
+ pain.end();
+}
+
+void testIO()
+{
+ qDebug() << "qDebug() 1";
+ qDebug() << "qDebug() 2";
+ qDebug() << "qDebug() 3";
+
+ std::cout << "std::cout @@ 1" << std::endl;
+ std::cout << "std::cout @@ 2\n";
+ std::cout << "std::cout @@ 3" << std::endl;
+
+ std::cerr << "std::cerr 1\n";
+ std::cerr << "std::cerr 2\n";
+ std::cerr << "std::cerr 3\n";
+}
+
+
+void testList()
+{
+#if 1
+ QList<int> li;
+ QList<uint> lu;
+
+ for (int i = 0; i != 3; ++i) {
+ li.append(i);
+ }
+ li.append(101);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+ li.append(102);
+
+
+ for (int i = 0; i != 3; ++i) {
+ lu.append(i);
+ }
+ lu.append(101);
+ lu.append(102);
+ lu.append(102);
+ lu.append(102);
+ lu.append(102);
+ lu.append(102);
+ lu.append(102);
+ lu.append(102);
+ lu.append(102);
+
+ QList<uint> i;
+ i.append(42);
+ i.append(43);
+ i.append(44);
+ i.append(45);
+
+ QList<qulonglong> l;
+ l.append(42);
+ l.append(43);
+ l.append(44);
+ l.append(45);
+
+ QList<Foo> f;
+ f.append(Foo(1));
+ f.append(Foo(2));
+#endif
+ QList<std::string> v;
+
+ v.push_back("aa");
+ v.push_back("bb");
+ v.push_back("cc");
+ v.push_back("dd");
+ }
+
+void testMap()
+{
+ QMap<uint, QStringList> ggl;
+ ggl[11] = QStringList() << "11";
+ ggl[22] = QStringList() << "22";
+
+ typedef QMap<uint, QStringList> T;
+ T ggt;
+ ggt[11] = QStringList() << "11";
+ ggt[22] = QStringList() << "22";
+
+#if 0
+ QMap<uint, float> gg0;
+ gg0[11] = 11.0;
+ gg0[22] = 22.0;
+
+
+ QMap<QString, float> gg1;
+ gg1["22.0"] = 22.0;
+
+ QMap<int, QString> gg2;
+ gg2[22] = "22.0";
+
+ QMap<QString, Foo> gg3;
+ gg3["22.0"] = Foo(22);
+ gg3["33.0"] = Foo(33);
+
+ QObject ob;
+ QMap<QString, QPointer<QObject> > map;
+ map.insert("Hallo", QPointer<QObject>(&ob));
+ map.insert("Welt", QPointer<QObject>(&ob));
+ map.insert(".", QPointer<QObject>(&ob));
+#endif
+}
+
+void testObject(int &argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QAction act("xxx", &app);
+ QString t = act.text();
+ t += "y";
+
+/*
+ QObject ob(&app);
+ ob.setObjectName("An Object");
+ QObject ob1;
+ ob1.setObjectName("Another Object");
+
+ QObject::connect(&ob, SIGNAL(destroyed()), &ob1, SLOT(deleteLater()));
+ QObject::connect(&app, SIGNAL(lastWindowClosed()), &ob, SLOT(deleteLater()));
+
+ QList<QObject *> obs;
+ obs.append(&ob);
+ obs.append(&ob1);
+ obs.append(0);
+ obs.append(&app);
+ ob1.setObjectName("A Subobject");
+*/
+ QLabel l("XXXXXXXXXXXXXXXXX");
+ l.show();
+ app.exec();
+}
+
+void testPixmap()
+{
+ QImage im(QSize(200, 200), QImage::Format_RGB32);
+ im.fill(QColor(200, 100, 130).rgba());
+ QPainter pain;
+ pain.begin(&im);
+ pain.drawLine(2, 2, 130, 130);
+ pain.end();
+ QPixmap pm = QPixmap::fromImage(im);
+ int i = 1;
+ Q_UNUSED(i);
+}
+
+void testPlugin()
+{
+ QString dir = QDir::currentPath();
+#ifdef Q_OS_LINUX
+ QLibrary lib(dir + "/libplugin.so");
+#endif
+#ifdef Q_OS_MAC
+ dir = QFileInfo(dir + "/../..").canonicalPath();
+ QLibrary lib(dir + "/libplugin.dylib");
+#endif
+#ifdef Q_OS_WIN
+ QLibrary lib(dir + "/plugin.dll");
+#endif
+ int (*foo)() = (int(*)()) lib.resolve("pluginTest");
+ qDebug() << "library resolve: " << foo;
+ if (foo) {
+ int res = foo();
+ res += 1;
+ } else {
+ qDebug() << lib.errorString();
+ }
+}
+
+void stringRefTest(const QString &refstring)
+{
+ Q_UNUSED(refstring);
+}
+
+
+int F(int a, int b)
+{
+ return a + b;
+}
+
+int add(int i) { return i + 2; }
+
+int mul(int i) { return i * 2; }
+
+
+void testStdVector()
+{
+ int x = F(add(1), mul(2));
+ Q_UNUSED(x);
+ std::vector<int *> plist1;
+ plist1.push_back(new int(1));
+ plist1.push_back(0);
+ plist1.push_back(new int(2));
+
+ std::vector<int> flist2;
+ flist2.push_back(1);
+ flist2.push_back(2);
+ flist2.push_back(3);
+ flist2.push_back(4);
+
+ int a = 1;
+ int b = 0;
+
+ while (0) {
+ a += 1;
+ if (b)
+ break;
+ }
+
+ flist2.push_back(1);
+ flist2.push_back(2);
+ flist2.push_back(3);
+ flist2.push_back(4);
+
+ std::vector<Foo *> plist;
+ plist.push_back(new Foo(1));
+ plist.push_back(0);
+ plist.push_back(new Foo(2));
+
+ std::vector<Foo> flist;
+ flist.push_back(1);
+
+ flist.push_back(2);
+ flist.push_back(3);
+ flist.push_back(4);
+ //flist.takeFirst();
+ //flist.takeFirst();
+
+ std::vector<bool> vec;
+ vec.push_back(true);
+ vec.push_back(false);
+}
+
+void testStdString()
+{
+ QString foo;
+ std::string str;
+ std::wstring wstr;
+
+ std::vector<std::string> v;
+
+ foo += "a";
+ str += "b";
+ wstr += wchar_t('e');
+ foo += "c";
+ str += "d";
+ foo += "e";
+ wstr += wchar_t('e');
+ str += "e";
+ foo += "a";
+ str += "b";
+ foo += "c";
+ str += "d";
+ str += "e";
+ wstr += wchar_t('e');
+ wstr += wchar_t('e');
+ str += "e";
+
+ QList<std::string> l;
+
+ l.push_back(str);
+ l.push_back(str);
+ l.push_back(str);
+ l.push_back(str);
+
+ v.push_back(str);
+ v.push_back(str);
+ v.push_back(str);
+ v.push_back(str);
+}
+
+void testString()
+{
+ QString str = "Hello ";
+ str += " big, ";
+ str += " fat ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+ str += " World ";
+}
+
+void testString3()
+{
+ QString str = "Hello ";
+ str += " big, ";
+ str += " fat ";
+ str += " World ";
+
+ QString string("String Test");
+ QString *pstring = new QString("Pointer String Test");
+ stringRefTest(QString("Ref String Test"));
+ string = "Hi";
+ string += "Du";
+ qDebug() << string;
+ delete pstring;
+}
+
+void testStringList()
+{
+ QStringList l;
+ l << "Hello ";
+ l << " big, ";
+ l << " fat ";
+ l << " World ";
+}
+
+void testStruct()
+{
+ Foo f(2);
+ f.doit();
+ f.doit();
+ f.doit();
+}
+
+class Thread : public QThread
+{
+public:
+ Thread(int id) : m_id(id) {}
+
+ void run()
+ {
+ for (int i = 0; i != 100000; ++i) {
+ //sleep(1);
+ std::cerr << m_id;
+ }
+ }
+
+private:
+ int m_id;
+};
+
+void testThreads()
+{
+ Thread thread1(1);
+ Thread thread2(2);
+ thread1.start();
+ thread2.start();
+ thread1.wait();
+ thread2.wait();
+}
+
+void testVariant1()
+{
+ QVariant v;
+ v = 1;
+ v = 1.0;
+ v = "string";
+ v = 1;
+}
+
+void testVariant2()
+{
+ QVariant var;
+#if 0
+ QVariant var3;
+ QHostAddress ha("127.0.0.1");
+ qVariantSetValue(var, ha);
+ var3 = var;
+ var3 = var;
+ var3 = var;
+ var3 = var;
+ QHostAddress ha1 = var.value<QHostAddress>();
+#endif
+ typedef QMap<uint, QStringList> MyType;
+ MyType my;
+ my[1] = (QStringList() << "Hello");
+ my[3] = (QStringList() << "World");
+ var.setValue(my);
+ QString type = var.typeName();
+ var.setValue(my);
+ var.setValue(my);
+ var.setValue(my);
+ var.setValue(my);
+}
+
+void testVariant3()
+{
+ QList<int> list;
+ list << 1 << 2 << 3;
+ QVariant variant = qVariantFromValue(list);
+ list.clear();
+ list = qVariantValue<QList<int> >(variant);
+}
+
+void testVector()
+{
+ QVector<Foo *> plist;
+ plist.append(new Foo(1));
+ plist.append(0);
+ plist.append(new Foo(2));
+
+ QVector<Foo> flist;
+ flist.append(1);
+
+ flist.append(2);
+ flist.append(3);
+ flist.append(4);
+ //flist.takeFirst();
+ //flist.takeFirst();
+
+ QVector<bool> vec;
+ vec.append(true);
+ vec.append(false);
+}
+
+void testVectorOfList()
+{
+ QVector<QList<int> > v;
+ QVector<QList<int> > *pv = &v;
+ v.append(QList<int>() << 1);
+ v.append(QList<int>() << 2 << 3);
+ Q_UNUSED(pv);
+}
+
+void foo() {}
+void foo(int) {}
+void foo(QList<int>) {}
+void foo(QList<QVector<int> >) {}
+void foo(QList<QVector<int> *>) {}
+void foo(QList<QVector<int *> *>) {}
+
+template <class T>
+void foo(QList<QVector<T> *>) {}
+
+namespace {
+
+namespace A { int barz() { return 42;} }
+namespace B { int barz() { return 43;} }
+
+}
+
+namespace somespace {
+
+class MyBase : public QObject
+{
+public:
+ MyBase() {}
+ virtual void doit(int i)
+ {
+ n = i;
+ }
+protected:
+ int n;
+};
+
+namespace nested {
+
+class MyFoo : public MyBase
+{
+public:
+ MyFoo() {}
+ virtual void doit(int i)
+ {
+ n = i;
+ }
+protected:
+ int n;
+};
+
+class MyBar : public MyFoo
+{
+public:
+ virtual void doit(int i)
+ {
+ n = i + 1;
+ }
+};
+
+namespace {
+
+class MyAnon : public MyBar
+{
+public:
+ virtual void doit(int i)
+ {
+ n = i + 3;
+ }
+};
+
+namespace baz {
+
+class MyBaz : public MyAnon
+{
+public:
+ virtual void doit(int i)
+ {
+ n = i + 5;
+ }
+};
+
+} // namespace baz
+
+} // namespace anon
+
+
+} // namespace nested
+} // namespace somespace
+
+void testNamespace()
+{
+ using namespace somespace;
+ using namespace nested;
+ MyFoo foo;
+ MyBar bar;
+ MyAnon anon;
+ baz::MyBaz baz;
+ baz.doit(1);
+ anon.doit(1);
+ foo.doit(1);
+ bar.doit(1);
+ bar.doit(1);
+ bar.doit(1);
+ bar.doit(1);
+ bar.doit(1);
+ bar.doit(1);
+ bar.doit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ testIO();
+ //QString s;
+ //s = "hallo";
+ //QList<QVector<int> *> vi;
+ //QList<QVector<double> *> vd;
+ //int n = A::barz();
+
+
+ int n = 1;
+ n = 2;
+ n = 3;
+ n = 3;
+ n = 3;
+ n = 3;
+ n = 3;
+ n = 3;
+ n = 3;
+ {
+ QString n = "2";
+ n = "3";
+ n = "4";
+ {
+ double n = 3.5;
+ ++n;
+ ++n;
+ }
+ n = "3";
+ n = "4";
+ }
+ ++n;
+ ++n;
+
+ testArray();
+ testStdVector();
+ testStdString();
+
+ testPlugin();
+ testList();
+ testNamespace();
+ //return 0;
+ testByteArray();
+ testHash();
+ testImage();
+ testMap();
+ testString();
+ testStringList();
+ testStruct();
+ //testThreads();
+ testVariant1();
+ testVariant2();
+ testVariant3();
+ testVector();
+ testVectorOfList();
+ testObject(argc, argv);
+
+ //QColor color(255,128,10);
+ //QFont font;
+
+ while(true)
+ ;
+
+ return 0;
+}
+
+//Q_DECLARE_METATYPE(QHostAddress)
+Q_DECLARE_METATYPE(QList<int>)
+
+//#define COMMA ,
+//Q_DECLARE_METATYPE(QMap<uint COMMA QStringList>)
+
+QT_BEGIN_NAMESPACE
+
+template <>
+struct QMetaTypeId<QHostAddress>
+{
+ enum { Defined = 1 };
+ static int qt_metatype_id()
+ {
+ static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (!metatype_id)
+ metatype_id = qRegisterMetaType<QHostAddress>("myns::QHostAddress");
+ return metatype_id; \
+ } \
+};
+
+template <>
+struct QMetaTypeId< QMap<uint, QStringList> >
+{
+ enum { Defined = 1 };
+ static int qt_metatype_id()
+ {
+ static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (!metatype_id)
+ metatype_id = qRegisterMetaType< QMap<uint, QStringList> >("myns::QMap<uint, myns::QStringList>");
+ return metatype_id; \
+ } \
+};
+QT_END_NAMESPACE
diff --git a/tests/manual/gdbdebugger/simple/app/app.pro b/tests/manual/gdbdebugger/simple/app/app.pro
new file mode 100644
index 0000000000..bf168bab10
--- /dev/null
+++ b/tests/manual/gdbdebugger/simple/app/app.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET = debuggertest
+DEPENDPATH += .
+INCLUDEPATH += .
+DESTDIR = ..
+
+# Input
+SOURCES += ../app.cpp
+QT += network
diff --git a/tests/manual/gdbdebugger/simple/plugin.cpp b/tests/manual/gdbdebugger/simple/plugin.cpp
new file mode 100644
index 0000000000..36edb806b5
--- /dev/null
+++ b/tests/manual/gdbdebugger/simple/plugin.cpp
@@ -0,0 +1,45 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+
+#include <stdio.h>
+#include <qglobal.h>
+
+extern "C" Q_DECL_EXPORT int pluginTest()
+{
+ int s = 0;
+ for (int i = 1; i != 2000; ++i)
+ s += i;
+ fprintf(stderr, "in plugin test");
+ return s;
+}
diff --git a/tests/manual/gdbdebugger/simple/plugin/plugin.pro b/tests/manual/gdbdebugger/simple/plugin/plugin.pro
new file mode 100644
index 0000000000..911dc2481e
--- /dev/null
+++ b/tests/manual/gdbdebugger/simple/plugin/plugin.pro
@@ -0,0 +1,18 @@
+TEMPLATE = lib
+TARGET = plugin
+DESTDIR = ..
+CONFIG += shared
+
+SOURCES += ../plugin.cpp
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/
+} else:linux-* {
+ #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ QMAKE_RPATHDIR += \$\$ORIGIN/..
+ IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":")
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\'
+ QMAKE_RPATHDIR =
+}
+
+
diff --git a/tests/manual/gdbdebugger/simple/simple.pro b/tests/manual/gdbdebugger/simple/simple.pro
new file mode 100644
index 0000000000..78c70731cd
--- /dev/null
+++ b/tests/manual/gdbdebugger/simple/simple.pro
@@ -0,0 +1,4 @@
+
+TEMPLATE = subdirs
+
+SUBDIRS += app plugin
diff --git a/tests/manual/gdbdebugger/spacy path/app with space.cpp b/tests/manual/gdbdebugger/spacy path/app with space.cpp
new file mode 100644
index 0000000000..c5969e5f96
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy path/app with space.cpp
@@ -0,0 +1,419 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2004-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QLibrary>
+#include <QtCore/QMap>
+#include <QtCore/QPointer>
+#include <QtCore/QString>
+#include <QtCore/QThread>
+#include <QtCore/QVariant>
+#include <QtCore/QVector>
+
+#include <QtGui/QApplication>
+#include <QtGui/QAction>
+#include <QtGui/QColor>
+#include <QtGui/QFont>
+#include <QtGui/QLabel>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+
+#include <QtNetwork/QHostAddress>
+
+#include <iostream>
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#endif
+
+
+uint qHash(const QMap<int, int> &)
+{
+ return 0;
+}
+
+uint qHash(const double & f)
+{
+ return int(f);
+}
+
+class Foo
+{
+public:
+ Foo(int i=0)
+ : a(i), b(2)
+ {
+
+ }
+ void doit()
+ {
+ static QObject ob;
+ m["1"] = "2";
+ h[&ob] = m.begin();
+
+ a += 1;
+ --b;
+ //s += 'x';
+ }
+
+
+ struct Bar {
+ Bar() : ob(0) {}
+ QObject *ob;
+ };
+
+public:
+ int a, b;
+ char x[6];
+
+private:
+ //QString s;
+ typedef QMap<QString, QString> Map;
+ Map m;
+ QHash<QObject *, Map::iterator> h;
+};
+
+void testArray()
+{
+ QString x[4];
+ x[0] = "a";
+ x[1] = "b";
+ x[2] = "c";
+ x[3] = "d";
+
+ Foo foo[100];
+ //for (int i = 0; i != sizeof(foo)/sizeof(foo[0]); ++i) {
+ for (int i = 0; i < 5; ++i) {
+ foo[i].a = i;
+ foo[i].doit();
+ }
+}
+
+void testByteArray()
+{
+ QByteArray ba = "Hello";
+ ba += '"';
+ ba += "World";
+ ba += char(0);
+ ba += 1;
+ ba += 2;
+}
+
+void testHash()
+{
+ QHash<int, float> hgg0;
+ hgg0[11] = 11.0;
+ hgg0[22] = 22.0;
+
+
+ QHash<QString, float> hgg1;
+ hgg1["22.0"] = 22.0;
+
+ QHash<int, QString> hgg2;
+ hgg2[22] = "22.0";
+
+ QHash<QString, Foo> hgg3;
+ hgg3["22.0"] = Foo(22);
+ hgg3["33.0"] = Foo(33);
+
+ QObject ob;
+ QHash<QString, QPointer<QObject> > hash;
+ hash.insert("Hallo", QPointer<QObject>(&ob));
+ hash.insert("Welt", QPointer<QObject>(&ob));
+ hash.insert(".", QPointer<QObject>(&ob));
+}
+
+void testImage()
+{
+ QImage im(QSize(200, 200), QImage::Format_RGB32);
+ im.fill(QColor(200, 100, 130).rgba());
+ QPainter pain;
+ pain.begin(&im);
+ pain.drawLine(2, 2, 130, 130);
+ pain.drawLine(4, 2, 130, 140);
+ pain.drawRect(30, 30, 80, 80);
+ pain.end();
+}
+
+void testIO()
+{
+ qDebug() << "qDebug() 1";
+ qDebug() << "qDebug() 2";
+ qDebug() << "qDebug() 3";
+
+ std::cout << "std::cout @@ 1\n";
+ std::cout << "std::cout @@ 2\n";
+ std::cout << "std::cout @@ 3\n";
+
+ std::cerr << "std::cerr 1\n";
+ std::cerr << "std::cerr 2\n";
+ std::cerr << "std::cerr 3\n";
+};
+
+
+void testList()
+{
+ QList<int> foo;
+ for (int i = 0; i != 100; ++i) {
+ foo.append(i);
+ }
+ foo.append(101);
+ foo.append(102);
+ }
+
+void testMap()
+{
+ QMap<int, float> gg0;
+ gg0[11] = 11.0;
+ gg0[22] = 22.0;
+
+
+ QMap<QString, float> gg1;
+ gg1["22.0"] = 22.0;
+
+ QMap<int, QString> gg2;
+ gg2[22] = "22.0";
+
+ QMap<QString, Foo> gg3;
+ gg3["22.0"] = Foo(22);
+ gg3["33.0"] = Foo(33);
+
+ QObject ob;
+ QMap<QString, QPointer<QObject> > map;
+ map.insert("Hallo", QPointer<QObject>(&ob));
+ map.insert("Welt", QPointer<QObject>(&ob));
+ map.insert(".", QPointer<QObject>(&ob));
+}
+
+void testObject(int &argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QAction act("xxx", &app);
+ QString t = act.text();
+ t += "y";
+
+/*
+ QObject ob(&app);
+ ob.setObjectName("An Object");
+ QObject ob1;
+ ob1.setObjectName("Another Object");
+
+ QObject::connect(&ob, SIGNAL(destroyed()), &ob1, SLOT(deleteLater()));
+ QObject::connect(&app, SIGNAL(lastWindowClosed()), &ob, SLOT(deleteLater()));
+
+ QList<QObject *> obs;
+ obs.append(&ob);
+ obs.append(&ob1);
+ obs.append(0);
+ obs.append(&app);
+ ob1.setObjectName("A Subobject");
+*/
+ QLabel l("XXXXXXXXXXXXXXXXX");
+ l.show();
+ app.exec();
+}
+
+void testPixmap()
+{
+ QImage im(QSize(200, 200), QImage::Format_RGB32);
+ im.fill(QColor(200, 100, 130).rgba());
+ QPainter pain;
+ pain.begin(&im);
+ pain.drawLine(2, 2, 130, 130);
+ pain.end();
+ QPixmap pm = QPixmap::fromImage(im);
+ int i = 1;
+ Q_UNUSED(i);
+}
+
+void testPlugin()
+{
+ QString dir = QDir::currentPath();
+#ifdef Q_OS_LINUX
+ QLibrary lib(dir + "/libplugin.so");
+#endif
+ int (*foo)() = (int(*)()) lib.resolve("pluginTest");
+ qDebug() << "library resolve: " << foo;
+ if (foo) {
+ int res = foo();
+ res += 1;
+ } else {
+ qDebug() << lib.errorString();
+ }
+}
+
+void stringRefTest(const QString &refstring)
+{
+ Q_UNUSED(refstring);
+}
+
+void testString()
+{
+ QString str = "Hello ";
+ str += " big, ";
+ str += " fat ";
+ str += " World ";
+
+ QString string("String Test");
+ QString *pstring = new QString("Pointer String Test");
+ stringRefTest(QString("Ref String Test"));
+ string = "Hi";
+ string += "Du";
+ qDebug() << string;
+ delete pstring;
+}
+
+void testStringList()
+{
+ QStringList l;
+ l << "Hello ";
+ l << " big, ";
+ l << " fat ";
+ l << " World ";
+}
+
+void testStruct()
+{
+ Foo f(2);
+ f.doit();
+ f.doit();
+ f.doit();
+};
+
+class Thread : public QThread
+{
+public:
+ Thread(int id) : m_id(id) {}
+
+ void run()
+ {
+ for (int i = 0; i != 100000; ++i) {
+ //sleep(1);
+ std::cerr << m_id;
+ }
+ }
+
+private:
+ int m_id;
+};
+
+void testThreads()
+{
+ Thread thread1(1);
+ Thread thread2(2);
+ thread1.start();
+ thread2.start();
+ thread1.wait();
+ thread2.wait();
+}
+
+void testVariant1()
+{
+ QVariant v;
+ v = 1;
+ v = 1.0;
+ v = "string";
+ v = 1;
+}
+
+void testVariant2()
+{
+ QVariant var;
+ QVariant var3;
+ QHostAddress ha("127.0.0.1");
+ qVariantSetValue(var, ha);
+ var3 = var;
+ var3 = var;
+ var3 = var;
+ var3 = var;
+ QHostAddress ha1 = var.value<QHostAddress>();
+}
+
+void testVariant3()
+{
+ QList<int> list;
+ list << 1 << 2 << 3;
+ QVariant variant = qVariantFromValue(list);
+ list.clear();
+ list = qVariantValue<QList<int> >(variant);
+}
+
+void testVector()
+{
+ QVector<Foo *> plist;
+ plist.append(new Foo(1));
+ plist.append(0);
+ plist.append(new Foo(2));
+
+ QVector<Foo> flist;
+ flist.append(1);
+
+ flist.append(2);
+ flist.append(3);
+ flist.append(4);
+ //flist.takeFirst();
+ //flist.takeFirst();
+
+ QVector<bool> vec;
+ vec.append(true);
+ vec.append(false);
+}
+
+void testVectorOfList()
+{
+ QVector<QList<int> > v;
+ QVector<QList<int> > *pv = &v;
+ v.append(QList<int>() << 1);
+ v.append(QList<int>() << 2 << 3);
+ Q_UNUSED(pv);
+}
+
+int main(int argc, char *argv[])
+{
+ testArray();
+ testPlugin();
+ testList();
+ return 0;
+ testByteArray();
+ testHash();
+ testImage();
+ testIO();
+ testMap();
+ testString();
+ testStringList();
+ testStruct();
+ testThreads();
+ testVariant1();
+ testVariant2();
+ testVariant3();
+ testVector();
+ testVectorOfList();
+
+ testObject(argc, argv);
+
+ QColor color(255,128,10);
+ QFont font;
+
+ while(true)
+ ;
+
+ return 0;
+}
+
+Q_DECLARE_METATYPE(QHostAddress)
+Q_DECLARE_METATYPE(QList<int>)
+
+
diff --git a/tests/manual/gdbdebugger/spacy path/plugin with space.cpp b/tests/manual/gdbdebugger/spacy path/plugin with space.cpp
new file mode 100644
index 0000000000..75486ccd67
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy path/plugin with space.cpp
@@ -0,0 +1,13 @@
+
+
+#include <stdio.h>
+#include <qglobal.h>
+
+extern "C" Q_DECL_EXPORT int pluginTest()
+{
+ int s = 0;
+ for (int i = 1; i != 2000; ++i)
+ s += i;
+ fprintf(stderr, "in plugin test");
+ return s;
+}
diff --git a/tests/manual/gdbdebugger/spacy path/spacy app/spacy app.pro b/tests/manual/gdbdebugger/spacy path/spacy app/spacy app.pro
new file mode 100644
index 0000000000..eee7110844
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy path/spacy app/spacy app.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET = "spacy app"
+DEPENDPATH += .
+INCLUDEPATH += .
+DESTDIR = ..
+
+# Input
+SOURCES += "../app with space.cpp"
+QT += network
diff --git a/tests/manual/gdbdebugger/spacy path/spacy path.pro b/tests/manual/gdbdebugger/spacy path/spacy path.pro
new file mode 100644
index 0000000000..879aea6259
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy path/spacy path.pro
@@ -0,0 +1,4 @@
+
+TEMPLATE = subdirs
+
+SUBDIRS += "\"spacy app\"" "\"spacy plugin\""
diff --git a/tests/manual/gdbdebugger/spacy path/spacy plugin/spacy plugin.pro b/tests/manual/gdbdebugger/spacy path/spacy plugin/spacy plugin.pro
new file mode 100644
index 0000000000..3cad806e7a
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy path/spacy plugin/spacy plugin.pro
@@ -0,0 +1,18 @@
+TEMPLATE = lib
+TARGET = plugin
+DESTDIR = ..
+CONFIG += shared
+
+SOURCES += "../plugin with space.cpp"
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/
+} else:linux-* {
+ #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ QMAKE_RPATHDIR += \$\$ORIGIN/..
+ IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":")
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\'
+ QMAKE_RPATHDIR =
+}
+
+
diff --git a/tests/manual/gdbdebugger/spacy-file/app with space.cpp b/tests/manual/gdbdebugger/spacy-file/app with space.cpp
new file mode 100644
index 0000000000..c5969e5f96
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy-file/app with space.cpp
@@ -0,0 +1,419 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2004-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QLibrary>
+#include <QtCore/QMap>
+#include <QtCore/QPointer>
+#include <QtCore/QString>
+#include <QtCore/QThread>
+#include <QtCore/QVariant>
+#include <QtCore/QVector>
+
+#include <QtGui/QApplication>
+#include <QtGui/QAction>
+#include <QtGui/QColor>
+#include <QtGui/QFont>
+#include <QtGui/QLabel>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+
+#include <QtNetwork/QHostAddress>
+
+#include <iostream>
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#endif
+
+
+uint qHash(const QMap<int, int> &)
+{
+ return 0;
+}
+
+uint qHash(const double & f)
+{
+ return int(f);
+}
+
+class Foo
+{
+public:
+ Foo(int i=0)
+ : a(i), b(2)
+ {
+
+ }
+ void doit()
+ {
+ static QObject ob;
+ m["1"] = "2";
+ h[&ob] = m.begin();
+
+ a += 1;
+ --b;
+ //s += 'x';
+ }
+
+
+ struct Bar {
+ Bar() : ob(0) {}
+ QObject *ob;
+ };
+
+public:
+ int a, b;
+ char x[6];
+
+private:
+ //QString s;
+ typedef QMap<QString, QString> Map;
+ Map m;
+ QHash<QObject *, Map::iterator> h;
+};
+
+void testArray()
+{
+ QString x[4];
+ x[0] = "a";
+ x[1] = "b";
+ x[2] = "c";
+ x[3] = "d";
+
+ Foo foo[100];
+ //for (int i = 0; i != sizeof(foo)/sizeof(foo[0]); ++i) {
+ for (int i = 0; i < 5; ++i) {
+ foo[i].a = i;
+ foo[i].doit();
+ }
+}
+
+void testByteArray()
+{
+ QByteArray ba = "Hello";
+ ba += '"';
+ ba += "World";
+ ba += char(0);
+ ba += 1;
+ ba += 2;
+}
+
+void testHash()
+{
+ QHash<int, float> hgg0;
+ hgg0[11] = 11.0;
+ hgg0[22] = 22.0;
+
+
+ QHash<QString, float> hgg1;
+ hgg1["22.0"] = 22.0;
+
+ QHash<int, QString> hgg2;
+ hgg2[22] = "22.0";
+
+ QHash<QString, Foo> hgg3;
+ hgg3["22.0"] = Foo(22);
+ hgg3["33.0"] = Foo(33);
+
+ QObject ob;
+ QHash<QString, QPointer<QObject> > hash;
+ hash.insert("Hallo", QPointer<QObject>(&ob));
+ hash.insert("Welt", QPointer<QObject>(&ob));
+ hash.insert(".", QPointer<QObject>(&ob));
+}
+
+void testImage()
+{
+ QImage im(QSize(200, 200), QImage::Format_RGB32);
+ im.fill(QColor(200, 100, 130).rgba());
+ QPainter pain;
+ pain.begin(&im);
+ pain.drawLine(2, 2, 130, 130);
+ pain.drawLine(4, 2, 130, 140);
+ pain.drawRect(30, 30, 80, 80);
+ pain.end();
+}
+
+void testIO()
+{
+ qDebug() << "qDebug() 1";
+ qDebug() << "qDebug() 2";
+ qDebug() << "qDebug() 3";
+
+ std::cout << "std::cout @@ 1\n";
+ std::cout << "std::cout @@ 2\n";
+ std::cout << "std::cout @@ 3\n";
+
+ std::cerr << "std::cerr 1\n";
+ std::cerr << "std::cerr 2\n";
+ std::cerr << "std::cerr 3\n";
+};
+
+
+void testList()
+{
+ QList<int> foo;
+ for (int i = 0; i != 100; ++i) {
+ foo.append(i);
+ }
+ foo.append(101);
+ foo.append(102);
+ }
+
+void testMap()
+{
+ QMap<int, float> gg0;
+ gg0[11] = 11.0;
+ gg0[22] = 22.0;
+
+
+ QMap<QString, float> gg1;
+ gg1["22.0"] = 22.0;
+
+ QMap<int, QString> gg2;
+ gg2[22] = "22.0";
+
+ QMap<QString, Foo> gg3;
+ gg3["22.0"] = Foo(22);
+ gg3["33.0"] = Foo(33);
+
+ QObject ob;
+ QMap<QString, QPointer<QObject> > map;
+ map.insert("Hallo", QPointer<QObject>(&ob));
+ map.insert("Welt", QPointer<QObject>(&ob));
+ map.insert(".", QPointer<QObject>(&ob));
+}
+
+void testObject(int &argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QAction act("xxx", &app);
+ QString t = act.text();
+ t += "y";
+
+/*
+ QObject ob(&app);
+ ob.setObjectName("An Object");
+ QObject ob1;
+ ob1.setObjectName("Another Object");
+
+ QObject::connect(&ob, SIGNAL(destroyed()), &ob1, SLOT(deleteLater()));
+ QObject::connect(&app, SIGNAL(lastWindowClosed()), &ob, SLOT(deleteLater()));
+
+ QList<QObject *> obs;
+ obs.append(&ob);
+ obs.append(&ob1);
+ obs.append(0);
+ obs.append(&app);
+ ob1.setObjectName("A Subobject");
+*/
+ QLabel l("XXXXXXXXXXXXXXXXX");
+ l.show();
+ app.exec();
+}
+
+void testPixmap()
+{
+ QImage im(QSize(200, 200), QImage::Format_RGB32);
+ im.fill(QColor(200, 100, 130).rgba());
+ QPainter pain;
+ pain.begin(&im);
+ pain.drawLine(2, 2, 130, 130);
+ pain.end();
+ QPixmap pm = QPixmap::fromImage(im);
+ int i = 1;
+ Q_UNUSED(i);
+}
+
+void testPlugin()
+{
+ QString dir = QDir::currentPath();
+#ifdef Q_OS_LINUX
+ QLibrary lib(dir + "/libplugin.so");
+#endif
+ int (*foo)() = (int(*)()) lib.resolve("pluginTest");
+ qDebug() << "library resolve: " << foo;
+ if (foo) {
+ int res = foo();
+ res += 1;
+ } else {
+ qDebug() << lib.errorString();
+ }
+}
+
+void stringRefTest(const QString &refstring)
+{
+ Q_UNUSED(refstring);
+}
+
+void testString()
+{
+ QString str = "Hello ";
+ str += " big, ";
+ str += " fat ";
+ str += " World ";
+
+ QString string("String Test");
+ QString *pstring = new QString("Pointer String Test");
+ stringRefTest(QString("Ref String Test"));
+ string = "Hi";
+ string += "Du";
+ qDebug() << string;
+ delete pstring;
+}
+
+void testStringList()
+{
+ QStringList l;
+ l << "Hello ";
+ l << " big, ";
+ l << " fat ";
+ l << " World ";
+}
+
+void testStruct()
+{
+ Foo f(2);
+ f.doit();
+ f.doit();
+ f.doit();
+};
+
+class Thread : public QThread
+{
+public:
+ Thread(int id) : m_id(id) {}
+
+ void run()
+ {
+ for (int i = 0; i != 100000; ++i) {
+ //sleep(1);
+ std::cerr << m_id;
+ }
+ }
+
+private:
+ int m_id;
+};
+
+void testThreads()
+{
+ Thread thread1(1);
+ Thread thread2(2);
+ thread1.start();
+ thread2.start();
+ thread1.wait();
+ thread2.wait();
+}
+
+void testVariant1()
+{
+ QVariant v;
+ v = 1;
+ v = 1.0;
+ v = "string";
+ v = 1;
+}
+
+void testVariant2()
+{
+ QVariant var;
+ QVariant var3;
+ QHostAddress ha("127.0.0.1");
+ qVariantSetValue(var, ha);
+ var3 = var;
+ var3 = var;
+ var3 = var;
+ var3 = var;
+ QHostAddress ha1 = var.value<QHostAddress>();
+}
+
+void testVariant3()
+{
+ QList<int> list;
+ list << 1 << 2 << 3;
+ QVariant variant = qVariantFromValue(list);
+ list.clear();
+ list = qVariantValue<QList<int> >(variant);
+}
+
+void testVector()
+{
+ QVector<Foo *> plist;
+ plist.append(new Foo(1));
+ plist.append(0);
+ plist.append(new Foo(2));
+
+ QVector<Foo> flist;
+ flist.append(1);
+
+ flist.append(2);
+ flist.append(3);
+ flist.append(4);
+ //flist.takeFirst();
+ //flist.takeFirst();
+
+ QVector<bool> vec;
+ vec.append(true);
+ vec.append(false);
+}
+
+void testVectorOfList()
+{
+ QVector<QList<int> > v;
+ QVector<QList<int> > *pv = &v;
+ v.append(QList<int>() << 1);
+ v.append(QList<int>() << 2 << 3);
+ Q_UNUSED(pv);
+}
+
+int main(int argc, char *argv[])
+{
+ testArray();
+ testPlugin();
+ testList();
+ return 0;
+ testByteArray();
+ testHash();
+ testImage();
+ testIO();
+ testMap();
+ testString();
+ testStringList();
+ testStruct();
+ testThreads();
+ testVariant1();
+ testVariant2();
+ testVariant3();
+ testVector();
+ testVectorOfList();
+
+ testObject(argc, argv);
+
+ QColor color(255,128,10);
+ QFont font;
+
+ while(true)
+ ;
+
+ return 0;
+}
+
+Q_DECLARE_METATYPE(QHostAddress)
+Q_DECLARE_METATYPE(QList<int>)
+
+
diff --git a/tests/manual/gdbdebugger/spacy-file/app/app.pro b/tests/manual/gdbdebugger/spacy-file/app/app.pro
new file mode 100644
index 0000000000..eee7110844
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy-file/app/app.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET = "spacy app"
+DEPENDPATH += .
+INCLUDEPATH += .
+DESTDIR = ..
+
+# Input
+SOURCES += "../app with space.cpp"
+QT += network
diff --git a/tests/manual/gdbdebugger/spacy-file/plugin with space.cpp b/tests/manual/gdbdebugger/spacy-file/plugin with space.cpp
new file mode 100644
index 0000000000..75486ccd67
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy-file/plugin with space.cpp
@@ -0,0 +1,13 @@
+
+
+#include <stdio.h>
+#include <qglobal.h>
+
+extern "C" Q_DECL_EXPORT int pluginTest()
+{
+ int s = 0;
+ for (int i = 1; i != 2000; ++i)
+ s += i;
+ fprintf(stderr, "in plugin test");
+ return s;
+}
diff --git a/tests/manual/gdbdebugger/spacy-file/plugin/plugin.pro b/tests/manual/gdbdebugger/spacy-file/plugin/plugin.pro
new file mode 100644
index 0000000000..3cad806e7a
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy-file/plugin/plugin.pro
@@ -0,0 +1,18 @@
+TEMPLATE = lib
+TARGET = plugin
+DESTDIR = ..
+CONFIG += shared
+
+SOURCES += "../plugin with space.cpp"
+
+macx {
+ QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/
+} else:linux-* {
+ #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ QMAKE_RPATHDIR += \$\$ORIGIN/..
+ IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":")
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\'
+ QMAKE_RPATHDIR =
+}
+
+
diff --git a/tests/manual/gdbdebugger/spacy-file/spacy-file.pro b/tests/manual/gdbdebugger/spacy-file/spacy-file.pro
new file mode 100644
index 0000000000..78c70731cd
--- /dev/null
+++ b/tests/manual/gdbdebugger/spacy-file/spacy-file.pro
@@ -0,0 +1,4 @@
+
+TEMPLATE = subdirs
+
+SUBDIRS += app plugin
diff --git a/tests/manual/progressmanager/find.png b/tests/manual/progressmanager/find.png
new file mode 100644
index 0000000000..cbe2f31521
--- /dev/null
+++ b/tests/manual/progressmanager/find.png
Binary files differ
diff --git a/tests/manual/progressmanager/main.cpp b/tests/manual/progressmanager/main.cpp
new file mode 100644
index 0000000000..e1289e07cc
--- /dev/null
+++ b/tests/manual/progressmanager/main.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtGui/QApplication>
+#include "roundprogress.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ roundprogress w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/manual/progressmanager/roundprogress.cpp b/tests/manual/progressmanager/roundprogress.cpp
new file mode 100644
index 0000000000..488ce4d265
--- /dev/null
+++ b/tests/manual/progressmanager/roundprogress.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "roundprogress.h"
+#include "multitask.h"
+#include "runextensions.h"
+
+roundprogress::roundprogress(QWidget *parent)
+ : QWidget(parent), task(MyInternalTask(true)), task2(MyInternalTask(false))
+{
+ ui.setupUi(this);
+ ui.progressButton->setIcon(QIcon("find.png"));
+ connect(ui.startButton, SIGNAL(clicked()), this, SLOT(start()));
+ connect(ui.startButton2, SIGNAL(clicked()), this, SLOT(start2()));
+ connect(ui.startBothButton, SIGNAL(clicked()), this, SLOT(start3()));
+ ui.startButton->setFocus();
+}
+
+void roundprogress::start()
+{
+ if (future.isRunning())
+ return;
+ future = QtConcurrent::run(&MyInternalTask::run, &task);
+ ui.progressButton->setFuture(future);
+}
+
+void roundprogress::start2()
+{
+ if (future.isRunning())
+ return;
+ future = QtConcurrent::run(&MyInternalTask::run, &task2);
+ ui.progressButton->setFuture(future);
+}
+
+void roundprogress::start3()
+{
+ if (future.isRunning())
+ return;
+ future = QtConcurrent::run(&MyInternalTask::run, QList<MyInternalTask*>() << &task2 << &task);
+ ui.progressButton->setFuture(future);
+}
diff --git a/tests/manual/progressmanager/roundprogress.h b/tests/manual/progressmanager/roundprogress.h
new file mode 100644
index 0000000000..f1e43ff5e7
--- /dev/null
+++ b/tests/manual/progressmanager/roundprogress.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ROUNDPROGRESS_H
+#define ROUNDPROGRESS_H
+
+#include <QtGui/QMainWindow>
+#include "ui_roundprogress.h"
+#include <QtCore>
+#include <QtGui>
+#include <QtDebug>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QFuture>
+
+class MyInternalTask;
+
+class MyInternalTask : public QObject
+{
+ Q_OBJECT
+public:
+ static const int MAX = 10;
+
+ MyInternalTask(bool withProgress)
+ {
+ m_hasProgress = withProgress;
+ if (m_hasProgress)
+ m_duration = 4000;
+ else
+ m_duration = 2500;
+ }
+
+ MyInternalTask(const MyInternalTask &) : QObject() {}
+
+ void run(QFutureInterface<void> &f)
+ {
+ m_future = &f;
+ m_count = 0;
+ m_future->setProgressRange(0, (m_hasProgress ? MAX : 0));
+ m_future->setProgressValueAndText(m_count, tr("Starting..."));
+ m_loop = new QEventLoop;
+ m_timer = new QTimer;
+ m_timer->setInterval(m_duration/MAX);
+ m_timer->setSingleShot(false);
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(advance()));
+ m_timer->start();
+ m_loop->exec();
+ delete m_timer;
+ delete m_loop;
+ }
+
+private slots:
+ void advance()
+ {
+ ++m_count;
+ m_future->setProgressValueAndText(m_count, tr("Something happening %1").arg(m_count));
+ if (m_count == MAX || m_future->isCanceled()) {
+ m_future->setProgressValueAndText(m_count, tr("Finished!"));
+ m_loop->quit();
+ }
+ }
+private:
+ bool m_hasProgress;
+ QEventLoop *m_loop;
+ QTimer *m_timer;
+ QFutureInterface<void> *m_future;
+ int m_count;
+ int m_duration;
+};
+
+class roundprogress : public QWidget
+{
+ Q_OBJECT
+
+public:
+ roundprogress(QWidget *parent = 0);
+ ~roundprogress() {}
+
+private slots:
+ void start();
+ void start2();
+ void start3();
+private:
+ Ui::roundprogressClass ui;
+ MyInternalTask task;
+ MyInternalTask task2;
+ QFuture<void> future;
+};
+
+#endif // ROUNDPROGRESS_H
diff --git a/tests/manual/progressmanager/roundprogress.pro b/tests/manual/progressmanager/roundprogress.pro
new file mode 100644
index 0000000000..6e34bdca1d
--- /dev/null
+++ b/tests/manual/progressmanager/roundprogress.pro
@@ -0,0 +1,15 @@
+TARGET = roundprogress
+TEMPLATE = app
+QT += core \
+ gui
+INCLUDEPATH += $$PWD/../../../src/plugins/core/progressmanager $$PWD/../../../src/libs/qtconcurrent
+SOURCES += main.cpp \
+ roundprogress.cpp \
+ $$PWD/../../../src/plugins/core/progressmanager/progresspie.cpp \
+ $$PWD/../../../src/plugins/core/progressmanager/futureprogress.cpp
+HEADERS += roundprogress.h \
+ $$PWD/../../../src/libs/qtconcurrent/multitask.h \
+ $$PWD/../../../src/plugins/core/progressmanager/progresspie_p.h \
+ $$PWD/../../../src/plugins/core/progressmanager/progresspie.h \
+ $$PWD/../../../src/plugins/core/progressmanager/futureprogress.h
+FORMS += roundprogress.ui
diff --git a/tests/manual/progressmanager/roundprogress.ui b/tests/manual/progressmanager/roundprogress.ui
new file mode 100644
index 0000000000..1c1fe4b472
--- /dev/null
+++ b/tests/manual/progressmanager/roundprogress.ui
@@ -0,0 +1,55 @@
+<ui version="4.0" >
+ <class>roundprogressClass</class>
+ <widget class="QWidget" name="roundprogressClass" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>212</width>
+ <height>144</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="FutureProgress" name="progressButton" >
+ <property name="font" >
+ <font/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QPushButton" name="startButton" >
+ <property name="text" >
+ <string>Start with progress</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QPushButton" name="startButton2" >
+ <property name="text" >
+ <string>Start with animation</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QPushButton" name="startBothButton" >
+ <property name="text" >
+ <string>Start both</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>FutureProgress</class>
+ <extends>QToolButton</extends>
+ <header>../../../src/plugins/core/progressmanager/futureprogress.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/manual/proparser/main.cpp b/tests/manual/proparser/main.cpp
new file mode 100644
index 0000000000..f2acfbf28a
--- /dev/null
+++ b/tests/manual/proparser/main.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+
+#include "proreader.h"
+#include "proitems.h"
+#include "proxml.h"
+
+int main(int argc, char *argv[])
+{
+ ProReader pr;
+ ProFile *pf = pr.read(QString::fromUtf8(argv[1]));
+
+ qDebug() << Qt4ProjectManager::Internal::ProXmlParser::itemToString(pf);
+
+ return 0;
+}
diff --git a/tests/manual/proparser/proparser.pro b/tests/manual/proparser/proparser.pro
new file mode 100644
index 0000000000..c822929991
--- /dev/null
+++ b/tests/manual/proparser/proparser.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+QT += xml
+
+PROXMLPATH = ../../../src/plugins/qt4projectmanager/proparser
+PROPARSERPATH = $$(QTDIR)/tools/linguist/shared
+INCLUDEPATH += $$PROPARSERPATH $$PROXMLPATH
+
+# Input
+HEADERS += $$PROPARSERPATH/proitems.h \
+ $$PROXMLPATH/proxml.h \
+ $$PROPARSERPATH/proreader.h
+SOURCES += main.cpp \
+ $$PROPARSERPATH/proitems.cpp \
+ $$PROXMLPATH/proxml.cpp \
+ $$PROPARSERPATH/proreader.cpp
+
diff --git a/tests/manual/proparser/test.pro b/tests/manual/proparser/test.pro
new file mode 100644
index 0000000000..55921087c1
--- /dev/null
+++ b/tests/manual/proparser/test.pro
@@ -0,0 +1,27 @@
+#comment
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+QT += xml
+
+win32 {
+ PROPARSERPATH = ../../some/other/test/test
+ unix:PROPARSERPATH = ../../test/test
+}
+
+# test comment
+PROPARSERPATH = ../../../src/plugins/qt4projectmanager/proparser
+INCLUDEPATH += $$PROPARSERPATH
+
+# Input
+HEADERS += $$PROPARSERPATH/proitems.h \ # test comment2
+ $$PROPARSERPATH/proxml.h \
+ $$PROPARSERPATH/proreader.h
+SOURCES += main.cpp \
+ $$PROPARSERPATH/proitems.cpp \
+# test comment 3
+ $$PROPARSERPATH/proxml.cpp \
+ $$PROPARSERPATH/proreader.cpp
diff --git a/tests/qt4projectmanager/test1/a.cpp b/tests/qt4projectmanager/test1/a.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qt4projectmanager/test1/a.cpp
diff --git a/tests/qt4projectmanager/test1/a.h b/tests/qt4projectmanager/test1/a.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qt4projectmanager/test1/a.h
diff --git a/tests/qt4projectmanager/test1/test1.pro b/tests/qt4projectmanager/test1/test1.pro
new file mode 100644
index 0000000000..eba77bc4bd
--- /dev/null
+++ b/tests/qt4projectmanager/test1/test1.pro
@@ -0,0 +1,4 @@
+SOURCES = a.cpp
+HEADERS = a.h
+
+